mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-26 19:36:08 +03:00
Merge pull request #664 from vector-im/feature/room_list_actions
Feature/room list actions
This commit is contained in:
commit
cbdbe5033f
84 changed files with 1690 additions and 494 deletions
|
@ -2,6 +2,7 @@ Changes in RiotX 0.8.0 (2019-XX-XX)
|
|||
===================================================
|
||||
|
||||
Features ✨:
|
||||
- Handle long click on room in the room list (#395)
|
||||
- Ignore/UnIgnore users, and display list of ignored users (#542, #617)
|
||||
|
||||
Improvements 🙌:
|
||||
|
@ -38,6 +39,7 @@ Improvements:
|
|||
- Attachments: start using system pickers (#52)
|
||||
- Mark all messages as read (#396)
|
||||
|
||||
|
||||
Other changes:
|
||||
- Accessibility improvements to read receipts in the room timeline and reactions emoji chooser
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.room.Room
|
|||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.ReadReceipt
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
|
@ -67,6 +68,10 @@ class RxRoom(private val room: Room) {
|
|||
fun liveDrafts(): Observable<List<UserDraft>> {
|
||||
return room.getDraftsLive().asObservable()
|
||||
}
|
||||
|
||||
fun liveNotificationState(): Observable<RoomNotificationState> {
|
||||
return room.getLiveRoomNotificationState().asObservable()
|
||||
}
|
||||
}
|
||||
|
||||
fun Room.rx(): RxRoom {
|
||||
|
|
|
@ -21,7 +21,7 @@ import timber.log.Timber
|
|||
sealed class Action {
|
||||
object Notify : Action()
|
||||
object DoNotNotify : Action()
|
||||
data class Sound(val sound: String) : Action()
|
||||
data class Sound(val sound: String = ACTION_OBJECT_VALUE_VALUE_DEFAULT) : Action()
|
||||
data class Highlight(val highlight: Boolean) : Action()
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,29 @@ private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default"
|
|||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@Suppress("IMPLICIT_CAST_TO_ANY")
|
||||
fun List<Action>.toJson(): List<Any> {
|
||||
return map { action ->
|
||||
when (action) {
|
||||
is Action.Notify -> ACTION_NOTIFY
|
||||
is Action.DoNotNotify -> ACTION_DONT_NOTIFY
|
||||
is Action.Sound -> {
|
||||
mapOf(
|
||||
ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_SOUND,
|
||||
ACTION_OBJECT_VALUE_KEY to action.sound
|
||||
)
|
||||
}
|
||||
is Action.Highlight -> {
|
||||
mapOf(
|
||||
ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT,
|
||||
ACTION_OBJECT_VALUE_KEY to action.highlight
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun PushRule.getActions(): List<Action> {
|
||||
val result = ArrayList<Action>()
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@ interface PushRuleService {
|
|||
|
||||
fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun addPushRuleListener(listener: PushRuleListener)
|
||||
|
||||
fun removePushRuleListener(listener: PushRuleListener)
|
||||
|
|
|
@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.room.crypto.RoomCryptoService
|
|||
import im.vector.matrix.android.api.session.room.members.MembershipService
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.relation.RelationService
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService
|
||||
import im.vector.matrix.android.api.session.room.reporting.ReportingService
|
||||
import im.vector.matrix.android.api.session.room.read.ReadService
|
||||
import im.vector.matrix.android.api.session.room.send.DraftService
|
||||
|
@ -41,7 +42,8 @@ interface Room :
|
|||
StateService,
|
||||
ReportingService,
|
||||
RelationService,
|
||||
RoomCryptoService {
|
||||
RoomCryptoService,
|
||||
RoomPushRuleService {
|
||||
|
||||
/**
|
||||
* The roomId of this room
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.room.notification
|
||||
|
||||
/**
|
||||
* Defines the room notification state
|
||||
*/
|
||||
enum class RoomNotificationState {
|
||||
/**
|
||||
* All the messages will trigger a noisy notification
|
||||
*/
|
||||
ALL_MESSAGES_NOISY,
|
||||
|
||||
/**
|
||||
* All the messages will trigger a notification
|
||||
*/
|
||||
ALL_MESSAGES,
|
||||
|
||||
/**
|
||||
* Only the messages with user display name / user name will trigger notifications
|
||||
*/
|
||||
MENTIONS_ONLY,
|
||||
|
||||
/**
|
||||
* No notifications
|
||||
*/
|
||||
MUTE
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.room.notification
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
interface RoomPushRuleService {
|
||||
|
||||
fun getLiveRoomNotificationState(): LiveData<RoomNotificationState>
|
||||
|
||||
fun setRoomNotificationState(roomNotificationState: RoomNotificationState, matrixCallback: MatrixCallback<Unit>): Cancelable
|
||||
}
|
|
@ -17,6 +17,8 @@ package im.vector.matrix.android.internal.database.model
|
|||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.RealmResults
|
||||
import io.realm.annotations.LinkingObjects
|
||||
|
||||
internal open class PushRuleEntity(
|
||||
// Required. The actions to perform when this rule is matched.
|
||||
|
@ -33,5 +35,8 @@ internal open class PushRuleEntity(
|
|||
var pattern: String? = null
|
||||
) : RealmObject() {
|
||||
|
||||
@LinkingObjects("pushRules")
|
||||
val parent: RealmResults<PushRulesEntity>? = null
|
||||
|
||||
companion object
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.api.pushrules.RuleKind
|
||||
import im.vector.matrix.android.internal.database.model.*
|
||||
import im.vector.matrix.android.internal.database.model.PushRuleEntity
|
||||
import im.vector.matrix.android.internal.database.model.PushRulesEntity
|
||||
import im.vector.matrix.android.internal.database.model.PushRulesEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntity
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntityFields
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.where
|
||||
|
@ -41,3 +41,11 @@ internal fun PushRulesEntity.Companion.where(realm: Realm,
|
|||
.equalTo(PushRulesEntityFields.SCOPE, scope)
|
||||
.equalTo(PushRulesEntityFields.KIND_STR, kind.name)
|
||||
}
|
||||
|
||||
internal fun PushRuleEntity.Companion.where(realm: Realm,
|
||||
scope: String,
|
||||
ruleId: String): RealmQuery<PushRuleEntity> {
|
||||
return realm.where<PushRuleEntity>()
|
||||
.equalTo("${PushRuleEntityFields.PARENT}.${PushRulesEntityFields.SCOPE}", scope)
|
||||
.equalTo(PushRuleEntityFields.RULE_ID, ruleId)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
|
|||
import im.vector.matrix.android.internal.database.model.PushRulesEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.session.pushers.AddPushRuleTask
|
||||
import im.vector.matrix.android.internal.session.pushers.GetPushRulesTask
|
||||
import im.vector.matrix.android.internal.session.pushers.RemovePushRuleTask
|
||||
import im.vector.matrix.android.internal.session.pushers.UpdatePushRuleEnableStatusTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
|
@ -38,6 +40,8 @@ import javax.inject.Inject
|
|||
@SessionScope
|
||||
internal class DefaultPushRuleService @Inject constructor(private val getPushRulesTask: GetPushRulesTask,
|
||||
private val updatePushRuleEnableStatusTask: UpdatePushRuleEnableStatusTask,
|
||||
private val addPushRuleTask: AddPushRuleTask,
|
||||
private val removePushRuleTask: RemovePushRuleTask,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val monarchy: Monarchy
|
||||
) : PushRuleService {
|
||||
|
@ -98,6 +102,22 @@ internal class DefaultPushRuleService @Inject constructor(private val getPushRul
|
|||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable {
|
||||
return addPushRuleTask
|
||||
.configureWith(AddPushRuleTask.Params(kind, pushRule)) {
|
||||
this.callback = callback
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable {
|
||||
return removePushRuleTask
|
||||
.configureWith(RemovePushRuleTask.Params(kind, pushRule)) {
|
||||
this.callback = callback
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun removePushRuleListener(listener: PushRuleService.PushRuleListener) {
|
||||
synchronized(listeners) {
|
||||
listeners.remove(listener)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import im.vector.matrix.android.api.pushrules.RuleKind
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface AddPushRuleTask : Task<AddPushRuleTask.Params, Unit> {
|
||||
data class Params(
|
||||
val kind: RuleKind,
|
||||
val pushRule: PushRule
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultAddPushRuleTask @Inject constructor(private val pushRulesApi: PushRulesApi)
|
||||
: AddPushRuleTask {
|
||||
|
||||
override suspend fun execute(params: AddPushRuleTask.Params) {
|
||||
return executeRequest {
|
||||
apiCall = pushRulesApi.addRule(params.kind.value, params.pushRule.ruleId, params.pushRule)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ import im.vector.matrix.android.api.session.pushers.PushersService
|
|||
import im.vector.matrix.android.internal.session.notification.DefaultProcessEventForPushTask
|
||||
import im.vector.matrix.android.internal.session.notification.DefaultPushRuleService
|
||||
import im.vector.matrix.android.internal.session.notification.ProcessEventForPushTask
|
||||
import im.vector.matrix.android.internal.session.room.notification.DefaultSetRoomNotificationStateTask
|
||||
import im.vector.matrix.android.internal.session.room.notification.SetRoomNotificationStateTask
|
||||
import retrofit2.Retrofit
|
||||
|
||||
@Module
|
||||
|
@ -67,6 +69,15 @@ internal abstract class PushersModule {
|
|||
@Binds
|
||||
abstract fun bindUpdatePushRuleEnableStatusTask(updatePushRuleEnableStatusTask: DefaultUpdatePushRuleEnableStatusTask): UpdatePushRuleEnableStatusTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindAddPushRuleTask(addPushRuleTask: DefaultAddPushRuleTask): AddPushRuleTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindRemovePushRuleTask(removePushRuleTask: DefaultRemovePushRuleTask): RemovePushRuleTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindSetRoomNotificationStateTask(setRoomNotificationStateTask: DefaultSetRoomNotificationStateTask): SetRoomNotificationStateTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindPushRuleService(pushRuleService: DefaultPushRuleService): PushRuleService
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import im.vector.matrix.android.api.pushrules.RuleKind
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface RemovePushRuleTask : Task<RemovePushRuleTask.Params, Unit> {
|
||||
data class Params(
|
||||
val kind: RuleKind,
|
||||
val pushRule: PushRule
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultRemovePushRuleTask @Inject constructor(private val pushRulesApi: PushRulesApi)
|
||||
: RemovePushRuleTask {
|
||||
|
||||
override suspend fun execute(params: RemovePushRuleTask.Params) {
|
||||
return executeRequest {
|
||||
apiCall = pushRulesApi.deleteRule(params.kind.value, params.pushRule.ruleId)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.room.Room
|
|||
import im.vector.matrix.android.api.session.room.members.MembershipService
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.relation.RelationService
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService
|
||||
import im.vector.matrix.android.api.session.room.reporting.ReportingService
|
||||
import im.vector.matrix.android.api.session.room.read.ReadService
|
||||
import im.vector.matrix.android.api.session.room.send.DraftService
|
||||
|
@ -49,7 +50,8 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
|||
private val readService: ReadService,
|
||||
private val cryptoService: CryptoService,
|
||||
private val relationService: RelationService,
|
||||
private val roomMembersService: MembershipService) :
|
||||
private val roomMembersService: MembershipService,
|
||||
private val roomPushRuleService: RoomPushRuleService) :
|
||||
Room,
|
||||
TimelineService by timelineService,
|
||||
SendService by sendService,
|
||||
|
@ -58,7 +60,8 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
|||
ReportingService by reportingService,
|
||||
ReadService by readService,
|
||||
RelationService by relationService,
|
||||
MembershipService by roomMembersService {
|
||||
MembershipService by roomMembersService,
|
||||
RoomPushRuleService by roomPushRuleService {
|
||||
|
||||
override fun getRoomSummaryLive(): LiveData<Optional<RoomSummary>> {
|
||||
val liveData = monarchy.findAllMappedWithChanges(
|
||||
|
|
|
@ -22,6 +22,7 @@ import im.vector.matrix.android.api.session.room.Room
|
|||
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
|
||||
import im.vector.matrix.android.internal.session.room.draft.DefaultDraftService
|
||||
import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService
|
||||
import im.vector.matrix.android.internal.session.room.notification.DefaultRoomPushRuleService
|
||||
import im.vector.matrix.android.internal.session.room.read.DefaultReadService
|
||||
import im.vector.matrix.android.internal.session.room.relation.DefaultRelationService
|
||||
import im.vector.matrix.android.internal.session.room.reporting.DefaultReportingService
|
||||
|
@ -44,7 +45,8 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
|
|||
private val reportingServiceFactory: DefaultReportingService.Factory,
|
||||
private val readServiceFactory: DefaultReadService.Factory,
|
||||
private val relationServiceFactory: DefaultRelationService.Factory,
|
||||
private val membershipServiceFactory: DefaultMembershipService.Factory) :
|
||||
private val membershipServiceFactory: DefaultMembershipService.Factory,
|
||||
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory) :
|
||||
RoomFactory {
|
||||
|
||||
override fun create(roomId: String): Room {
|
||||
|
@ -60,7 +62,8 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
|
|||
readServiceFactory.create(roomId),
|
||||
cryptoService,
|
||||
relationServiceFactory.create(roomId),
|
||||
membershipServiceFactory.create(roomId)
|
||||
membershipServiceFactory.create(roomId),
|
||||
roomPushRuleServiceFactory.create(roomId)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.room.notification
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.pushrules.RuleScope
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.model.PushRuleEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
|
||||
internal class DefaultRoomPushRuleService @AssistedInject constructor(@Assisted private val roomId: String,
|
||||
private val setRoomNotificationStateTask: SetRoomNotificationStateTask,
|
||||
private val monarchy: Monarchy,
|
||||
private val taskExecutor: TaskExecutor)
|
||||
: RoomPushRuleService {
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(roomId: String): RoomPushRuleService
|
||||
}
|
||||
|
||||
override fun getLiveRoomNotificationState(): LiveData<RoomNotificationState> {
|
||||
return Transformations.map(getPushRuleForRoom()) {
|
||||
it?.toRoomNotificationState() ?: RoomNotificationState.ALL_MESSAGES
|
||||
}
|
||||
}
|
||||
|
||||
override fun setRoomNotificationState(roomNotificationState: RoomNotificationState, matrixCallback: MatrixCallback<Unit>): Cancelable {
|
||||
return setRoomNotificationStateTask
|
||||
.configureWith(SetRoomNotificationStateTask.Params(roomId, roomNotificationState)) {
|
||||
this.callback = callback
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
private fun getPushRuleForRoom(): LiveData<RoomPushRule?> {
|
||||
val liveData = monarchy.findAllMappedWithChanges(
|
||||
{ realm ->
|
||||
PushRuleEntity.where(realm, scope = RuleScope.GLOBAL, ruleId = roomId)
|
||||
},
|
||||
{ result ->
|
||||
result.toRoomPushRule()
|
||||
}
|
||||
)
|
||||
return Transformations.map(liveData) { results ->
|
||||
results.firstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.room.notification
|
||||
|
||||
import im.vector.matrix.android.api.pushrules.RuleKind
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
|
||||
internal data class RoomPushRule(
|
||||
val kind: RuleKind,
|
||||
val rule: PushRule
|
||||
)
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.room.notification
|
||||
|
||||
import im.vector.matrix.android.api.pushrules.*
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushCondition
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
|
||||
import im.vector.matrix.android.internal.database.model.PushRuleEntity
|
||||
|
||||
internal fun PushRuleEntity.toRoomPushRule(): RoomPushRule? {
|
||||
val kind = parent?.firstOrNull()?.kind
|
||||
val pushRule = when (kind) {
|
||||
RuleSetKey.OVERRIDE -> {
|
||||
PushRulesMapper.map(this)
|
||||
}
|
||||
RuleSetKey.ROOM -> {
|
||||
PushRulesMapper.mapRoomRule(this)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
return if (pushRule == null || kind == null) {
|
||||
null
|
||||
} else {
|
||||
RoomPushRule(kind, pushRule)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? {
|
||||
return when {
|
||||
this == RoomNotificationState.ALL_MESSAGES -> null
|
||||
this == RoomNotificationState.ALL_MESSAGES_NOISY -> {
|
||||
val rule = PushRule(
|
||||
actions = listOf(Action.Notify, Action.Sound()).toJson(),
|
||||
enabled = true,
|
||||
ruleId = roomId
|
||||
)
|
||||
return RoomPushRule(RuleSetKey.ROOM, rule)
|
||||
}
|
||||
else -> {
|
||||
val condition = PushCondition(
|
||||
kind = Condition.Kind.event_match.value,
|
||||
key = "room_id",
|
||||
pattern = roomId
|
||||
)
|
||||
val rule = PushRule(
|
||||
actions = listOf(Action.DoNotNotify).toJson(),
|
||||
enabled = true,
|
||||
ruleId = roomId,
|
||||
conditions = listOf(condition)
|
||||
)
|
||||
val kind = if (this == RoomNotificationState.MUTE) {
|
||||
RuleSetKey.OVERRIDE
|
||||
} else {
|
||||
RuleSetKey.ROOM
|
||||
}
|
||||
return RoomPushRule(kind, rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RoomPushRule.toRoomNotificationState(): RoomNotificationState {
|
||||
return if (rule.enabled) {
|
||||
val actions = rule.getActions()
|
||||
if (actions.contains(Action.DoNotNotify)) {
|
||||
if (kind == RuleSetKey.OVERRIDE) {
|
||||
RoomNotificationState.MUTE
|
||||
} else {
|
||||
RoomNotificationState.MENTIONS_ONLY
|
||||
}
|
||||
} else if (actions.contains(Action.Notify)) {
|
||||
val hasSoundAction = actions.find {
|
||||
it is Action.Sound
|
||||
} != null
|
||||
if (hasSoundAction) {
|
||||
RoomNotificationState.ALL_MESSAGES_NOISY
|
||||
} else {
|
||||
RoomNotificationState.ALL_MESSAGES
|
||||
}
|
||||
} else {
|
||||
RoomNotificationState.ALL_MESSAGES
|
||||
}
|
||||
} else {
|
||||
RoomNotificationState.ALL_MESSAGES
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.room.notification
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.pushrules.RuleScope
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
import im.vector.matrix.android.internal.database.model.PushRuleEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.pushers.AddPushRuleTask
|
||||
import im.vector.matrix.android.internal.session.pushers.RemovePushRuleTask
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import io.realm.Realm
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface SetRoomNotificationStateTask : Task<SetRoomNotificationStateTask.Params, Unit> {
|
||||
data class Params(
|
||||
val roomId: String,
|
||||
val roomNotificationState: RoomNotificationState
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultSetRoomNotificationStateTask @Inject constructor(private val monarchy: Monarchy,
|
||||
private val removePushRuleTask: RemovePushRuleTask,
|
||||
private val addPushRuleTask: AddPushRuleTask)
|
||||
: SetRoomNotificationStateTask {
|
||||
|
||||
override suspend fun execute(params: SetRoomNotificationStateTask.Params) {
|
||||
val currentRoomPushRule = Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
PushRuleEntity.where(it, scope = RuleScope.GLOBAL, ruleId = params.roomId).findFirst()?.toRoomPushRule()
|
||||
}
|
||||
if (currentRoomPushRule != null) {
|
||||
removePushRuleTask.execute(RemovePushRuleTask.Params(currentRoomPushRule.kind, currentRoomPushRule.rule))
|
||||
}
|
||||
val newRoomPushRule = params.roomNotificationState.toRoomPushRule(params.roomId)
|
||||
if (newRoomPushRule != null) {
|
||||
addPushRuleTask.execute(AddPushRuleTask.Params(newRoomPushRule.kind, newRoomPushRule.rule))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,23 +16,15 @@
|
|||
|
||||
package im.vector.matrix.android.api.pushrules
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.toContent
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.model.*
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineSettings
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
|
@ -133,17 +125,20 @@ class PushrulesConditionTest {
|
|||
val conditionEqual3Bis = RoomMemberCountCondition("==3")
|
||||
val conditionLessThan3 = RoomMemberCountCondition("<3")
|
||||
|
||||
val session = MockRoomService()
|
||||
val room2JoinedId = "2joined"
|
||||
val room3JoinedId = "3joined"
|
||||
|
||||
Event(
|
||||
type = "m.room.message",
|
||||
eventId = "mx0",
|
||||
content = MessageTextContent("m.text", "A").toContent(),
|
||||
originServerTs = 0,
|
||||
roomId = "2joined").also {
|
||||
Assert.assertFalse("This room does not have 3 members", conditionEqual3.isSatisfied(it, session))
|
||||
Assert.assertFalse("This room does not have 3 members", conditionEqual3Bis.isSatisfied(it, session))
|
||||
Assert.assertTrue("This room has less than 3 members", conditionLessThan3.isSatisfied(it, session))
|
||||
val roomStub2Joined = mockk<Room> {
|
||||
every { getNumberOfJoinedMembers() } returns 2
|
||||
}
|
||||
|
||||
val roomStub3Joined = mockk<Room> {
|
||||
every { getNumberOfJoinedMembers() } returns 3
|
||||
}
|
||||
|
||||
val sessionStub = mockk<RoomService> {
|
||||
every { getRoom(room2JoinedId) } returns roomStub2Joined
|
||||
every { getRoom(room3JoinedId) } returns roomStub3Joined
|
||||
}
|
||||
|
||||
Event(
|
||||
|
@ -151,10 +146,21 @@ class PushrulesConditionTest {
|
|||
eventId = "mx0",
|
||||
content = MessageTextContent("m.text", "A").toContent(),
|
||||
originServerTs = 0,
|
||||
roomId = "3joined").also {
|
||||
Assert.assertTrue("This room has 3 members", conditionEqual3.isSatisfied(it, session))
|
||||
Assert.assertTrue("This room has 3 members", conditionEqual3Bis.isSatisfied(it, session))
|
||||
Assert.assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, session))
|
||||
roomId = room2JoinedId).also {
|
||||
Assert.assertFalse("This room does not have 3 members", conditionEqual3.isSatisfied(it, sessionStub))
|
||||
Assert.assertFalse("This room does not have 3 members", conditionEqual3Bis.isSatisfied(it, sessionStub))
|
||||
Assert.assertTrue("This room has less than 3 members", conditionLessThan3.isSatisfied(it, sessionStub))
|
||||
}
|
||||
|
||||
Event(
|
||||
type = "m.room.message",
|
||||
eventId = "mx0",
|
||||
content = MessageTextContent("m.text", "A").toContent(),
|
||||
originServerTs = 0,
|
||||
roomId = room3JoinedId).also {
|
||||
Assert.assertTrue("This room has 3 members", conditionEqual3.isSatisfied(it, sessionStub))
|
||||
Assert.assertTrue("This room has 3 members", conditionEqual3Bis.isSatisfied(it, sessionStub))
|
||||
Assert.assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, sessionStub))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,212 +177,4 @@ class PushrulesConditionTest {
|
|||
Assert.assertTrue("Notice", conditionEqual.isSatisfied(it))
|
||||
}
|
||||
}
|
||||
|
||||
class MockRoomService() : RoomService {
|
||||
override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback<String>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun joinRoom(roomId: String, viaServers: List<String>, callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getRoom(roomId: String): Room? {
|
||||
return when (roomId) {
|
||||
"2joined" -> MockRoom(roomId, 2)
|
||||
"3joined" -> MockRoom(roomId, 3)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun liveRoomSummaries(): LiveData<List<RoomSummary>> {
|
||||
return MutableLiveData()
|
||||
}
|
||||
|
||||
override fun markAllAsRead(roomIds: List<String>, callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
class MockRoom(override val roomId: String, val _numberOfJoinedMembers: Int) : Room {
|
||||
override fun reportContent(eventId: String, score: Int, reason: String, callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getReadMarkerLive(): LiveData<Optional<String>> {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getMyReadReceiptLive(): LiveData<Optional<String>> {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun resendTextMessage(localEcho: TimelineEvent): Cancelable? {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun deleteFailedEcho(localEcho: TimelineEvent) {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun clearSendingQueue() {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun resendAllFailedMessages() {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun saveDraft(draft: UserDraft) {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun deleteDraft() {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getDraftsLive(): LiveData<List<UserDraft>> {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>> {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getStateEvent(eventType: String): Event? {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun editReply(replyToEdit: TimelineEvent, originalTimelineEvent: TimelineEvent, newBodyText: String, compatibilityBodyText: String): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun fetchEditHistory(eventId: String, callback: MatrixCallback<List<Event>>) {
|
||||
}
|
||||
|
||||
override fun getTimeLineEventLive(eventId: String): LiveData<Optional<TimelineEvent>> {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getNumberOfJoinedMembers(): Int {
|
||||
return _numberOfJoinedMembers
|
||||
}
|
||||
|
||||
override fun getRoomSummaryLive(): LiveData<Optional<RoomSummary>> {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun roomSummary(): RoomSummary? {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getTimeLineEvent(eventId: String): TimelineEvent? {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun sendTextMessage(text: String, msgType: String, autoMarkdown: Boolean): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun sendFormattedTextMessage(text: String, formattedText: String): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun sendMedia(attachment: ContentAttachmentData): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun sendMedias(attachments: List<ContentAttachmentData>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun redactEvent(event: Event, reason: String?): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun markAllAsRead(callback: MatrixCallback<Unit>) {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun setReadReceipt(eventId: String, callback: MatrixCallback<Unit>) {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun setReadMarker(fullyReadEventId: String, callback: MatrixCallback<Unit>) {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun isEventRead(eventId: String): Boolean {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getRoomMember(userId: String): RoomMember? {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getRoomMemberIdsLive(): LiveData<List<String>> {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun invite(userId: String, callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun join(viaServers: List<String>, callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun leave(callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun updateTopic(topic: String, callback: MatrixCallback<Unit>) {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun sendReaction(targetEventId: String, reaction: String): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun undoReaction(targetEventId: String, reaction: String): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun editTextMessage(targetEventId: String, msgType: String, newBodyText: String,
|
||||
newBodyAutoMarkdown: Boolean, compatibilityBodyText: String): Cancelable {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun replyToMessage(eventReplied: TimelineEvent, replyText: String, autoMarkdown: Boolean): Cancelable? {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getEventSummaryLive(eventId: String): LiveData<Optional<EventAnnotationsSummary>> {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun isEncrypted(): Boolean {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun encryptionAlgorithm(): String? {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun shouldEncryptForInvitedMembers(): Boolean {
|
||||
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ package im.vector.riotx
|
|||
|
||||
import arrow.core.Option
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotx.core.utils.RxStore
|
||||
import im.vector.riotx.core.utils.BehaviorDataSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ActiveSessionObservableStore @Inject constructor() : RxStore<Option<Session>>()
|
||||
class ActiveSessionDataSource @Inject constructor() : BehaviorDataSource<Option<Session>>()
|
|
@ -23,9 +23,9 @@ import arrow.core.Option
|
|||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.features.home.HomeRoomListObservableStore
|
||||
import im.vector.riotx.features.home.HomeRoomListDataSource
|
||||
import im.vector.riotx.features.home.group.ALL_COMMUNITIES_GROUP_ID
|
||||
import im.vector.riotx.features.home.group.SelectedGroupStore
|
||||
import im.vector.riotx.features.home.group.SelectedGroupDataSource
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
@ -41,9 +41,9 @@ import javax.inject.Singleton
|
|||
*/
|
||||
@Singleton
|
||||
class AppStateHandler @Inject constructor(
|
||||
private val sessionObservableStore: ActiveSessionObservableStore,
|
||||
private val homeRoomListObservableStore: HomeRoomListObservableStore,
|
||||
private val selectedGroupStore: SelectedGroupStore) : LifecycleObserver {
|
||||
private val sessionDataSource: ActiveSessionDataSource,
|
||||
private val homeRoomListDataSource: HomeRoomListDataSource,
|
||||
private val selectedGroupDataSource: SelectedGroupDataSource) : LifecycleObserver {
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
|
@ -60,14 +60,14 @@ class AppStateHandler @Inject constructor(
|
|||
private fun observeRoomsAndGroup() {
|
||||
Observable
|
||||
.combineLatest<List<RoomSummary>, Option<GroupSummary>, List<RoomSummary>>(
|
||||
sessionObservableStore.observe()
|
||||
sessionDataSource.observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.switchMap {
|
||||
it.orNull()?.rx()?.liveRoomSummaries()
|
||||
?: Observable.just(emptyList())
|
||||
}
|
||||
.throttleLast(300, TimeUnit.MILLISECONDS),
|
||||
selectedGroupStore.observe(),
|
||||
selectedGroupDataSource.observe(),
|
||||
BiFunction { rooms, selectedGroupOption ->
|
||||
val selectedGroup = selectedGroupOption.orNull()
|
||||
val filteredDirectRooms = rooms
|
||||
|
@ -92,7 +92,7 @@ class AppStateHandler @Inject constructor(
|
|||
}
|
||||
)
|
||||
.subscribe {
|
||||
homeRoomListObservableStore.post(it)
|
||||
homeRoomListDataSource.post(it)
|
||||
}
|
||||
.addTo(compositeDisposable)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ package im.vector.riotx.core.di
|
|||
import arrow.core.Option
|
||||
import im.vector.matrix.android.api.auth.Authenticator
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotx.ActiveSessionObservableStore
|
||||
import im.vector.riotx.ActiveSessionDataSource
|
||||
import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
|
||||
import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
@ -28,7 +28,7 @@ import javax.inject.Singleton
|
|||
|
||||
@Singleton
|
||||
class ActiveSessionHolder @Inject constructor(private val authenticator: Authenticator,
|
||||
private val sessionObservableStore: ActiveSessionObservableStore,
|
||||
private val sessionObservableStore: ActiveSessionDataSource,
|
||||
private val keyRequestHandler: KeyRequestHandler,
|
||||
private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler
|
||||
) {
|
||||
|
|
|
@ -32,6 +32,7 @@ import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsB
|
|||
import im.vector.riotx.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
|
||||
import im.vector.riotx.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
||||
import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||
import im.vector.riotx.features.home.room.list.RoomListModule
|
||||
import im.vector.riotx.features.invite.VectorInviteView
|
||||
import im.vector.riotx.features.link.LinkHandlerActivity
|
||||
|
@ -123,6 +124,8 @@ interface ScreenComponent {
|
|||
|
||||
fun inject(incomingShareActivity: IncomingShareActivity)
|
||||
|
||||
fun inject(roomListActionsBottomSheet: RoomListQuickActionsBottomSheet)
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
fun create(vectorComponent: VectorComponent,
|
||||
|
|
|
@ -23,7 +23,7 @@ import dagger.Component
|
|||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.auth.Authenticator
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotx.ActiveSessionObservableStore
|
||||
import im.vector.riotx.ActiveSessionDataSource
|
||||
import im.vector.riotx.EmojiCompatFontProvider
|
||||
import im.vector.riotx.EmojiCompatWrapper
|
||||
import im.vector.riotx.VectorApplication
|
||||
|
@ -33,8 +33,8 @@ import im.vector.riotx.features.configuration.VectorConfiguration
|
|||
import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
|
||||
import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.HomeRoomListObservableStore
|
||||
import im.vector.riotx.features.home.group.SelectedGroupStore
|
||||
import im.vector.riotx.features.home.HomeRoomListDataSource
|
||||
import im.vector.riotx.features.home.group.SelectedGroupDataSource
|
||||
import im.vector.riotx.features.html.EventHtmlRenderer
|
||||
import im.vector.riotx.features.navigation.Navigator
|
||||
import im.vector.riotx.features.notifications.*
|
||||
|
@ -43,7 +43,7 @@ import im.vector.riotx.features.rageshake.VectorFileLogger
|
|||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||
import im.vector.riotx.features.session.SessionListener
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
import im.vector.riotx.features.share.ShareRoomListObservableStore
|
||||
import im.vector.riotx.features.share.ShareRoomListDataSource
|
||||
import im.vector.riotx.features.ui.UiStateRepository
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -85,13 +85,13 @@ interface VectorComponent {
|
|||
|
||||
fun navigator(): Navigator
|
||||
|
||||
fun homeRoomListObservableStore(): HomeRoomListObservableStore
|
||||
fun homeRoomListObservableStore(): HomeRoomListDataSource
|
||||
|
||||
fun shareRoomListObservableStore(): ShareRoomListObservableStore
|
||||
fun shareRoomListObservableStore(): ShareRoomListDataSource
|
||||
|
||||
fun selectedGroupStore(): SelectedGroupStore
|
||||
fun selectedGroupStore(): SelectedGroupDataSource
|
||||
|
||||
fun activeSessionObservableStore(): ActiveSessionObservableStore
|
||||
fun activeSessionObservableStore(): ActiveSessionDataSource
|
||||
|
||||
fun incomingVerificationRequestHandler(): IncomingVerificationRequestHandler
|
||||
|
||||
|
|
|
@ -27,10 +27,7 @@ import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreFromP
|
|||
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreSharedViewModel
|
||||
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupSharedViewModel
|
||||
import im.vector.riotx.features.crypto.verification.SasVerificationViewModel
|
||||
import im.vector.riotx.features.home.HomeNavigationViewModel
|
||||
import im.vector.riotx.features.home.createdirect.CreateDirectRoomNavigationViewModel
|
||||
import im.vector.riotx.features.reactions.EmojiChooserViewModel
|
||||
import im.vector.riotx.features.roomdirectory.RoomDirectoryNavigationViewModel
|
||||
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
||||
|
||||
@Module
|
||||
|
@ -76,16 +73,6 @@ interface ViewModelModule {
|
|||
@ViewModelKey(KeysBackupRestoreFromPassphraseViewModel::class)
|
||||
fun bindKeysBackupRestoreFromPassphraseViewModel(viewModel: KeysBackupRestoreFromPassphraseViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(RoomDirectoryNavigationViewModel::class)
|
||||
fun bindRoomDirectoryNavigationViewModel(viewModel: RoomDirectoryNavigationViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(HomeNavigationViewModel::class)
|
||||
fun bindHomeNavigationViewModel(viewModel: HomeNavigationViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(KeysBackupSetupSharedViewModel::class)
|
||||
|
@ -95,9 +82,4 @@ interface ViewModelModule {
|
|||
@IntoMap
|
||||
@ViewModelKey(ConfigurationViewModel::class)
|
||||
fun bindConfigurationViewModel(viewModel: ConfigurationViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(CreateDirectRoomNavigationViewModel::class)
|
||||
fun bindCreateDirectRoomNavigationViewModel(viewModel: CreateDirectRoomNavigationViewModel): ViewModel
|
||||
}
|
||||
|
|
|
@ -5,26 +5,33 @@
|
|||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package im.vector.riotx.features.home.room.detail.timeline.action
|
||||
package im.vector.riotx.core.epoxy.bottomsheet
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.ImageViewCompat
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.features.themes.ThemeUtils
|
||||
|
||||
/**
|
||||
* A action for bottom sheet.
|
||||
|
@ -42,28 +49,48 @@ abstract class BottomSheetItemAction : VectorEpoxyModel<BottomSheetItemAction.Ho
|
|||
@EpoxyAttribute
|
||||
var expanded = false
|
||||
@EpoxyAttribute
|
||||
var selected = false
|
||||
@EpoxyAttribute
|
||||
var subMenuItem = false
|
||||
@EpoxyAttribute
|
||||
var destructive = false
|
||||
@EpoxyAttribute
|
||||
lateinit var listener: View.OnClickListener
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
holder.view.setOnClickListener {
|
||||
listener.onClick(it)
|
||||
}
|
||||
|
||||
holder.startSpace.isVisible = subMenuItem
|
||||
val tintColor = if (destructive) {
|
||||
ContextCompat.getColor(holder.view.context, R.color.riotx_notice)
|
||||
} else {
|
||||
ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_secondary)
|
||||
}
|
||||
holder.icon.setImageResource(iconRes)
|
||||
ImageViewCompat.setImageTintList(holder.icon, ColorStateList.valueOf(tintColor))
|
||||
holder.text.setText(textRes)
|
||||
holder.expand.isVisible = showExpand
|
||||
holder.text.setTextColor(tintColor)
|
||||
holder.selected.isInvisible = !selected
|
||||
if (showExpand) {
|
||||
holder.expand.setImageResource(if (expanded) R.drawable.ic_material_expand_less_black else R.drawable.ic_material_expand_more_black)
|
||||
val expandDrawable = if (expanded) {
|
||||
ContextCompat.getDrawable(holder.view.context, R.drawable.ic_material_expand_less_black)
|
||||
} else {
|
||||
ContextCompat.getDrawable(holder.view.context, R.drawable.ic_material_expand_more_black)
|
||||
}
|
||||
expandDrawable?.also {
|
||||
DrawableCompat.setTint(it, tintColor)
|
||||
}
|
||||
holder.text.setCompoundDrawablesWithIntrinsicBounds(null, null, expandDrawable, null)
|
||||
} else {
|
||||
holder.text.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val startSpace by bind<View>(R.id.action_start_space)
|
||||
val icon by bind<ImageView>(R.id.action_icon)
|
||||
val text by bind<TextView>(R.id.action_title)
|
||||
val expand by bind<ImageView>(R.id.action_expand)
|
||||
val startSpace by bind<View>(R.id.actionStartSpace)
|
||||
val icon by bind<ImageView>(R.id.actionIcon)
|
||||
val text by bind<TextView>(R.id.actionTitle)
|
||||
val selected by bind<ImageView>(R.id.actionSelected)
|
||||
}
|
||||
}
|
|
@ -5,15 +5,16 @@
|
|||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package im.vector.riotx.features.home.room.detail.timeline.action
|
||||
package im.vector.riotx.core.epoxy.bottomsheet
|
||||
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
@ -24,7 +25,6 @@ import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
|||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||
|
||||
/**
|
||||
* A message preview for bottom sheet.
|
||||
|
@ -35,7 +35,9 @@ abstract class BottomSheetItemMessagePreview : VectorEpoxyModel<BottomSheetItemM
|
|||
@EpoxyAttribute
|
||||
lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute
|
||||
lateinit var informationData: MessageInformationData
|
||||
lateinit var avatarUrl: String
|
||||
@EpoxyAttribute
|
||||
lateinit var senderId: String
|
||||
@EpoxyAttribute
|
||||
var senderName: String? = null
|
||||
@EpoxyAttribute
|
||||
|
@ -44,7 +46,7 @@ abstract class BottomSheetItemMessagePreview : VectorEpoxyModel<BottomSheetItemM
|
|||
var time: CharSequence? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
avatarRenderer.render(informationData.avatarUrl, informationData.senderId, senderName, holder.avatar)
|
||||
avatarRenderer.render(avatarUrl, senderId, senderName, holder.avatar)
|
||||
holder.sender.setTextOrHide(senderName)
|
||||
holder.body.text = body
|
||||
holder.timestamp.setTextOrHide(time)
|
|
@ -5,15 +5,16 @@
|
|||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package im.vector.riotx.features.home.room.detail.timeline.action
|
||||
package im.vector.riotx.core.epoxy.bottomsheet
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.widget.TextView
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package im.vector.riotx.core.epoxy.bottomsheet
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
|
||||
/**
|
||||
* A room preview for bottom sheet.
|
||||
*/
|
||||
@EpoxyModelClass(layout = R.layout.item_bottom_sheet_room_preview)
|
||||
abstract class BottomSheetItemRoomPreview : VectorEpoxyModel<BottomSheetItemRoomPreview.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute
|
||||
lateinit var avatarUrl: String
|
||||
@EpoxyAttribute
|
||||
lateinit var roomId: String
|
||||
@EpoxyAttribute
|
||||
var roomName: String? = null
|
||||
@EpoxyAttribute var settingsClickListener: View.OnClickListener? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
avatarRenderer.render(avatarUrl, roomId, roomName, holder.avatar)
|
||||
holder.roomName.setTextOrHide(roomName)
|
||||
holder.roomSettings.setOnClickListener(settingsClickListener)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val avatar by bind<ImageView>(R.id.bottomSheetRoomPreviewAvatar)
|
||||
val roomName by bind<TextView>(R.id.bottomSheetRoomPreviewName)
|
||||
val roomSettings by bind<View>(R.id.bottomSheetRoomPreviewSettings)
|
||||
}
|
||||
}
|
|
@ -5,15 +5,16 @@
|
|||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package im.vector.riotx.features.home.room.detail.timeline.action
|
||||
package im.vector.riotx.core.epoxy.bottomsheet
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
|
@ -5,15 +5,16 @@
|
|||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package im.vector.riotx.features.home.room.detail.timeline.action
|
||||
package im.vector.riotx.core.epoxy.bottomsheet
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.core.mvrx
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
|
||||
abstract class NavigationViewModel<NavigationClass> : ViewModel() {
|
||||
|
||||
private val _navigateTo = MutableLiveData<LiveEvent<NavigationClass>>()
|
||||
val navigateTo: LiveData<LiveEvent<NavigationClass>>
|
||||
get() = _navigateTo
|
||||
|
||||
fun goTo(navigation: NavigationClass) {
|
||||
_navigateTo.postLiveEvent(navigation)
|
||||
}
|
||||
}
|
|
@ -17,18 +17,30 @@
|
|||
package im.vector.riotx.core.utils
|
||||
|
||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||
import com.jakewharton.rxrelay2.PublishRelay
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
open class RxStore<T>(private val defaultValue: T? = null) {
|
||||
interface DataSource<T> {
|
||||
fun observe(): Observable<T>
|
||||
}
|
||||
|
||||
interface MutableDataSource<T> : DataSource<T> {
|
||||
fun post(value: T)
|
||||
}
|
||||
|
||||
/**
|
||||
* This datasource emits the most recent value it has observed and all subsequent observed values to each subscriber.
|
||||
*/
|
||||
open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableDataSource<T> {
|
||||
|
||||
private val storeRelay = createRelay()
|
||||
|
||||
fun observe(): Observable<T> {
|
||||
override fun observe(): Observable<T> {
|
||||
return storeRelay.hide().observeOn(Schedulers.computation())
|
||||
}
|
||||
|
||||
fun post(value: T) {
|
||||
override fun post(value: T) {
|
||||
storeRelay.accept(value)
|
||||
}
|
||||
|
||||
|
@ -40,3 +52,19 @@ open class RxStore<T>(private val defaultValue: T? = null) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This datasource only emits all subsequent observed values to each subscriber.
|
||||
*/
|
||||
open class PublishDataSource<T> : MutableDataSource<T> {
|
||||
|
||||
private val storeRelay = PublishRelay.create<T>()
|
||||
|
||||
override fun observe(): Observable<T> {
|
||||
return storeRelay.hide()
|
||||
}
|
||||
|
||||
override fun post(value: T) {
|
||||
storeRelay.accept(value)
|
||||
}
|
||||
}
|
|
@ -31,7 +31,6 @@ import im.vector.riotx.R
|
|||
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.extensions.hideKeyboard
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.extensions.replaceFragment
|
||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
|
@ -83,15 +82,17 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
||||
}
|
||||
|
||||
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
|
||||
when (navigation) {
|
||||
is Navigation.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
||||
is Navigation.OpenGroup -> {
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java)
|
||||
navigationViewModel.observe()
|
||||
.subscribe { navigation ->
|
||||
when (navigation) {
|
||||
is Navigation.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
||||
is Navigation.OpenGroup -> {
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
|
||||
if (intent.getBooleanExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION, false)) {
|
||||
notificationDrawerManager.clearAllEvents()
|
||||
|
|
|
@ -129,7 +129,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
groupToolbar.title = ""
|
||||
groupToolbarAvatarImageView.setOnClickListener {
|
||||
navigationViewModel.goTo(HomeActivity.Navigation.OpenDrawer)
|
||||
navigationViewModel.post(HomeActivity.Navigation.OpenDrawer)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import im.vector.matrix.rx.rx
|
|||
import im.vector.riotx.core.di.HasScreenInjector
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.features.home.group.SelectedGroupStore
|
||||
import im.vector.riotx.features.home.group.SelectedGroupDataSource
|
||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||
import im.vector.riotx.features.ui.UiStateRepository
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
@ -38,8 +38,8 @@ import io.reactivex.schedulers.Schedulers
|
|||
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
|
||||
private val session: Session,
|
||||
private val uiStateRepository: UiStateRepository,
|
||||
private val selectedGroupStore: SelectedGroupStore,
|
||||
private val homeRoomListStore: HomeRoomListObservableStore,
|
||||
private val selectedGroupStore: SelectedGroupDataSource,
|
||||
private val homeRoomListStore: HomeRoomListDataSource,
|
||||
private val stringProvider: StringProvider)
|
||||
: VectorViewModel<HomeDetailViewState>(initialState) {
|
||||
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package im.vector.riotx.features.home
|
||||
|
||||
import im.vector.riotx.core.mvrx.NavigationViewModel
|
||||
import javax.inject.Inject
|
||||
import androidx.lifecycle.ViewModel
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import im.vector.riotx.core.utils.MutableDataSource
|
||||
|
||||
class HomeNavigationViewModel @Inject constructor() : NavigationViewModel<HomeActivity.Navigation>()
|
||||
class HomeNavigationViewModel(private val source: MutableDataSource<HomeActivity.Navigation> = PublishDataSource())
|
||||
: ViewModel(), MutableDataSource<HomeActivity.Navigation> by source
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
package im.vector.riotx.features.home
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotx.core.utils.RxStore
|
||||
import im.vector.riotx.core.utils.BehaviorDataSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class HomeRoomListObservableStore @Inject constructor() : RxStore<List<RoomSummary>>()
|
||||
class HomeRoomListDataSource @Inject constructor() : BehaviorDataSource<List<RoomSummary>>()
|
|
@ -31,7 +31,6 @@ import im.vector.riotx.core.di.ScreenComponent
|
|||
import im.vector.riotx.core.error.ErrorFormatter
|
||||
import im.vector.riotx.core.extensions.addFragment
|
||||
import im.vector.riotx.core.extensions.addFragmentToBackstack
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.platform.SimpleFragmentActivity
|
||||
import im.vector.riotx.core.platform.WaitingViewData
|
||||
import kotlinx.android.synthetic.main.activity.*
|
||||
|
@ -59,13 +58,15 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
toolbar.visibility = View.GONE
|
||||
navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(CreateDirectRoomNavigationViewModel::class.java)
|
||||
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
|
||||
when (navigation) {
|
||||
is Navigation.UsersDirectory -> addFragmentToBackstack(R.id.container, CreateDirectRoomDirectoryUsersFragment::class.java)
|
||||
Navigation.Close -> finish()
|
||||
Navigation.Previous -> onBackPressed()
|
||||
}
|
||||
}
|
||||
navigationViewModel.observe()
|
||||
.subscribe { navigation ->
|
||||
when (navigation) {
|
||||
is Navigation.UsersDirectory -> addFragmentToBackstack(R.id.container, CreateDirectRoomDirectoryUsersFragment::class.java)
|
||||
Navigation.Close -> finish()
|
||||
Navigation.Previous -> onBackPressed()
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
if (isFirstCreation()) {
|
||||
addFragment(R.id.container, CreateDirectRoomKnownUsersFragment::class.java)
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ class CreateDirectRoomDirectoryUsersFragment @Inject constructor(
|
|||
|
||||
private fun setupCloseView() {
|
||||
createDirectRoomClose.setOnClickListener {
|
||||
navigationViewModel.goTo(CreateDirectRoomActivity.Navigation.Previous)
|
||||
navigationViewModel.post(CreateDirectRoomActivity.Navigation.Previous)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ class CreateDirectRoomDirectoryUsersFragment @Inject constructor(
|
|||
override fun onItemClick(user: User) {
|
||||
view?.hideKeyboard()
|
||||
viewModel.handle(CreateDirectRoomActions.SelectUser(user))
|
||||
navigationViewModel.goTo(CreateDirectRoomActivity.Navigation.Previous)
|
||||
navigationViewModel.post(CreateDirectRoomActivity.Navigation.Previous)
|
||||
}
|
||||
|
||||
override fun retryDirectoryUsersRequest() {
|
||||
|
|
|
@ -89,7 +89,7 @@ class CreateDirectRoomKnownUsersFragment @Inject constructor(
|
|||
|
||||
private fun setupAddByMatrixIdView() {
|
||||
addByMatrixId.setOnClickListener {
|
||||
navigationViewModel.goTo(CreateDirectRoomActivity.Navigation.UsersDirectory)
|
||||
navigationViewModel.post(CreateDirectRoomActivity.Navigation.UsersDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package im.vector.riotx.features.home.createdirect
|
||||
|
||||
import im.vector.riotx.core.mvrx.NavigationViewModel
|
||||
import javax.inject.Inject
|
||||
import androidx.lifecycle.ViewModel
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import im.vector.riotx.core.utils.MutableDataSource
|
||||
|
||||
class CreateDirectRoomNavigationViewModel @Inject constructor(): NavigationViewModel<CreateDirectRoomActivity.Navigation>()
|
||||
class CreateDirectRoomNavigationViewModel(private val dataSource: MutableDataSource<CreateDirectRoomActivity.Navigation> = PublishDataSource())
|
||||
: ViewModel(), MutableDataSource<CreateDirectRoomActivity.Navigation> by dataSource
|
||||
|
|
|
@ -49,7 +49,7 @@ class GroupListFragment @Inject constructor(
|
|||
groupListEpoxyRecyclerView.setController(groupController)
|
||||
viewModel.subscribe { renderState(it) }
|
||||
viewModel.openGroupLiveData.observeEvent(this) {
|
||||
navigationViewModel.goTo(HomeActivity.Navigation.OpenGroup)
|
||||
navigationViewModel.post(HomeActivity.Navigation.OpenGroup)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ import io.reactivex.functions.BiFunction
|
|||
const val ALL_COMMUNITIES_GROUP_ID = "ALL_COMMUNITIES_GROUP_ID"
|
||||
|
||||
class GroupListViewModel @AssistedInject constructor(@Assisted initialState: GroupListViewState,
|
||||
private val selectedGroupStore: SelectedGroupStore,
|
||||
private val selectedGroupStore: SelectedGroupDataSource,
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider
|
||||
) : VectorViewModel<GroupListViewState>(initialState) {
|
||||
|
|
|
@ -18,9 +18,9 @@ package im.vector.riotx.features.home.group
|
|||
|
||||
import arrow.core.Option
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.riotx.core.utils.RxStore
|
||||
import im.vector.riotx.core.utils.BehaviorDataSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SelectedGroupStore @Inject constructor() : RxStore<Option<GroupSummary>>(Option.empty())
|
||||
class SelectedGroupDataSource @Inject constructor() : BehaviorDataSource<Option<GroupSummary>>(Option.empty())
|
|
@ -97,8 +97,8 @@ import im.vector.riotx.features.home.room.detail.composer.TextComposerViewModel
|
|||
import im.vector.riotx.features.home.room.detail.composer.TextComposerViewState
|
||||
import im.vector.riotx.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
|
||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.riotx.features.home.room.detail.timeline.action.ActionsHandler
|
||||
import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsBottomSheet
|
||||
import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsDispatcher
|
||||
import im.vector.riotx.features.home.room.detail.timeline.action.SimpleAction
|
||||
import im.vector.riotx.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.*
|
||||
|
@ -193,7 +193,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
override fun getMenuRes() = R.menu.menu_timeline
|
||||
|
||||
private lateinit var actionViewModel: ActionsHandler
|
||||
private lateinit var messageActionsDispatcher: MessageActionsDispatcher
|
||||
private lateinit var layoutManager: LinearLayoutManager
|
||||
private lateinit var attachmentsHelper: AttachmentsHelper
|
||||
private lateinit var keyboardStateUtils: KeyboardStateUtils
|
||||
|
@ -206,7 +206,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
actionViewModel = ViewModelProviders.of(requireActivity()).get(ActionsHandler::class.java)
|
||||
messageActionsDispatcher = ViewModelProviders.of(requireActivity()).get(MessageActionsDispatcher::class.java)
|
||||
attachmentsHelper = AttachmentsHelper.create(this, this).register()
|
||||
keyboardStateUtils = KeyboardStateUtils(requireActivity())
|
||||
setupToolbar(roomToolbar)
|
||||
|
@ -225,9 +225,12 @@ class RoomDetailFragment @Inject constructor(
|
|||
val message = requireContext().getString(pair.first, *pair.second.toTypedArray())
|
||||
showSnackWithMessage(message, Snackbar.LENGTH_LONG)
|
||||
}
|
||||
actionViewModel.actionCommandEvent.observeEvent(this) {
|
||||
handleActions(it)
|
||||
}
|
||||
messageActionsDispatcher
|
||||
.observe()
|
||||
.subscribe {
|
||||
handleActions(it)
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
|
||||
roomDetailViewModel.navigateToEvent.observeEvent(this) {
|
||||
val scrollPosition = timelineEventController.searchPositionOfEvent(it)
|
||||
|
|
|
@ -47,7 +47,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
|
|||
|
||||
override val showExpanded = true
|
||||
|
||||
private lateinit var actionHandlerModel: ActionsHandler
|
||||
private lateinit var messageActionsStore: MessageActionsDispatcher
|
||||
|
||||
override fun injectWith(screenComponent: ScreenComponent) {
|
||||
screenComponent.inject(this)
|
||||
|
@ -61,7 +61,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
|
|||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
actionHandlerModel = ViewModelProviders.of(requireActivity()).get(ActionsHandler::class.java)
|
||||
messageActionsStore = ViewModelProviders.of(requireActivity()).get(MessageActionsDispatcher::class.java)
|
||||
recyclerView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
|
||||
recyclerView.adapter = messageActionsEpoxyController.adapter
|
||||
// Disable item animation
|
||||
|
@ -74,7 +74,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
|
|||
// Toggle report menu
|
||||
viewModel.toggleReportMenu()
|
||||
} else {
|
||||
actionHandlerModel.fireAction(simpleAction)
|
||||
messageActionsStore.post(simpleAction)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,20 +15,13 @@
|
|||
*/
|
||||
package im.vector.riotx.features.home.room.detail.timeline.action
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
import javax.inject.Inject
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import im.vector.riotx.core.utils.MutableDataSource
|
||||
|
||||
/**
|
||||
* Activity shared view model to handle message actions
|
||||
*/
|
||||
class ActionsHandler @Inject constructor() : ViewModel() {
|
||||
|
||||
val actionCommandEvent = MutableLiveData<LiveEvent<SimpleAction>>()
|
||||
|
||||
fun fireAction(action: SimpleAction) {
|
||||
actionCommandEvent.postLiveEvent(action)
|
||||
}
|
||||
}
|
||||
class MessageActionsDispatcher constructor(
|
||||
private val dataSource: MutableDataSource<SimpleAction> = PublishDataSource()
|
||||
) : ViewModel(), MutableDataSource<SimpleAction> by dataSource
|
|
@ -20,6 +20,12 @@ import com.airbnb.epoxy.TypedEpoxyController
|
|||
import com.airbnb.mvrx.Success
|
||||
import im.vector.riotx.EmojiCompatFontProvider
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.BottomSheetItemQuickReactions
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemAction
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemMessagePreview
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemQuickReactions
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemSendState
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemSeparator
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import javax.inject.Inject
|
||||
|
@ -40,7 +46,8 @@ class MessageActionsEpoxyController @Inject constructor(private val stringProvid
|
|||
bottomSheetItemMessagePreview {
|
||||
id("preview")
|
||||
avatarRenderer(avatarRenderer)
|
||||
informationData(state.informationData)
|
||||
avatarUrl(state.informationData.avatarUrl ?: "")
|
||||
senderId(state.informationData.senderId)
|
||||
senderName(state.senderName())
|
||||
body(body)
|
||||
time(state.time())
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.riotx.features.home.room.list
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
|
||||
sealed class RoomListActions {
|
||||
data class SelectRoom(val roomSummary: RoomSummary) : RoomListActions()
|
||||
|
@ -24,5 +25,7 @@ sealed class RoomListActions {
|
|||
data class AcceptInvitation(val roomSummary: RoomSummary) : RoomListActions()
|
||||
data class RejectInvitation(val roomSummary: RoomSummary) : RoomListActions()
|
||||
data class FilterWith(val filter: String) : RoomListActions()
|
||||
data class ChangeRoomNotificationState(val roomId: String, val notificationState: RoomNotificationState) : RoomListActions()
|
||||
data class LeaveRoom(val roomId: String) : RoomListActions()
|
||||
object MarkAllRoomsRead : RoomListActions()
|
||||
}
|
||||
|
|
|
@ -21,8 +21,10 @@ import android.os.Parcelable
|
|||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.airbnb.mvrx.*
|
||||
|
@ -30,17 +32,20 @@ import com.google.android.material.snackbar.Snackbar
|
|||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer
|
||||
import im.vector.riotx.core.error.ErrorFormatter
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.extensions.observeEventFirstThrottle
|
||||
import im.vector.riotx.core.platform.OnBackPressed
|
||||
import im.vector.riotx.core.platform.StateView
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActions
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsStore
|
||||
import im.vector.riotx.features.home.room.list.widget.FabMenuView
|
||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||
import im.vector.riotx.features.share.SharedData
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import javax.inject.Inject
|
||||
|
@ -67,6 +72,7 @@ class RoomListFragment @Inject constructor(
|
|||
SHARE(/* Not used */ 0)
|
||||
}
|
||||
|
||||
private lateinit var quickActionsDispatcher: RoomListQuickActionsStore
|
||||
private val roomListParams: RoomListParams by args()
|
||||
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
|
||||
|
||||
|
@ -94,25 +100,43 @@ class RoomListFragment @Inject constructor(
|
|||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
quickActionsDispatcher = ViewModelProviders.of(requireActivity()).get(RoomListQuickActionsStore::class.java)
|
||||
setupCreateRoomButton()
|
||||
setupRecyclerView()
|
||||
roomListViewModel.subscribe { renderState(it) }
|
||||
roomListViewModel.openRoomLiveData.observeEventFirstThrottle(this, 800L) {
|
||||
if (roomListParams.displayMode == DisplayMode.SHARE) {
|
||||
val sharedData = roomListParams.sharedData ?: return@observeEventFirstThrottle
|
||||
navigator.openRoomForSharing(requireActivity(), it, sharedData)
|
||||
} else {
|
||||
navigator.openRoom(requireActivity(), it)
|
||||
}
|
||||
}
|
||||
|
||||
roomListViewModel.viewEvents
|
||||
.observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
when (it) {
|
||||
is RoomListViewEvents.SelectRoom -> openSelectedRoom(it)
|
||||
is RoomListViewEvents.Failure -> showError(it)
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
|
||||
createChatFabMenu.listener = this
|
||||
|
||||
roomListViewModel.invitationAnswerErrorLiveData.observeEvent(this) { throwable ->
|
||||
vectorBaseActivity.coordinatorLayout?.let {
|
||||
Snackbar.make(it, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
quickActionsDispatcher
|
||||
.observe()
|
||||
.subscribe { handleQuickActions(it) }
|
||||
.disposeOnDestroy()
|
||||
}
|
||||
|
||||
private fun openSelectedRoom(event: RoomListViewEvents.SelectRoom) {
|
||||
if (roomListParams.displayMode == DisplayMode.SHARE) {
|
||||
val sharedData = roomListParams.sharedData ?: return
|
||||
navigator.openRoomForSharing(requireActivity(), event.roomId, sharedData)
|
||||
} else {
|
||||
navigator.openRoom(requireActivity(), event.roomId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showError(event: RoomListViewEvents.Failure) {
|
||||
vectorBaseActivity.coordinatorLayout?.let {
|
||||
Snackbar.make(it, errorFormatter.toHumanReadable(event.throwable), Snackbar.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,6 +216,36 @@ class RoomListFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleQuickActions(quickActions: RoomListQuickActions) {
|
||||
when (quickActions) {
|
||||
is RoomListQuickActions.NotificationsAllNoisy -> {
|
||||
roomListViewModel.accept(RoomListActions.ChangeRoomNotificationState(quickActions.roomId, RoomNotificationState.ALL_MESSAGES_NOISY))
|
||||
}
|
||||
is RoomListQuickActions.NotificationsAll -> {
|
||||
roomListViewModel.accept(RoomListActions.ChangeRoomNotificationState(quickActions.roomId, RoomNotificationState.ALL_MESSAGES))
|
||||
}
|
||||
is RoomListQuickActions.NotificationsMentionsOnly -> {
|
||||
roomListViewModel.accept(RoomListActions.ChangeRoomNotificationState(quickActions.roomId, RoomNotificationState.MENTIONS_ONLY))
|
||||
}
|
||||
is RoomListQuickActions.NotificationsMute -> {
|
||||
roomListViewModel.accept(RoomListActions.ChangeRoomNotificationState(quickActions.roomId, RoomNotificationState.MUTE))
|
||||
}
|
||||
is RoomListQuickActions.Settings -> {
|
||||
vectorBaseActivity.notImplemented("Opening room settings")
|
||||
}
|
||||
is RoomListQuickActions.Leave -> {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.room_participants_leave_prompt_title)
|
||||
.setMessage(R.string.room_participants_leave_prompt_msg)
|
||||
.setPositiveButton(R.string.leave) { _, _ ->
|
||||
roomListViewModel.accept(RoomListActions.LeaveRoom(quickActions.roomId))
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderState(state: RoomListViewState) {
|
||||
when (state.asyncFilteredRooms) {
|
||||
is Incomplete -> renderLoading()
|
||||
|
@ -287,10 +341,17 @@ class RoomListFragment @Inject constructor(
|
|||
|
||||
// RoomSummaryController.Callback **************************************************************
|
||||
|
||||
override fun onRoomSelected(room: RoomSummary) {
|
||||
override fun onRoomClicked(room: RoomSummary) {
|
||||
roomListViewModel.accept(RoomListActions.SelectRoom(room))
|
||||
}
|
||||
|
||||
override fun onRoomLongClicked(room: RoomSummary): Boolean {
|
||||
RoomListQuickActionsBottomSheet
|
||||
.newInstance(room.roomId)
|
||||
.show(requireActivity().supportFragmentManager, "ROOM_LIST_QUICK_ACTIONS")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onAcceptRoomInvitation(room: RoomSummary) {
|
||||
notificationDrawerManager.clearMemberShipNotificationForRoom(room.roomId)
|
||||
roomListViewModel.accept(RoomListActions.AcceptInvitation(room))
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.home.room.list
|
||||
|
||||
/**
|
||||
* Transient events for RoomList
|
||||
*/
|
||||
sealed class RoomListViewEvents {
|
||||
data class Failure(val throwable: Throwable) : RoomListViewEvents()
|
||||
data class SelectRoom(val roomId: String) : RoomListViewEvents()
|
||||
}
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package im.vector.riotx.features.home.room.list
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
|
@ -26,17 +24,16 @@ import im.vector.matrix.android.api.session.Session
|
|||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
import im.vector.riotx.core.utils.RxStore
|
||||
import im.vector.riotx.core.utils.DataSource
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
||||
private val session: Session,
|
||||
private val roomSummariesStore: RxStore<List<RoomSummary>>,
|
||||
private val roomSummariesSource: DataSource<List<RoomSummary>>,
|
||||
private val alphabeticalRoomComparator: AlphabeticalRoomComparator,
|
||||
private val chronologicalRoomComparator: ChronologicalRoomComparator)
|
||||
: VectorViewModel<RoomListViewState>(initialState) {
|
||||
|
@ -57,13 +54,8 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
private val displayMode = initialState.displayMode
|
||||
private val roomListDisplayModeFilter = RoomListDisplayModeFilter(displayMode)
|
||||
|
||||
private val _openRoomLiveData = MutableLiveData<LiveEvent<String>>()
|
||||
val openRoomLiveData: LiveData<LiveEvent<String>>
|
||||
get() = _openRoomLiveData
|
||||
|
||||
private val _invitationAnswerErrorLiveData = MutableLiveData<LiveEvent<Throwable>>()
|
||||
val invitationAnswerErrorLiveData: LiveData<LiveEvent<Throwable>>
|
||||
get() = _invitationAnswerErrorLiveData
|
||||
private val _viewEvents = PublishDataSource<RoomListViewEvents>()
|
||||
val viewEvents: DataSource<RoomListViewEvents> = _viewEvents
|
||||
|
||||
init {
|
||||
observeRoomSummaries()
|
||||
|
@ -71,19 +63,21 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
|
||||
fun accept(action: RoomListActions) {
|
||||
when (action) {
|
||||
is RoomListActions.SelectRoom -> handleSelectRoom(action)
|
||||
is RoomListActions.ToggleCategory -> handleToggleCategory(action)
|
||||
is RoomListActions.AcceptInvitation -> handleAcceptInvitation(action)
|
||||
is RoomListActions.RejectInvitation -> handleRejectInvitation(action)
|
||||
is RoomListActions.FilterWith -> handleFilter(action)
|
||||
is RoomListActions.MarkAllRoomsRead -> handleMarkAllRoomsRead()
|
||||
is RoomListActions.SelectRoom -> handleSelectRoom(action)
|
||||
is RoomListActions.ToggleCategory -> handleToggleCategory(action)
|
||||
is RoomListActions.AcceptInvitation -> handleAcceptInvitation(action)
|
||||
is RoomListActions.RejectInvitation -> handleRejectInvitation(action)
|
||||
is RoomListActions.FilterWith -> handleFilter(action)
|
||||
is RoomListActions.MarkAllRoomsRead -> handleMarkAllRoomsRead()
|
||||
is RoomListActions.LeaveRoom -> handleLeaveRoom(action)
|
||||
is RoomListActions.ChangeRoomNotificationState -> handleChangeNotificationMode(action)
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handleSelectRoom(action: RoomListActions.SelectRoom) {
|
||||
_openRoomLiveData.postLiveEvent(action.roomSummary.roomId)
|
||||
_viewEvents.post(RoomListViewEvents.SelectRoom(action.roomSummary.roomId))
|
||||
}
|
||||
|
||||
private fun handleToggleCategory(action: RoomListActions.ToggleCategory) = setState {
|
||||
|
@ -99,7 +93,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
}
|
||||
|
||||
private fun observeRoomSummaries() {
|
||||
roomSummariesStore
|
||||
roomSummariesSource
|
||||
.observe()
|
||||
.observeOn(Schedulers.computation())
|
||||
.map {
|
||||
|
@ -109,7 +103,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
copy(asyncRooms = asyncRooms)
|
||||
}
|
||||
|
||||
roomSummariesStore
|
||||
roomSummariesSource
|
||||
.observe()
|
||||
.observeOn(Schedulers.computation())
|
||||
.map { buildRoomSummaries(it) }
|
||||
|
@ -142,8 +136,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
// Notify the user
|
||||
_invitationAnswerErrorLiveData.postLiveEvent(failure)
|
||||
|
||||
_viewEvents.post(RoomListViewEvents.Failure(failure))
|
||||
setState {
|
||||
copy(
|
||||
joiningRoomsIds = joiningRoomsIds - roomId,
|
||||
|
@ -180,8 +173,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
// Notify the user
|
||||
_invitationAnswerErrorLiveData.postLiveEvent(failure)
|
||||
|
||||
_viewEvents.post(RoomListViewEvents.Failure(failure))
|
||||
setState {
|
||||
copy(
|
||||
rejectingRoomsIds = rejectingRoomsIds - roomId,
|
||||
|
@ -201,6 +193,22 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
?.let { session.markAllAsRead(it, object : MatrixCallback<Unit> {}) }
|
||||
}
|
||||
|
||||
private fun handleChangeNotificationMode(action: RoomListActions.ChangeRoomNotificationState) {
|
||||
session.getRoom(action.roomId)?.setRoomNotificationState(action.notificationState, object : MatrixCallback<Unit> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
_viewEvents.post(RoomListViewEvents.Failure(failure))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handleLeaveRoom(action: RoomListActions.LeaveRoom) {
|
||||
session.getRoom(action.roomId)?.leave(object : MatrixCallback<Unit> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
_viewEvents.post(RoomListViewEvents.Failure(failure))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
|
||||
val invites = ArrayList<RoomSummary>()
|
||||
val favourites = ArrayList<RoomSummary>()
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
package im.vector.riotx.features.home.room.list
|
||||
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotx.features.home.HomeRoomListObservableStore
|
||||
import im.vector.riotx.features.share.ShareRoomListObservableStore
|
||||
import im.vector.riotx.features.home.HomeRoomListDataSource
|
||||
import im.vector.riotx.features.share.ShareRoomListDataSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
|
||||
private val homeRoomListObservableStore: Provider<HomeRoomListObservableStore>,
|
||||
private val shareRoomListObservableStore: Provider<ShareRoomListObservableStore>,
|
||||
private val homeRoomListDataSource: Provider<HomeRoomListDataSource>,
|
||||
private val shareRoomListDataSource: Provider<ShareRoomListDataSource>,
|
||||
private val alphabeticalRoomComparator: Provider<AlphabeticalRoomComparator>,
|
||||
private val chronologicalRoomComparator: Provider<ChronologicalRoomComparator>) : RoomListViewModel.Factory {
|
||||
|
||||
|
@ -32,7 +32,7 @@ class RoomListViewModelFactory @Inject constructor(private val session: Provider
|
|||
return RoomListViewModel(
|
||||
initialState,
|
||||
session.get(),
|
||||
if (initialState.displayMode == RoomListFragment.DisplayMode.SHARE) shareRoomListObservableStore.get() else homeRoomListObservableStore.get(),
|
||||
if (initialState.displayMode == RoomListFragment.DisplayMode.SHARE) shareRoomListDataSource.get() else homeRoomListDataSource.get(),
|
||||
alphabeticalRoomComparator.get(),
|
||||
chronologicalRoomComparator.get())
|
||||
}
|
||||
|
|
|
@ -154,7 +154,8 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
|||
|
||||
interface Listener : FilteredRoomFooterItem.FilteredRoomFooterItemListener {
|
||||
fun onToggleRoomCategory(roomCategory: RoomCategory)
|
||||
fun onRoomSelected(room: RoomSummary)
|
||||
fun onRoomClicked(room: RoomSummary)
|
||||
fun onRoomLongClicked(room: RoomSummary): Boolean
|
||||
fun onRejectRoomInvitation(room: RoomSummary)
|
||||
fun onAcceptRoomInvitation(room: RoomSummary)
|
||||
}
|
||||
|
|
|
@ -41,11 +41,13 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
|||
@EpoxyAttribute var hasUnreadMessage: Boolean = false
|
||||
@EpoxyAttribute var hasDraft: Boolean = false
|
||||
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
@EpoxyAttribute var itemLongClickListener: View.OnLongClickListener? = null
|
||||
@EpoxyAttribute var itemClickListener: View.OnClickListener? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||
holder.rootView.setOnClickListener(itemClickListener)
|
||||
holder.rootView.setOnLongClickListener(itemLongClickListener)
|
||||
holder.titleView.text = roomName
|
||||
holder.lastEventTimeView.text = lastEventTime
|
||||
holder.lastEventView.text = lastFormattedEvent
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.riotx.features.home.room.list
|
||||
|
||||
import android.view.View
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
|
@ -28,6 +29,7 @@ import im.vector.riotx.core.extensions.localDateTime
|
|||
import im.vector.riotx.core.resources.ColorProvider
|
||||
import im.vector.riotx.core.resources.DateProvider
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventFormatter
|
||||
import me.gujun.android.span.span
|
||||
|
@ -78,7 +80,7 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
|
|||
.rejectListener { listener?.onRejectRoomInvitation(roomSummary) }
|
||||
.roomName(roomSummary.displayName)
|
||||
.avatarUrl(roomSummary.avatarUrl)
|
||||
.listener { listener?.onRoomSelected(roomSummary) }
|
||||
.listener { listener?.onRoomClicked(roomSummary) }
|
||||
}
|
||||
|
||||
private fun createRoomItem(roomSummary: RoomSummary, listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
|
||||
|
@ -133,6 +135,13 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
|
|||
.unreadNotificationCount(unreadCount)
|
||||
.hasUnreadMessage(roomSummary.hasUnreadMessages)
|
||||
.hasDraft(roomSummary.userDrafts.isNotEmpty())
|
||||
.listener { listener?.onRoomSelected(roomSummary) }
|
||||
.itemLongClickListener { _ ->
|
||||
listener?.onRoomLongClicked(roomSummary) ?: false
|
||||
}
|
||||
.itemClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { _ ->
|
||||
listener?.onRoomClicked(roomSummary)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.home.room.list.actions
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import im.vector.riotx.R
|
||||
|
||||
sealed class RoomListQuickActions(@StringRes val titleRes: Int, @DrawableRes val iconResId: Int, val destructive: Boolean = false) {
|
||||
|
||||
data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActions(
|
||||
R.string.room_list_quick_actions_notifications_all_noisy,
|
||||
R.drawable.ic_room_actions_notifications_all_noisy
|
||||
)
|
||||
|
||||
data class NotificationsAll(val roomId: String) : RoomListQuickActions(
|
||||
R.string.room_list_quick_actions_notifications_all,
|
||||
R.drawable.ic_room_actions_notifications_all
|
||||
)
|
||||
|
||||
data class NotificationsMentionsOnly(val roomId: String) : RoomListQuickActions(
|
||||
R.string.room_list_quick_actions_notifications_mentions,
|
||||
R.drawable.ic_room_actions_notifications_mentions
|
||||
)
|
||||
|
||||
data class NotificationsMute(val roomId: String) : RoomListQuickActions(
|
||||
R.string.room_list_quick_actions_notifications_mute,
|
||||
R.drawable.ic_room_actions_notifications_mutes
|
||||
)
|
||||
|
||||
data class Settings(val roomId: String) : RoomListQuickActions(
|
||||
R.string.room_list_quick_actions_settings,
|
||||
R.drawable.ic_room_actions_settings
|
||||
)
|
||||
|
||||
data class Leave(val roomId: String) : RoomListQuickActions(
|
||||
R.string.room_list_quick_actions_leave,
|
||||
R.drawable.ic_room_actions_leave,
|
||||
true
|
||||
)
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.home.room.list.actions
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.riotx.features.navigation.Navigator
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import javax.inject.Inject
|
||||
|
||||
@Parcelize
|
||||
data class RoomListActionsArgs(
|
||||
val roomId: String
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
* Bottom sheet fragment that shows room information with list of contextual actions
|
||||
*/
|
||||
class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomListQuickActionsEpoxyController.Listener {
|
||||
|
||||
private lateinit var actionsDispatcher: RoomListQuickActionsStore
|
||||
@Inject lateinit var roomListActionsViewModelFactory: RoomListQuickActionsViewModel.Factory
|
||||
@Inject lateinit var roomListActionsEpoxyController: RoomListQuickActionsEpoxyController
|
||||
@Inject lateinit var navigator: Navigator
|
||||
|
||||
private val viewModel: RoomListQuickActionsViewModel by fragmentViewModel(RoomListQuickActionsViewModel::class)
|
||||
|
||||
@BindView(R.id.bottomSheetRecyclerView)
|
||||
lateinit var recyclerView: RecyclerView
|
||||
|
||||
override val showExpanded = true
|
||||
|
||||
override fun injectWith(screenComponent: ScreenComponent) {
|
||||
screenComponent.inject(this)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(R.layout.bottom_sheet_generic_list, container, false)
|
||||
ButterKnife.bind(this, view)
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
actionsDispatcher = ViewModelProviders.of(requireActivity()).get(RoomListQuickActionsStore::class.java)
|
||||
recyclerView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
|
||||
recyclerView.adapter = roomListActionsEpoxyController.adapter
|
||||
// Disable item animation
|
||||
recyclerView.itemAnimator = null
|
||||
roomListActionsEpoxyController.listener = this
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) {
|
||||
roomListActionsEpoxyController.setData(it)
|
||||
super.invalidate()
|
||||
}
|
||||
|
||||
override fun didSelectMenuAction(quickActions: RoomListQuickActions) {
|
||||
actionsDispatcher.post(quickActions)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(roomId: String): RoomListQuickActionsBottomSheet {
|
||||
return RoomListQuickActionsBottomSheet().apply {
|
||||
setArguments(RoomListActionsArgs(roomId))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.riotx.features.home.room.list.actions
|
||||
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemAction
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemRoomPreview
|
||||
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetItemSeparator
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Epoxy controller for room list actions
|
||||
*/
|
||||
class RoomListQuickActionsEpoxyController @Inject constructor(private val avatarRenderer: AvatarRenderer)
|
||||
: TypedEpoxyController<RoomListQuickActionsState>() {
|
||||
|
||||
var listener: Listener? = null
|
||||
|
||||
override fun buildModels(state: RoomListQuickActionsState) {
|
||||
val roomSummary = state.roomSummary() ?: return
|
||||
|
||||
// Preview
|
||||
bottomSheetItemRoomPreview {
|
||||
id("preview")
|
||||
avatarRenderer(avatarRenderer)
|
||||
roomName(roomSummary.displayName)
|
||||
avatarUrl(roomSummary.avatarUrl)
|
||||
roomId(roomSummary.roomId)
|
||||
settingsClickListener(View.OnClickListener { listener?.didSelectMenuAction(RoomListQuickActions.Settings(roomSummary.roomId)) })
|
||||
}
|
||||
|
||||
// Notifications
|
||||
bottomSheetItemSeparator {
|
||||
id("notifications_separator")
|
||||
}
|
||||
|
||||
val selectedRoomState = state.roomNotificationState()
|
||||
RoomListQuickActions.NotificationsAllNoisy(roomSummary.roomId).toBottomSheetItem(0, selectedRoomState)
|
||||
RoomListQuickActions.NotificationsAll(roomSummary.roomId).toBottomSheetItem(1, selectedRoomState)
|
||||
RoomListQuickActions.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState)
|
||||
RoomListQuickActions.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState)
|
||||
|
||||
// Leave
|
||||
bottomSheetItemSeparator {
|
||||
id("leave_separator")
|
||||
}
|
||||
RoomListQuickActions.Leave(roomSummary.roomId).toBottomSheetItem(5)
|
||||
}
|
||||
|
||||
private fun RoomListQuickActions.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) {
|
||||
val selected = when (this) {
|
||||
is RoomListQuickActions.NotificationsAllNoisy -> roomNotificationState == RoomNotificationState.ALL_MESSAGES_NOISY
|
||||
is RoomListQuickActions.NotificationsAll -> roomNotificationState == RoomNotificationState.ALL_MESSAGES
|
||||
is RoomListQuickActions.NotificationsMentionsOnly -> roomNotificationState == RoomNotificationState.MENTIONS_ONLY
|
||||
is RoomListQuickActions.NotificationsMute -> roomNotificationState == RoomNotificationState.MUTE
|
||||
is RoomListQuickActions.Settings,
|
||||
is RoomListQuickActions.Leave -> false
|
||||
}
|
||||
return bottomSheetItemAction {
|
||||
id("action_$index")
|
||||
selected(selected)
|
||||
iconRes(iconResId)
|
||||
textRes(titleRes)
|
||||
destructive(this@toBottomSheetItem.destructive)
|
||||
listener(View.OnClickListener { listener?.didSelectMenuAction(this@toBottomSheetItem) })
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun didSelectMenuAction(quickActions: RoomListQuickActions)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.home.room.list.actions
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
|
||||
data class RoomListQuickActionsState(
|
||||
val roomId: String,
|
||||
val roomSummary: Async<RoomSummary> = Uninitialized,
|
||||
val roomNotificationState: Async<RoomNotificationState> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: RoomListActionsArgs) : this(roomId = args.roomId)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package im.vector.riotx.features.home.room.list.actions
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import im.vector.riotx.core.utils.MutableDataSource
|
||||
|
||||
/**
|
||||
* Activity shared view model to handle room list quick actions
|
||||
*/
|
||||
class RoomListQuickActionsStore constructor(
|
||||
private val store: MutableDataSource<RoomListQuickActions> = PublishDataSource()
|
||||
) : ViewModel(), MutableDataSource<RoomListQuickActions> by store
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.riotx.features.home.room.list.actions
|
||||
|
||||
import com.airbnb.mvrx.*
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.matrix.rx.unwrap
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
|
||||
class RoomListQuickActionsViewModel @AssistedInject constructor(@Assisted initialState: RoomListQuickActionsState,
|
||||
session: Session
|
||||
) : VectorViewModel<RoomListQuickActionsState>(initialState) {
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(initialState: RoomListQuickActionsState): RoomListQuickActionsViewModel
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<RoomListQuickActionsViewModel, RoomListQuickActionsState> {
|
||||
|
||||
override fun create(viewModelContext: ViewModelContext, state: RoomListQuickActionsState): RoomListQuickActionsViewModel? {
|
||||
val fragment: RoomListQuickActionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
|
||||
return fragment.roomListActionsViewModelFactory.create(state)
|
||||
}
|
||||
}
|
||||
|
||||
private val room = session.getRoom(initialState.roomId)!!
|
||||
|
||||
init {
|
||||
observeRoomSummary()
|
||||
observeNotificationState()
|
||||
}
|
||||
|
||||
private fun observeNotificationState() {
|
||||
room
|
||||
.rx()
|
||||
.liveNotificationState()
|
||||
.execute {
|
||||
copy(roomNotificationState = it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummary() {
|
||||
room
|
||||
.rx()
|
||||
.liveRoomSummary()
|
||||
.unwrap()
|
||||
.execute {
|
||||
copy(roomSummary = it)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -112,4 +112,8 @@ class DefaultNavigator @Inject constructor() : Navigator {
|
|||
override fun openUserDetail(userId: String, context: Context) {
|
||||
Timber.v("Open user detail $userId")
|
||||
}
|
||||
|
||||
override fun openRoomSettings(context: Context, roomId: String) {
|
||||
Timber.v("Open room settings$roomId")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,4 +50,6 @@ interface Navigator {
|
|||
fun openGroupDetail(groupId: String, context: Context)
|
||||
|
||||
fun openUserDetail(userId: String, context: Context)
|
||||
|
||||
fun openRoomSettings(context: Context, roomId: String)
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ class PublicRoomsFragment @Inject constructor(
|
|||
.disposeOnDestroy()
|
||||
|
||||
publicRoomsCreateNewRoom.setOnClickListener {
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.CreateRoom)
|
||||
navigationViewModel.post(RoomDirectoryActivity.Navigation.CreateRoom)
|
||||
}
|
||||
|
||||
viewModel.joinRoomErrorLiveData.observeEvent(this) { throwable ->
|
||||
|
@ -83,7 +83,7 @@ class PublicRoomsFragment @Inject constructor(
|
|||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.menu_room_directory_change_protocol -> {
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.ChangeProtocol)
|
||||
navigationViewModel.post(RoomDirectoryActivity.Navigation.ChangeProtocol)
|
||||
true
|
||||
}
|
||||
else ->
|
||||
|
|
|
@ -25,7 +25,6 @@ import im.vector.riotx.R
|
|||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.extensions.addFragment
|
||||
import im.vector.riotx.core.extensions.addFragmentToBackstack
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomFragment
|
||||
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomViewModel
|
||||
|
@ -62,14 +61,16 @@ class RoomDirectoryActivity : VectorBaseActivity() {
|
|||
roomDirectoryViewModel.filterWith(intent?.getStringExtra(INITIAL_FILTER) ?: "")
|
||||
}
|
||||
|
||||
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
|
||||
when (navigation) {
|
||||
is Navigation.Back -> onBackPressed()
|
||||
is Navigation.CreateRoom -> addFragmentToBackstack(R.id.simpleFragmentContainer, CreateRoomFragment::class.java)
|
||||
is Navigation.ChangeProtocol -> addFragmentToBackstack(R.id.simpleFragmentContainer, RoomDirectoryPickerFragment::class.java)
|
||||
is Navigation.Close -> finish()
|
||||
}
|
||||
}
|
||||
navigationViewModel.observe()
|
||||
.subscribe { navigation ->
|
||||
when (navigation) {
|
||||
is Navigation.Back -> onBackPressed()
|
||||
is Navigation.CreateRoom -> addFragmentToBackstack(R.id.simpleFragmentContainer, CreateRoomFragment::class.java)
|
||||
is Navigation.ChangeProtocol -> addFragmentToBackstack(R.id.simpleFragmentContainer, RoomDirectoryPickerFragment::class.java)
|
||||
is Navigation.Close -> finish()
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
|
||||
roomDirectoryViewModel.selectSubscribe(this, PublicRoomsViewState::currentFilter) { currentFilter ->
|
||||
// Transmit the filter to the createRoomViewModel
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package im.vector.riotx.features.roomdirectory
|
||||
|
||||
import im.vector.riotx.core.mvrx.NavigationViewModel
|
||||
import javax.inject.Inject
|
||||
import androidx.lifecycle.ViewModel
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import im.vector.riotx.core.utils.MutableDataSource
|
||||
|
||||
class RoomDirectoryNavigationViewModel @Inject constructor(): NavigationViewModel<RoomDirectoryActivity.Navigation>()
|
||||
class RoomDirectoryNavigationViewModel(private val source: MutableDataSource<RoomDirectoryActivity.Navigation> = PublishDataSource())
|
||||
: ViewModel(), MutableDataSource<RoomDirectoryActivity.Navigation> by source
|
||||
|
|
|
@ -24,7 +24,6 @@ import androidx.lifecycle.ViewModelProviders
|
|||
import com.airbnb.mvrx.viewModel
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.addFragment
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
|
||||
|
@ -57,12 +56,14 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(RoomDirectoryNavigationViewModel::class.java)
|
||||
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
|
||||
when (navigation) {
|
||||
is RoomDirectoryActivity.Navigation.Back,
|
||||
is RoomDirectoryActivity.Navigation.Close -> finish()
|
||||
}
|
||||
}
|
||||
navigationViewModel.observe()
|
||||
.subscribe { navigation ->
|
||||
when (navigation) {
|
||||
is RoomDirectoryActivity.Navigation.Back,
|
||||
is RoomDirectoryActivity.Navigation.Close -> finish()
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -46,7 +46,7 @@ class CreateRoomFragment @Inject constructor(private val createRoomController: C
|
|||
navigationViewModel = ViewModelProviders.of(requireActivity()).get(RoomDirectoryNavigationViewModel::class.java)
|
||||
setupRecyclerView()
|
||||
createRoomClose.setOnClickListener {
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Back)
|
||||
navigationViewModel.post(RoomDirectoryActivity.Navigation.Back)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ class CreateRoomFragment @Inject constructor(private val createRoomController: C
|
|||
// Navigate to freshly created room
|
||||
navigator.openRoom(requireActivity(), async())
|
||||
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Close)
|
||||
navigationViewModel.post(RoomDirectoryActivity.Navigation.Close)
|
||||
} else {
|
||||
// Populate list with Epoxy
|
||||
createRoomController.setData(state)
|
||||
|
|
|
@ -88,7 +88,7 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
|
|||
Timber.v("onRoomDirectoryClicked: $roomDirectoryData")
|
||||
viewModel.setRoomDirectoryData(roomDirectoryData)
|
||||
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Back)
|
||||
navigationViewModel.post(RoomDirectoryActivity.Navigation.Back)
|
||||
}
|
||||
|
||||
override fun retry() {
|
||||
|
|
|
@ -23,7 +23,7 @@ import com.airbnb.mvrx.ViewModelContext
|
|||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.ActiveSessionObservableStore
|
||||
import im.vector.riotx.ActiveSessionDataSource
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
|
@ -35,8 +35,8 @@ data class IncomingShareState(private val dummy: Boolean = false) : MvRxState
|
|||
* View model used to observe the room list and post update to the ShareRoomListObservableStore
|
||||
*/
|
||||
class IncomingShareViewModel @AssistedInject constructor(@Assisted initialState: IncomingShareState,
|
||||
private val sessionObservableStore: ActiveSessionObservableStore,
|
||||
private val shareRoomListObservableStore: ShareRoomListObservableStore)
|
||||
private val sessionObservableStore: ActiveSessionDataSource,
|
||||
private val shareRoomListObservableStore: ShareRoomListDataSource)
|
||||
: VectorViewModel<IncomingShareState>(initialState) {
|
||||
|
||||
@AssistedInject.Factory
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
package im.vector.riotx.features.share
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotx.core.utils.RxStore
|
||||
import im.vector.riotx.core.utils.BehaviorDataSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ShareRoomListObservableStore @Inject constructor() : RxStore<List<RoomSummary>>()
|
||||
class ShareRoomListDataSource @Inject constructor() : BehaviorDataSource<List<RoomSummary>>()
|
4
vector/src/main/res/drawable/ic_check_white_24dp.xml
Normal file
4
vector/src/main/res/drawable/ic_check_white_24dp.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||
</vector>
|
47
vector/src/main/res/drawable/ic_room_actions_leave.xml
Normal file
47
vector/src/main/res/drawable/ic_room_actions_leave.xml
Normal file
|
@ -0,0 +1,47 @@
|
|||
<!--
|
||||
~ Copyright 2019 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<path
|
||||
android:pathData="M11,11m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M14,8L8,14"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M8,8L14,14"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,39 @@
|
|||
<!--
|
||||
~ Copyright 2019 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="17dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="17"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M10,1l-5,4l-4,0l0,6l4,0l5,4z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M14.54,4.46C16.4919,6.4125 16.4919,9.5775 14.54,11.53"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,39 @@
|
|||
<!--
|
||||
~ Copyright 2019 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:pathData="M10,2l-5,4l-4,0l0,6l4,0l5,4z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M18.07,1.93C21.9738,5.835 21.9738,12.165 18.07,16.07M14.54,5.46C16.4919,7.4125 16.4919,10.5775 14.54,12.53"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,47 @@
|
|||
<!--
|
||||
~ Copyright 2019 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M10,1l-5,4l-4,0l0,6l4,0l5,4z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M18.8097,7.8097m-1.5238,0a1.5238,1.5238 0,1 1,3.0476 0a1.5238,1.5238 0,1 1,-3.0476 0"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.3"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M20.3336,6.2858L20.3336,8.1906C20.3336,8.8218 20.8452,9.3335 21.4764,9.3335C22.1076,9.3335 22.6193,8.8218 22.6193,8.1906L22.6193,7.8097C22.6192,6.0393 21.3995,4.5024 19.6755,4.1001C17.9515,3.6977 16.1776,4.5361 15.3938,6.1235C14.6101,7.7109 15.0233,9.629 16.3909,10.753C17.7586,11.877 19.7204,11.9108 21.1259,10.8344"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.3"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,47 @@
|
|||
<!--
|
||||
~ Copyright 2019 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="23dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="23"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M10,1l-5,4l-4,0l0,6l4,0l5,4z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M22,5L16,11"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M16,5L22,11"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
39
vector/src/main/res/drawable/ic_room_actions_settings.xml
Normal file
39
vector/src/main/res/drawable/ic_room_actions_settings.xml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<!--
|
||||
~ Copyright 2019 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M19.4,15C19.1277,15.6171 19.2583,16.3378 19.73,16.82L19.79,16.88C20.1656,17.2551 20.3766,17.7642 20.3766,18.295C20.3766,18.8258 20.1656,19.3349 19.79,19.71C19.4149,20.0856 18.9058,20.2966 18.375,20.2966C17.8442,20.2966 17.3351,20.0856 16.96,19.71L16.9,19.65C16.4178,19.1783 15.6971,19.0477 15.08,19.32C14.4755,19.5791 14.0826,20.1724 14.08,20.83L14.08,21C14.08,22.1046 13.1846,23 12.08,23C10.9754,23 10.08,22.1046 10.08,21L10.08,20.91C10.0642,20.2327 9.6359,19.6339 9,19.4C8.3829,19.1277 7.6622,19.2583 7.18,19.73L7.12,19.79C6.7449,20.1656 6.2358,20.3766 5.705,20.3766C5.1742,20.3766 4.6651,20.1656 4.29,19.79C3.9144,19.4149 3.7034,18.9058 3.7034,18.375C3.7034,17.8442 3.9144,17.3351 4.29,16.96L4.35,16.9C4.8217,16.4178 4.9523,15.6971 4.68,15.08C4.4209,14.4755 3.8276,14.0826 3.17,14.08L3,14.08C1.8954,14.08 1,13.1846 1,12.08C1,10.9754 1.8954,10.08 3,10.08L3.09,10.08C3.7673,10.0642 4.3661,9.6359 4.6,9C4.8723,8.3829 4.7417,7.6622 4.27,7.18L4.21,7.12C3.8344,6.7449 3.6234,6.2358 3.6234,5.705C3.6234,5.1742 3.8344,4.6651 4.21,4.29C4.5851,3.9144 5.0942,3.7034 5.625,3.7034C6.1558,3.7034 6.6649,3.9144 7.04,4.29L7.1,4.35C7.5822,4.8217 8.3029,4.9523 8.92,4.68L9,4.68C9.6045,4.4209 9.9974,3.8276 10,3.17L10,3C10,1.8954 10.8954,1 12,1C13.1046,1 14,1.8954 14,3L14,3.09C14.0026,3.7476 14.3955,4.3409 15,4.6C15.6171,4.8723 16.3378,4.7417 16.82,4.27L16.88,4.21C17.2551,3.8344 17.7642,3.6234 18.295,3.6234C18.8258,3.6234 19.3349,3.8344 19.71,4.21C20.0856,4.5851 20.2966,5.0942 20.2966,5.625C20.2966,6.1558 20.0856,6.6649 19.71,7.04L19.65,7.1C19.1783,7.5822 19.0477,8.3029 19.32,8.92L19.32,9C19.5791,9.6045 20.1724,9.9974 20.83,10L21,10C22.1046,10 23,10.8954 23,12C23,13.1046 22.1046,14 21,14L20.91,14C20.2524,14.0026 19.6591,14.3955 19.4,15Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9E9E9E"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -1,52 +1,72 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="50dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="@dimen/layout_horizontal_margin"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="@dimen/layout_horizontal_margin"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<Space
|
||||
android:id="@+id/action_start_space"
|
||||
android:id="@+id/actionStartSpace"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/action_icon"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:id="@+id/actionIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/actionStartSpace"
|
||||
android:scaleType="center"
|
||||
android:tint="?riotx_text_secondary"
|
||||
tools:src="@drawable/ic_delete" />
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/actionStartSpace"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_room_actions_notifications_all" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/action_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/actionTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:drawablePadding="16dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="17sp"
|
||||
tools:text="@string/delete" />
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/actionSelected"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@id/actionStartSpace"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_default="wrap"
|
||||
tools:text="zbla azjazjaz s sdkqdskdsqk kqsdkdqsk kdqsksqdk" />
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/action_expand"
|
||||
android:id="@+id/actionSelected"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tint="?riotx_text_secondary"
|
||||
android:src="@drawable/ic_check_white_24dp"
|
||||
android:tint="@color/riotx_accent"
|
||||
android:visibility="gone"
|
||||
tools:src="@drawable/ic_material_expand_more_black"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/bottom_sheet_message_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/bottomSheetRoomPreviewAvatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="@drawable/circle"
|
||||
android:importantForAccessibility="no"
|
||||
android:contentDescription="@string/avatar"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottomSheetRoomPreviewName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="sans-serif-bold"
|
||||
android:singleLine="true"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/bottomSheetRoomPreviewAvatar"
|
||||
app:layout_constraintEnd_toStartOf="@+id/bottomSheetRoomPreviewSettings"
|
||||
app:layout_constraintStart_toEndOf="@id/bottomSheetRoomPreviewAvatar"
|
||||
app:layout_constraintTop_toTopOf="@id/bottomSheetRoomPreviewAvatar"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/bottomSheetRoomPreviewSettings"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_room_actions_settings"
|
||||
android:contentDescription="@string/room_list_quick_actions_settings"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/bottomSheetRoomPreviewAvatar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/bottomSheetRoomPreviewAvatar" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -2,6 +2,12 @@
|
|||
<resources>
|
||||
|
||||
<!-- Strings not defined in Riot -->
|
||||
<string name="room_list_quick_actions_notifications_all_noisy">"All messages (noisy)"</string>
|
||||
<string name="room_list_quick_actions_notifications_all">"All messages"</string>
|
||||
<string name="room_list_quick_actions_notifications_mentions">"Mentions only"</string>
|
||||
<string name="room_list_quick_actions_notifications_mute">"Mute"</string>
|
||||
<string name="room_list_quick_actions_settings">"Settings"</string>
|
||||
<string name="room_list_quick_actions_leave">"Leave the room"</string>
|
||||
<string name="notice_member_no_changes">"%1$s made no changes"</string>
|
||||
|
||||
<string name="no_ignored_users">You are not ignoring any users</string>
|
||||
|
|
Loading…
Reference in a new issue