From 9aadbbc3c76b1867bd8c905485c44d374da50b10 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 14:27:24 +0100 Subject: [PATCH 01/28] Rework DefaultConditionResolver, and create RoomGetter --- .../matrix/android/api/pushrules/Condition.kt | 5 +- .../api/pushrules/ConditionResolver.kt | 16 +++- .../pushrules/ContainsDisplayNameCondition.kt | 4 +- .../api/pushrules/EventMatchCondition.kt | 4 +- .../api/pushrules/RoomMemberCountCondition.kt | 12 +-- .../SenderNotificationPermissionCondition.kt | 4 +- .../pushrules/rest/GetPushRulesResponse.kt | 2 +- .../api/pushrules/rest/PushCondition.kt | 10 ++- .../android/api/pushrules/rest/Ruleset.kt | 2 +- .../notification/DefaultPushRuleService.kt | 13 ++-- .../notification/ProcessEventForPushTask.kt | 9 +-- .../pushers/DefaultConditionResolver.kt | 37 ++++++---- .../session/room/DefaultRoomService.kt | 49 ++++--------- .../internal/session/room/RoomGetter.kt | 73 +++++++++++++++++++ .../internal/session/room/RoomModule.kt | 15 +++- 15 files changed, 169 insertions(+), 86 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt index ecc78996db..0cfb92ed7b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt @@ -15,8 +15,11 @@ */ package im.vector.matrix.android.api.pushrules +import im.vector.matrix.android.api.session.events.model.Event + abstract class Condition(val kind: Kind) { + // Use @Json? enum class Kind(val value: String) { event_match("event_match"), contains_display_name("contains_display_name"), @@ -38,7 +41,7 @@ abstract class Condition(val kind: Kind) { } } - abstract fun isSatisfied(conditionResolver: ConditionResolver): Boolean + abstract fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean open fun technicalDescription(): String { return "Kind: $kind" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ConditionResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ConditionResolver.kt index 340810bc80..95f89ec2c7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ConditionResolver.kt @@ -15,14 +15,22 @@ */ package im.vector.matrix.android.api.pushrules +import im.vector.matrix.android.api.session.events.model.Event + /** * Acts like a visitor on Conditions. * This class as all required context needed to evaluate rules */ interface ConditionResolver { + fun resolveEventMatchCondition(event: Event, + condition: EventMatchCondition): Boolean - fun resolveEventMatchCondition(eventMatchCondition: EventMatchCondition): Boolean - fun resolveRoomMemberCountCondition(roomMemberCountCondition: RoomMemberCountCondition): Boolean - fun resolveSenderNotificationPermissionCondition(senderNotificationPermissionCondition: SenderNotificationPermissionCondition): Boolean - fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition) : Boolean + fun resolveRoomMemberCountCondition(event: Event, + condition: RoomMemberCountCondition): Boolean + + fun resolveSenderNotificationPermissionCondition(event: Event, + condition: SenderNotificationPermissionCondition): Boolean + + fun resolveContainsDisplayNameCondition(event: Event, + condition: ContainsDisplayNameCondition): Boolean } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt index 166ec4f05f..e34dd070ab 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt @@ -23,8 +23,8 @@ import timber.log.Timber class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) { - override fun isSatisfied(conditionResolver: ConditionResolver): Boolean { - return conditionResolver.resolveContainsDisplayNameCondition(this) + override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { + return conditionResolver.resolveContainsDisplayNameCondition(event, this) } override fun technicalDescription(): String { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt index a4eacc9018..d72c065e9e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt @@ -21,8 +21,8 @@ import timber.log.Timber class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind.event_match) { - override fun isSatisfied(conditionResolver: ConditionResolver) : Boolean { - return conditionResolver.resolveEventMatchCondition(this) + override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { + return conditionResolver.resolveEventMatchCondition(event, this) } override fun technicalDescription(): String { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt index 34bdbffefe..9f773a4e15 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt @@ -16,25 +16,25 @@ package im.vector.matrix.android.api.pushrules import im.vector.matrix.android.api.session.events.model.Event -import im.vector.matrix.android.api.session.room.RoomService +import im.vector.matrix.android.internal.session.room.RoomGetter import timber.log.Timber private val regex = Regex("^(==|<=|>=|<|>)?(\\d*)$") class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_count) { - override fun isSatisfied(conditionResolver: ConditionResolver): Boolean { - return conditionResolver.resolveRoomMemberCountCondition(this) + override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { + return conditionResolver.resolveRoomMemberCountCondition(event, this) } override fun technicalDescription(): String { return "Room member count is $iz" } - fun isSatisfied(event: Event, session: RoomService?): Boolean { - // sanity check^ + internal fun isSatisfied(event: Event, roomGetter: RoomGetter): Boolean { + // sanity checks val roomId = event.roomId ?: return false - val room = session?.getRoom(roomId) ?: return false + val room = roomGetter.getRoom(roomId) ?: return false // Parse the is field into prefix and number the first time val (prefix, count) = parseIsField() ?: return false diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt index e0d4034082..1ab66c556c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt @@ -21,8 +21,8 @@ import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper class SenderNotificationPermissionCondition(val key: String) : Condition(Kind.sender_notification_permission) { - override fun isSatisfied(conditionResolver: ConditionResolver): Boolean { - return conditionResolver.resolveSenderNotificationPermissionCondition(this) + override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { + return conditionResolver.resolveSenderNotificationPermissionCondition(event, this) } override fun technicalDescription(): String { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/GetPushRulesResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/GetPushRulesResponse.kt index 8d567f9464..c5f03aed41 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/GetPushRulesResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/GetPushRulesResponse.kt @@ -22,7 +22,7 @@ import com.squareup.moshi.JsonClass * All push rulesets for a user. */ @JsonClass(generateAdapter = true) -data class GetPushRulesResponse( +internal data class GetPushRulesResponse( /** * Global rules, account level applying to all devices */ diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt index 4b643a0b42..cbfd049fa0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt @@ -17,7 +17,11 @@ package im.vector.matrix.android.api.pushrules.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import im.vector.matrix.android.api.pushrules.* +import im.vector.matrix.android.api.pushrules.Condition +import im.vector.matrix.android.api.pushrules.ContainsDisplayNameCondition +import im.vector.matrix.android.api.pushrules.EventMatchCondition +import im.vector.matrix.android.api.pushrules.RoomMemberCountCondition +import im.vector.matrix.android.api.pushrules.SenderNotificationPermissionCondition import timber.log.Timber @JsonClass(generateAdapter = true) @@ -30,13 +34,13 @@ data class PushCondition( /** * Required for event_match conditions. The dot- separated field of the event to match. */ - val key: String? = null, + /** *Required for event_match conditions. */ - val pattern: String? = null, + /** * Required for room_member_count conditions. * A decimal integer optionally prefixed by one of, ==, <, >, >= or <=. diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt index 72692d5afd..a7093731b5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt @@ -18,7 +18,7 @@ package im.vector.matrix.android.api.pushrules.rest import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class Ruleset( +internal data class Ruleset( val content: List? = null, val override: List? = null, val room: List? = null, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt index 9121202649..7e8dc1eb30 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt @@ -38,12 +38,13 @@ import timber.log.Timber 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 +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 { private var listeners = mutableSetOf() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/ProcessEventForPushTask.kt index 6e47bdfeaa..9774f04625 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/ProcessEventForPushTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/ProcessEventForPushTask.kt @@ -16,12 +16,11 @@ package im.vector.matrix.android.internal.session.notification +import im.vector.matrix.android.api.pushrules.ConditionResolver import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType -import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.internal.di.UserId -import im.vector.matrix.android.internal.session.pushers.DefaultConditionResolver import im.vector.matrix.android.internal.session.sync.model.RoomsSyncResponse import im.vector.matrix.android.internal.task.Task import timber.log.Timber @@ -36,7 +35,7 @@ internal interface ProcessEventForPushTask : Task): PushRule? { - // TODO This should be injected - val conditionResolver = DefaultConditionResolver(event, roomService, userId) return rules.firstOrNull { rule -> // All conditions must hold true for an event in order to apply the action for the event. rule.enabled && rule.conditions?.all { - it.asExecutableCondition()?.isSatisfied(conditionResolver) ?: false + it.asExecutableCondition()?.isSatisfied(event, conditionResolver) ?: false } ?: false } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt index 881d122606..c8edd7ab96 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt @@ -15,26 +15,34 @@ */ package im.vector.matrix.android.internal.session.pushers -import im.vector.matrix.android.api.pushrules.* +import im.vector.matrix.android.api.pushrules.ConditionResolver +import im.vector.matrix.android.api.pushrules.ContainsDisplayNameCondition +import im.vector.matrix.android.api.pushrules.EventMatchCondition +import im.vector.matrix.android.api.pushrules.RoomMemberCountCondition +import im.vector.matrix.android.api.pushrules.SenderNotificationPermissionCondition import im.vector.matrix.android.api.session.events.model.Event -import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.internal.di.UserId +import im.vector.matrix.android.internal.session.room.RoomGetter import timber.log.Timber +import javax.inject.Inject -// TODO Inject constructor -internal class DefaultConditionResolver(private val event: Event, - private val roomService: RoomService, - @UserId private val userId: String) : ConditionResolver { +internal class DefaultConditionResolver @Inject constructor( + private val roomGetter: RoomGetter, + @UserId private val userId: String +) : ConditionResolver { - override fun resolveEventMatchCondition(eventMatchCondition: EventMatchCondition): Boolean { - return eventMatchCondition.isSatisfied(event) + override fun resolveEventMatchCondition(event: Event, + condition: EventMatchCondition): Boolean { + return condition.isSatisfied(event) } - override fun resolveRoomMemberCountCondition(roomMemberCountCondition: RoomMemberCountCondition): Boolean { - return roomMemberCountCondition.isSatisfied(event, roomService) + override fun resolveRoomMemberCountCondition(event: Event, + condition: RoomMemberCountCondition): Boolean { + return condition.isSatisfied(event, roomGetter) } - override fun resolveSenderNotificationPermissionCondition(senderNotificationPermissionCondition: SenderNotificationPermissionCondition): Boolean { + override fun resolveSenderNotificationPermissionCondition(event: Event, + condition: SenderNotificationPermissionCondition): Boolean { // val roomId = event.roomId ?: return false // val room = roomService.getRoom(roomId) ?: return false // TODO RoomState not yet managed @@ -42,10 +50,11 @@ internal class DefaultConditionResolver(private val event: Event, return false // senderNotificationPermissionCondition.isSatisfied(event, ) } - override fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition): Boolean { + override fun resolveContainsDisplayNameCondition(event: Event, + condition: ContainsDisplayNameCondition): Boolean { val roomId = event.roomId ?: return false - val room = roomService.getRoom(roomId) ?: return false + val room = roomGetter.getRoom(roomId) ?: return false val myDisplayName = room.getRoomMember(userId)?.displayName ?: return false - return containsDisplayNameCondition.isSatisfied(event, myDisplayName) + return condition.isSatisfied(event, myDisplayName) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt index 409c844f0c..e049c1869d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt @@ -22,14 +22,12 @@ import im.vector.matrix.android.api.MatrixCallback 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.RoomSummaryQueryParams -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.VersioningState import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper -import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields import im.vector.matrix.android.internal.database.query.findByAlias @@ -37,7 +35,6 @@ import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.query.process import im.vector.matrix.android.internal.session.room.alias.GetRoomIdByAliasTask import im.vector.matrix.android.internal.session.room.create.CreateRoomTask -import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask import im.vector.matrix.android.internal.session.user.accountdata.UpdateBreadcrumbsTask @@ -48,15 +45,17 @@ import io.realm.Realm import io.realm.RealmQuery import javax.inject.Inject -internal class DefaultRoomService @Inject constructor(private val monarchy: Monarchy, - private val roomSummaryMapper: RoomSummaryMapper, - private val createRoomTask: CreateRoomTask, - private val joinRoomTask: JoinRoomTask, - private val markAllRoomsReadTask: MarkAllRoomsReadTask, - private val updateBreadcrumbsTask: UpdateBreadcrumbsTask, - private val roomIdByAliasTask: GetRoomIdByAliasTask, - private val roomFactory: RoomFactory, - private val taskExecutor: TaskExecutor) : RoomService { +internal class DefaultRoomService @Inject constructor( + private val monarchy: Monarchy, + private val roomSummaryMapper: RoomSummaryMapper, + private val createRoomTask: CreateRoomTask, + private val joinRoomTask: JoinRoomTask, + private val markAllRoomsReadTask: MarkAllRoomsReadTask, + private val updateBreadcrumbsTask: UpdateBreadcrumbsTask, + private val roomIdByAliasTask: GetRoomIdByAliasTask, + private val roomGetter: RoomGetter, + private val taskExecutor: TaskExecutor +) : RoomService { override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback): Cancelable { return createRoomTask @@ -67,33 +66,11 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona } override fun getRoom(roomId: String): Room? { - return Realm.getInstance(monarchy.realmConfiguration).use { - if (RoomEntity.where(it, roomId).findFirst() != null) { - roomFactory.create(roomId) - } else { - null - } - } + return roomGetter.getRoom(roomId) } override fun getExistingDirectRoomWithUser(otherUserId: String): Room? { - Realm.getInstance(monarchy.realmConfiguration).use { realm -> - val candidates = RoomSummaryEntity.where(realm) - .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) - .findAll()?.filter { dm -> - dm.otherMemberIds.contains(otherUserId) - && dm.membership == Membership.JOIN - }?.map { - it.roomId - } - ?: return null - candidates.forEach { roomId -> - if (RoomMemberHelper(realm, roomId).getActiveRoomMemberIds().any { it == otherUserId }) { - return RoomEntity.where(realm, roomId).findFirst()?.let { roomFactory.create(roomId) } - } - } - return null - } + return roomGetter.getDirectRoomWith(otherUserId) } override fun getRoomSummary(roomIdOrAlias: String): RoomSummary? { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt new file mode 100644 index 0000000000..6b59b0b117 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020 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 + +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.room.Room +import im.vector.matrix.android.api.session.room.model.Membership +import im.vector.matrix.android.internal.database.model.RoomEntity +import im.vector.matrix.android.internal.database.model.RoomSummaryEntity +import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields +import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.session.SessionScope +import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper +import io.realm.Realm +import javax.inject.Inject + +internal interface RoomGetter { + fun getRoom(roomId: String): Room? + + fun getDirectRoomWith(otherUserId: String): Room? +} + +@SessionScope +internal class DefaultRoomGetter @Inject constructor( + private val monarchy: Monarchy, + private val roomFactory: RoomFactory +) : RoomGetter { + + override fun getRoom(roomId: String): Room? { + return Realm.getInstance(monarchy.realmConfiguration).use { + if (RoomEntity.where(it, roomId).findFirst() != null) { + roomFactory.create(roomId) + } else { + null + } + } + } + + override fun getDirectRoomWith(otherUserId: String): Room? { + Realm.getInstance(monarchy.realmConfiguration).use { realm -> + val candidates = RoomSummaryEntity.where(realm) + .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) + .findAll()?.filter { dm -> + dm.otherMemberIds.contains(otherUserId) + && dm.membership == Membership.JOIN + }?.map { + it.roomId + } + ?: return null + candidates.forEach { roomId -> + if (RoomMemberHelper(realm, roomId).getActiveRoomMemberIds().any { it == otherUserId }) { + return RoomEntity.where(realm, roomId).findFirst()?.let { roomFactory.create(roomId) } + } + } + return null + } + } +} + diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt index c4bba4cbf6..6b003b5ba2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt @@ -46,12 +46,20 @@ import im.vector.matrix.android.internal.session.room.read.DefaultMarkAllRoomsRe import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask -import im.vector.matrix.android.internal.session.room.relation.* +import im.vector.matrix.android.internal.session.room.relation.DefaultFetchEditHistoryTask +import im.vector.matrix.android.internal.session.room.relation.DefaultFindReactionEventForUndoTask +import im.vector.matrix.android.internal.session.room.relation.DefaultUpdateQuickReactionTask +import im.vector.matrix.android.internal.session.room.relation.FetchEditHistoryTask +import im.vector.matrix.android.internal.session.room.relation.FindReactionEventForUndoTask +import im.vector.matrix.android.internal.session.room.relation.UpdateQuickReactionTask import im.vector.matrix.android.internal.session.room.reporting.DefaultReportContentTask import im.vector.matrix.android.internal.session.room.reporting.ReportContentTask import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask import im.vector.matrix.android.internal.session.room.state.SendStateTask -import im.vector.matrix.android.internal.session.room.timeline.* +import im.vector.matrix.android.internal.session.room.timeline.DefaultGetContextOfEventTask +import im.vector.matrix.android.internal.session.room.timeline.DefaultPaginationTask +import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask +import im.vector.matrix.android.internal.session.room.timeline.PaginationTask import im.vector.matrix.android.internal.session.room.typing.DefaultSendTypingTask import im.vector.matrix.android.internal.session.room.typing.SendTypingTask import retrofit2.Retrofit @@ -72,6 +80,9 @@ internal abstract class RoomModule { @Binds abstract fun bindRoomFactory(factory: DefaultRoomFactory): RoomFactory + @Binds + abstract fun bindRoomGetter(getter: DefaultRoomGetter): RoomGetter + @Binds abstract fun bindRoomService(service: DefaultRoomService): RoomService From 34c5f37bbc8610420265908df7568ba95b332b7f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 14:30:44 +0100 Subject: [PATCH 02/28] findAll() does not return null value --- .../internal/crypto/crosssigning/ShieldTrustUpdater.kt | 8 +++++--- .../matrix/android/internal/session/room/RoomGetter.kt | 8 +++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/ShieldTrustUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/ShieldTrustUpdater.kt index a49ea77da7..5bc6e2df0f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/ShieldTrustUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/ShieldTrustUpdater.kt @@ -110,9 +110,11 @@ internal class ShieldTrustUpdater @Inject constructor( val map = HashMap>() impactedRoomsId.forEach { roomId -> - RoomMemberSummaryEntity.where(backgroundSessionRealm.get(), roomId).findAll()?.let { results -> - map[roomId] = results.map { it.userId } - } + RoomMemberSummaryEntity.where(backgroundSessionRealm.get(), roomId) + .findAll() + .let { results -> + map[roomId] = results.map { it.userId } + } } map.forEach { entry -> diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt index 6b59b0b117..34f831b12d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt @@ -54,13 +54,11 @@ internal class DefaultRoomGetter @Inject constructor( Realm.getInstance(monarchy.realmConfiguration).use { realm -> val candidates = RoomSummaryEntity.where(realm) .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) - .findAll()?.filter { dm -> + .findAll() + .filter { dm -> dm.otherMemberIds.contains(otherUserId) && dm.membership == Membership.JOIN - }?.map { - it.roomId - } - ?: return null + }.map { it.roomId } candidates.forEach { roomId -> if (RoomMemberHelper(realm, roomId).getActiveRoomMemberIds().any { it == otherUserId }) { return RoomEntity.where(realm, roomId).findFirst()?.let { roomFactory.create(roomId) } From 31e5c0eb1a5183eabf37540da3eb424f63cbd2db Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 14:48:08 +0100 Subject: [PATCH 03/28] Improve algorithm --- .../internal/session/room/RoomGetter.kt | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt index 34f831b12d..4595da1752 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomGetter.kt @@ -41,31 +41,26 @@ internal class DefaultRoomGetter @Inject constructor( ) : RoomGetter { override fun getRoom(roomId: String): Room? { - return Realm.getInstance(monarchy.realmConfiguration).use { - if (RoomEntity.where(it, roomId).findFirst() != null) { - roomFactory.create(roomId) - } else { - null - } + return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + createRoom(realm, roomId) } } override fun getDirectRoomWith(otherUserId: String): Room? { - Realm.getInstance(monarchy.realmConfiguration).use { realm -> - val candidates = RoomSummaryEntity.where(realm) + return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + RoomSummaryEntity.where(realm) .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) + .equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name) .findAll() - .filter { dm -> - dm.otherMemberIds.contains(otherUserId) - && dm.membership == Membership.JOIN - }.map { it.roomId } - candidates.forEach { roomId -> - if (RoomMemberHelper(realm, roomId).getActiveRoomMemberIds().any { it == otherUserId }) { - return RoomEntity.where(realm, roomId).findFirst()?.let { roomFactory.create(roomId) } - } - } - return null + .filter { dm -> dm.otherMemberIds.contains(otherUserId) } + .map { it.roomId } + .firstOrNull { roomId -> otherUserId in RoomMemberHelper(realm, roomId).getActiveRoomMemberIds() } + ?.let { roomId -> createRoom(realm, roomId) } } } -} + private fun createRoom(realm: Realm, roomId: String): Room? { + return RoomEntity.where(realm, roomId).findFirst() + ?.let { roomFactory.create(roomId) } + } +} From f719da96ed0ce408241cd4bc98bdc42aa0268208 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 15:02:39 +0100 Subject: [PATCH 04/28] Rename Condition.Kind enum values and add some documentation --- .../matrix/android/api/pushrules/Condition.kt | 21 +++++++-------- .../pushrules/ContainsDisplayNameCondition.kt | 2 +- .../api/pushrules/EventMatchCondition.kt | 12 ++++++++- .../api/pushrules/RoomMemberCountCondition.kt | 9 ++++++- .../SenderNotificationPermissionCondition.kt | 10 ++++++- .../api/pushrules/rest/PushCondition.kt | 27 +++++++++++-------- .../database/mapper/PushRulesMapper.kt | 6 ++--- .../room/notification/RoomPushRuleMapper.kt | 2 +- 8 files changed, 59 insertions(+), 30 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt index 0cfb92ed7b..a7b475518c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Condition.kt @@ -19,23 +19,22 @@ import im.vector.matrix.android.api.session.events.model.Event abstract class Condition(val kind: Kind) { - // Use @Json? enum class Kind(val value: String) { - event_match("event_match"), - contains_display_name("contains_display_name"), - room_member_count("room_member_count"), - sender_notification_permission("sender_notification_permission"), - UNRECOGNIZE(""); + EventMatch("event_match"), + ContainsDisplayName("contains_display_name"), + RoomMemberCount("room_member_count"), + SenderNotificationPermission("sender_notification_permission"), + Unrecognised(""); companion object { fun fromString(value: String): Kind { return when (value) { - "event_match" -> event_match - "contains_display_name" -> contains_display_name - "room_member_count" -> room_member_count - "sender_notification_permission" -> sender_notification_permission - else -> UNRECOGNIZE + "event_match" -> EventMatch + "contains_display_name" -> ContainsDisplayName + "room_member_count" -> RoomMemberCount + "sender_notification_permission" -> SenderNotificationPermission + else -> Unrecognised } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt index e34dd070ab..a2613d2859 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/ContainsDisplayNameCondition.kt @@ -21,7 +21,7 @@ import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.message.MessageContent import timber.log.Timber -class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) { +class ContainsDisplayNameCondition : Condition(Kind.ContainsDisplayName) { override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { return conditionResolver.resolveContainsDisplayNameCondition(event, this) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt index d72c065e9e..a6d7e48b9d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/EventMatchCondition.kt @@ -19,7 +19,17 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.internal.di.MoshiProvider import timber.log.Timber -class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind.event_match) { +class EventMatchCondition( + /** + * The dot-separated field of the event to match, e.g. content.body + */ + val key: String, + /** + * The glob-style pattern to match against. Patterns with no special glob characters should + * be treated as having asterisks prepended and appended when testing the condition. + */ + val pattern: String +) : Condition(Kind.EventMatch) { override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { return conditionResolver.resolveEventMatchCondition(event, this) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt index 9f773a4e15..5c7b79a5ba 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RoomMemberCountCondition.kt @@ -21,7 +21,14 @@ import timber.log.Timber private val regex = Regex("^(==|<=|>=|<|>)?(\\d*)$") -class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_count) { +class RoomMemberCountCondition( + /** + * A decimal integer optionally prefixed by one of ==, <, >, >= or <=. + * A prefix of < matches rooms where the member count is strictly less than the given number and so forth. + * If no prefix is present, this parameter defaults to ==. + */ + val iz: String +) : Condition(Kind.RoomMemberCount) { override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { return conditionResolver.resolveRoomMemberCountCondition(event, this) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt index 1ab66c556c..cc6fe3f6ef 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/SenderNotificationPermissionCondition.kt @@ -19,7 +19,15 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.model.PowerLevelsContent import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper -class SenderNotificationPermissionCondition(val key: String) : Condition(Kind.sender_notification_permission) { +class SenderNotificationPermissionCondition( + /** + * A string that determines the power level the sender must have to trigger notifications of a given type, + * such as room. Refer to the m.room.power_levels event schema for information about what the defaults are + * and how to interpret the event. The key is used to look up the power level required to send a notification + * type from the notifications object in the power level event content. + */ + val key: String +) : Condition(Kind.SenderNotificationPermission) { override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { return conditionResolver.resolveSenderNotificationPermissionCondition(event, this) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt index cbfd049fa0..cc19e6a7d1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt @@ -37,7 +37,7 @@ data class PushCondition( val key: String? = null, /** - *Required for event_match conditions. + * Required for event_match conditions. */ val pattern: String? = null, @@ -51,30 +51,35 @@ data class PushCondition( ) { fun asExecutableCondition(): Condition? { - return when (Condition.Kind.fromString(this.kind)) { - Condition.Kind.event_match -> { - if (this.key != null && this.pattern != null) { + return when (Condition.Kind.fromString(kind)) { + Condition.Kind.EventMatch -> { + if (key != null && pattern != null) { EventMatchCondition(key, pattern) } else { Timber.e("Malformed Event match condition") null } } - Condition.Kind.contains_display_name -> { + Condition.Kind.ContainsDisplayName -> { ContainsDisplayNameCondition() } - Condition.Kind.room_member_count -> { - if (this.iz.isNullOrBlank()) { + Condition.Kind.RoomMemberCount -> { + if (iz.isNullOrEmpty()) { Timber.e("Malformed ROOM_MEMBER_COUNT condition") null } else { - RoomMemberCountCondition(this.iz) + RoomMemberCountCondition(iz) } } - Condition.Kind.sender_notification_permission -> { - this.key?.let { SenderNotificationPermissionCondition(it) } + Condition.Kind.SenderNotificationPermission -> { + if (key == null) { + Timber.e("Malformed Sender Notification Permission condition") + null + } else { + SenderNotificationPermissionCondition(key) + } } - Condition.Kind.UNRECOGNIZE -> { + Condition.Kind.Unrecognised -> { Timber.e("Unknown kind $kind") null } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt index 8912928a88..26cde21842 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt @@ -38,7 +38,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.event_match.name, "content.body", pushrule.pattern) + PushCondition(Condition.Kind.EventMatch.name, "content.body", pushrule.pattern) ) ) } @@ -59,7 +59,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.event_match.name, "room_id", pushrule.ruleId) + PushCondition(Condition.Kind.EventMatch.name, "room_id", pushrule.ruleId) ) ) } @@ -71,7 +71,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.event_match.name, "user_id", pushrule.ruleId) + PushCondition(Condition.Kind.EventMatch.name, "user_id", pushrule.ruleId) ) ) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRuleMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRuleMapper.kt index d08d346a1f..770ce55cde 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRuleMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRuleMapper.kt @@ -54,7 +54,7 @@ internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? } else -> { val condition = PushCondition( - kind = Condition.Kind.event_match.value, + kind = Condition.Kind.EventMatch.value, key = "room_id", pattern = roomId ) From 2a534b587493c20216a794c4347649b86def5cdf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 15:32:20 +0100 Subject: [PATCH 05/28] Handle SenderNotificationPermissionCondition --- .../pushers/DefaultConditionResolver.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt index c8edd7ab96..f130cf5bc7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultConditionResolver.kt @@ -21,9 +21,11 @@ import im.vector.matrix.android.api.pushrules.EventMatchCondition import im.vector.matrix.android.api.pushrules.RoomMemberCountCondition import im.vector.matrix.android.api.pushrules.SenderNotificationPermissionCondition import im.vector.matrix.android.api.session.events.model.Event +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.PowerLevelsContent import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.room.RoomGetter -import timber.log.Timber import javax.inject.Inject internal class DefaultConditionResolver @Inject constructor( @@ -43,11 +45,15 @@ internal class DefaultConditionResolver @Inject constructor( override fun resolveSenderNotificationPermissionCondition(event: Event, condition: SenderNotificationPermissionCondition): Boolean { -// val roomId = event.roomId ?: return false -// val room = roomService.getRoom(roomId) ?: return false - // TODO RoomState not yet managed - Timber.e("POWER LEVELS STATE NOT YET MANAGED BY RIOTX") - return false // senderNotificationPermissionCondition.isSatisfied(event, ) + val roomId = event.roomId ?: return false + val room = roomGetter.getRoom(roomId) ?: return false + + val powerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, "") + ?.content + ?.toModel() + ?: PowerLevelsContent() + + return condition.isSatisfied(event, powerLevelsContent) } override fun resolveContainsDisplayNameCondition(event: Event, From 8bdb2b88fd804941d46449fef4cdc5f390272cf9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 15:32:36 +0100 Subject: [PATCH 06/28] make the test compile --- .../api/pushrules/PushrulesConditionTest.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt index d67f14842b..f404eafb67 100644 --- a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt +++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt @@ -19,10 +19,10 @@ package im.vector.matrix.android.api.pushrules 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.Membership import im.vector.matrix.android.api.session.room.model.RoomMemberContent import im.vector.matrix.android.api.session.room.model.message.MessageTextContent +import im.vector.matrix.android.internal.session.room.RoomGetter import io.mockk.every import io.mockk.mockk import org.junit.Assert.assertFalse @@ -137,7 +137,7 @@ class PushrulesConditionTest { every { getNumberOfJoinedMembers() } returns 3 } - val sessionStub = mockk { + val roomGetterStub = mockk { every { getRoom(room2JoinedId) } returns roomStub2Joined every { getRoom(room3JoinedId) } returns roomStub3Joined } @@ -148,9 +148,9 @@ class PushrulesConditionTest { content = MessageTextContent("m.text", "A").toContent(), originServerTs = 0, roomId = room2JoinedId).also { - assertFalse("This room does not have 3 members", conditionEqual3.isSatisfied(it, sessionStub)) - assertFalse("This room does not have 3 members", conditionEqual3Bis.isSatisfied(it, sessionStub)) - assertTrue("This room has less than 3 members", conditionLessThan3.isSatisfied(it, sessionStub)) + assertFalse("This room does not have 3 members", conditionEqual3.isSatisfied(it, roomGetterStub)) + assertFalse("This room does not have 3 members", conditionEqual3Bis.isSatisfied(it, roomGetterStub)) + assertTrue("This room has less than 3 members", conditionLessThan3.isSatisfied(it, roomGetterStub)) } Event( @@ -159,9 +159,9 @@ class PushrulesConditionTest { content = MessageTextContent("m.text", "A").toContent(), originServerTs = 0, roomId = room3JoinedId).also { - assertTrue("This room has 3 members", conditionEqual3.isSatisfied(it, sessionStub)) - assertTrue("This room has 3 members", conditionEqual3Bis.isSatisfied(it, sessionStub)) - assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, sessionStub)) + assertTrue("This room has 3 members", conditionEqual3.isSatisfied(it, roomGetterStub)) + assertTrue("This room has 3 members", conditionEqual3Bis.isSatisfied(it, roomGetterStub)) + assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, roomGetterStub)) } } From 9df699db59f990809f9a22127ea9fa1845c0b1c3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 15:35:09 +0100 Subject: [PATCH 07/28] Reorder tests --- .../api/pushrules/PushrulesConditionTest.kt | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt index f404eafb67..f334c0f099 100644 --- a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt +++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt @@ -31,6 +31,10 @@ import org.junit.Test class PushrulesConditionTest { + /* ========================================================================================== + * Test EventMatchCondition + * ========================================================================================== */ + @Test fun test_eventmatch_type_condition() { val condition = EventMatchCondition("type", "m.room.message") @@ -120,6 +124,24 @@ class PushrulesConditionTest { assert(condition.isSatisfied(simpleTextEvent)) } + @Test + fun test_notice_condition() { + val conditionEqual = EventMatchCondition("content.msgtype", "m.notice") + + Event( + type = "m.room.message", + eventId = "mx0", + content = MessageTextContent("m.notice", "A").toContent(), + originServerTs = 0, + roomId = "2joined").also { + assertTrue("Notice", conditionEqual.isSatisfied(it)) + } + } + + /* ========================================================================================== + * Test RoomMemberCountCondition + * ========================================================================================== */ + @Test fun test_roommember_condition() { val conditionEqual3 = RoomMemberCountCondition("3") @@ -164,18 +186,4 @@ class PushrulesConditionTest { assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, roomGetterStub)) } } - - @Test - fun test_notice_condition() { - val conditionEqual = EventMatchCondition("content.msgtype", "m.notice") - - Event( - type = "m.room.message", - eventId = "mx0", - content = MessageTextContent("m.notice", "A").toContent(), - originServerTs = 0, - roomId = "2joined").also { - assertTrue("Notice", conditionEqual.isSatisfied(it)) - } - } } From dd13b6bd99a5b110f7568ea7718e7f45bbb12425 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 15:44:46 +0100 Subject: [PATCH 08/28] Add test for DisplayName condition (passing) --- .../api/pushrules/PushrulesConditionTest.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt index f334c0f099..960d585bdc 100644 --- a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt +++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageTextConten import im.vector.matrix.android.internal.session.room.RoomGetter import io.mockk.every import io.mockk.mockk +import org.amshove.kluent.shouldBe import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test @@ -186,4 +187,31 @@ class PushrulesConditionTest { assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, roomGetterStub)) } } + + /* ========================================================================================== + * Test ContainsDisplayNameCondition + * ========================================================================================== */ + + @Test + fun test_displayName_condition() { + val condition = ContainsDisplayNameCondition() + + val event = Event( + type = "m.room.message", + eventId = "mx0", + content = MessageTextContent("m.text", "How was the cake benoit?").toContent(), + originServerTs = 0, + roomId = "2joined") + + condition.isSatisfied(event, "how") shouldBe true + condition.isSatisfied(event, "How") shouldBe true + condition.isSatisfied(event, "benoit") shouldBe true + condition.isSatisfied(event, "Benoit") shouldBe true + condition.isSatisfied(event, "cake") shouldBe true + + condition.isSatisfied(event, "ben") shouldBe false + condition.isSatisfied(event, "oit") shouldBe false + condition.isSatisfied(event, "enoi") shouldBe false + condition.isSatisfied(event, "H") shouldBe false + } } From c34307ecf7bd269c5851e8fc552d7ff433ea3a87 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 16:28:47 +0100 Subject: [PATCH 09/28] Convert to ViewEvents -> RoomDirectoryViewModel --- .../roomdirectory/PublicRoomsFragment.kt | 17 ++++++++---- .../roomdirectory/RoomDirectoryViewEvents.kt | 27 +++++++++++++++++++ .../roomdirectory/RoomDirectoryViewModel.kt | 27 +++++++++---------- 3 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewEvents.kt diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt index 580844ddfa..0cb2a7feca 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt @@ -28,7 +28,7 @@ import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom import im.vector.riotx.R import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith -import im.vector.riotx.core.extensions.observeEvent +import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorBaseFragment import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_public_rooms.* @@ -75,13 +75,20 @@ class PublicRoomsFragment @Inject constructor( sharedActionViewModel.post(RoomDirectorySharedAction.CreateRoom) } - // TODO remove this, replace by ViewEvents - viewModel.joinRoomErrorLiveData.observeEvent(this) { throwable -> - Snackbar.make(publicRoomsCoordinator, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT) - .show() + viewModel.observeViewEvents { + handleViewEvents(it) } } + private fun handleViewEvents(viewEvents: RoomDirectoryViewEvents) { + when (viewEvents) { + is RoomDirectoryViewEvents.Failure -> { + Snackbar.make(publicRoomsCoordinator, errorFormatter.toHumanReadable(viewEvents.throwable), Snackbar.LENGTH_SHORT) + .show() + } + }.exhaustive + } + override fun onDestroyView() { publicRoomsController.callback = null publicRoomsList.cleanup() diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewEvents.kt new file mode 100644 index 0000000000..2fb46efd81 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewEvents.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 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.roomdirectory + +import im.vector.riotx.core.platform.VectorViewEvents + +/** + * Transient events for room directory screen + */ +sealed class RoomDirectoryViewEvents : VectorViewEvents { + // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() + data class Failure(val throwable: Throwable) : RoomDirectoryViewEvents() +} diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewModel.kt index bab07795e9..9f81e8b076 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewModel.kt @@ -16,9 +16,13 @@ package im.vector.riotx.features.roomdirectory -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import com.airbnb.mvrx.* +import com.airbnb.mvrx.ActivityViewModelContext +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.ViewModelContext +import com.airbnb.mvrx.appendAt import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback @@ -32,17 +36,14 @@ import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryD import im.vector.matrix.android.api.session.room.roomSummaryQueryParams import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.rx.rx -import im.vector.riotx.core.extensions.postLiveEvent -import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.VectorViewModel -import im.vector.riotx.core.utils.LiveEvent import timber.log.Timber private const val PUBLIC_ROOMS_LIMIT = 20 class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: PublicRoomsViewState, private val session: Session) - : VectorViewModel(initialState) { + : VectorViewModel(initialState) { @AssistedInject.Factory interface Factory { @@ -58,10 +59,6 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: } } - private val _joinRoomErrorLiveData = MutableLiveData>() - val joinRoomErrorLiveData: LiveData> - get() = _joinRoomErrorLiveData - private var since: String? = null private var currentTask: Cancelable? = null @@ -109,9 +106,9 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: override fun handle(action: RoomDirectoryAction) { when (action) { is RoomDirectoryAction.SetRoomDirectoryData -> setRoomDirectoryData(action) - is RoomDirectoryAction.FilterWith -> filterWith(action) - RoomDirectoryAction.LoadMore -> loadMore() - is RoomDirectoryAction.JoinRoom -> joinRoom(action) + is RoomDirectoryAction.FilterWith -> filterWith(action) + RoomDirectoryAction.LoadMore -> loadMore() + is RoomDirectoryAction.JoinRoom -> joinRoom(action) } } @@ -227,7 +224,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: override fun onFailure(failure: Throwable) { // Notify the user - _joinRoomErrorLiveData.postLiveEvent(failure) + _viewEvents.post(RoomDirectoryViewEvents.Failure(failure)) setState { copy( From 7f5cc77ee0ef119b8714fc40fd414fb55be0e500 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 17:10:57 +0100 Subject: [PATCH 10/28] Convert to ViewEvents -> DevicesViewModel --- .../verification/VerificationBottomSheet.kt | 4 +- .../settings/devices/DevicesAction.kt | 8 ++-- .../settings/devices/DevicesViewEvents.kt | 11 +++++ .../settings/devices/DevicesViewModel.kt | 34 ++++---------- .../devices/VectorSettingsDevicesFragment.kt | 44 ++++++------------- 5 files changed, 39 insertions(+), 62 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt index b4f9892252..b767f74fea 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt @@ -56,7 +56,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { val verificationId: String? = null, val roomId: String? = null, // Special mode where UX should show loading wheel until other user sends a request/tx - val waitForIncomingRequest : Boolean = false + val waitForIncomingRequest: Boolean = false ) : Parcelable @Inject @@ -250,7 +250,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { } } - val WAITING_SELF_VERIF_TAG : String = "WAITING_SELF_VERIF_TAG" + const val WAITING_SELF_VERIF_TAG: String = "WAITING_SELF_VERIF_TAG" } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesAction.kt b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesAction.kt index 29fbb9ca46..e4b1b98cc8 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesAction.kt @@ -16,14 +16,14 @@ package im.vector.riotx.features.settings.devices -import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.riotx.core.platform.VectorViewModelAction sealed class DevicesAction : VectorViewModelAction { object Retry : DevicesAction() data class Delete(val deviceId: String) : DevicesAction() data class Password(val password: String) : DevicesAction() - data class Rename(val deviceInfo: DeviceInfo, val newName: String) : DevicesAction() - data class PromptRename(val deviceId: String, val deviceInfo: DeviceInfo? = null) : DevicesAction() - data class VerifyMyDevice(val deviceId: String, val userId: String? = null, val transactionId: String? = null) : DevicesAction() + data class Rename(val deviceId: String, val newName: String) : DevicesAction() + + data class PromptRename(val deviceId: String) : DevicesAction() + data class VerifyMyDevice(val deviceId: String) : DevicesAction() } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewEvents.kt index b42738439a..b5788366f3 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewEvents.kt @@ -17,6 +17,7 @@ package im.vector.riotx.features.settings.devices +import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.riotx.core.platform.VectorViewEvents /** @@ -25,4 +26,14 @@ import im.vector.riotx.core.platform.VectorViewEvents sealed class DevicesViewEvents : VectorViewEvents { data class Loading(val message: CharSequence? = null) : DevicesViewEvents() data class Failure(val throwable: Throwable) : DevicesViewEvents() + + object RequestPassword : DevicesViewEvents() + + data class PromptRenameDevice(val deviceInfo: DeviceInfo) : DevicesViewEvents() + + data class ShowVerifyDevice( + val userId: String, + val deviceId: String, + val transactionId: String? + ) : DevicesViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewModel.kt index 419b6a5492..a7a25caed3 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewModel.kt @@ -16,8 +16,6 @@ package im.vector.riotx.features.settings.devices -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext @@ -41,9 +39,7 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse import im.vector.matrix.rx.rx -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.features.crypto.verification.supportedVerificationMethods data class DevicesViewState( @@ -76,15 +72,6 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic private var _currentDeviceId: String? = null private var _currentSession: String? = null - private val _requestPasswordLiveData = MutableLiveData>() - val requestPasswordLiveData: LiveData> - get() = _requestPasswordLiveData - - // Used to communicate back from model to fragment - private val _requestLiveData = MutableLiveData>>() - val fragmentActionLiveData: LiveData>> - get() = _requestLiveData - init { refreshDevicesList() session.getVerificationService().addListener(this) @@ -187,25 +174,22 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic private fun handleVerify(action: DevicesAction.VerifyMyDevice) { val txID = session.getVerificationService().requestKeyVerification(supportedVerificationMethods, session.myUserId, listOf(action.deviceId)) - _requestLiveData.postValue(LiveEvent(Success( - action.copy( - userId = session.myUserId, - transactionId = txID.transactionId - ) - ))) + _viewEvents.post(DevicesViewEvents.ShowVerifyDevice( + session.myUserId, + action.deviceId, + txID.transactionId + )) } private fun handlePromptRename(action: DevicesAction.PromptRename) = withState { state -> val info = state.devices.invoke()?.firstOrNull { it.deviceId == action.deviceId } - if (info == null) { - _requestLiveData.postValue(LiveEvent(Uninitialized)) - } else { - _requestLiveData.postValue(LiveEvent(Success(action.copy(deviceInfo = info)))) + if (info != null) { + _viewEvents.post(DevicesViewEvents.PromptRenameDevice(info)) } } private fun handleRename(action: DevicesAction.Rename) { - session.setDeviceName(action.deviceInfo.deviceId!!, action.newName, object : MatrixCallback { + session.setDeviceName(action.deviceId, action.newName, object : MatrixCallback { override fun onSuccess(data: Unit) { setState { copy( @@ -261,7 +245,7 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic ) } - _requestPasswordLiveData.postLiveEvent(Unit) + _viewEvents.post(DevicesViewEvents.RequestPassword) } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devices/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/devices/VectorSettingsDevicesFragment.kt index a1cc93d0b0..76496fc3de 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/devices/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/devices/VectorSettingsDevicesFragment.kt @@ -23,7 +23,6 @@ import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import com.airbnb.mvrx.Async import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo @@ -32,7 +31,6 @@ import im.vector.riotx.core.dialogs.PromptPasswordDialog import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith import im.vector.riotx.core.extensions.exhaustive -import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.platform.VectorBaseActivity import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.features.crypto.verification.VerificationBottomSheet @@ -64,35 +62,19 @@ class VectorSettingsDevicesFragment @Inject constructor( recyclerView.configureWith(devicesController, showDivider = true) viewModel.observeViewEvents { when (it) { - is DevicesViewEvents.Loading -> showLoading(it.message) - is DevicesViewEvents.Failure -> showFailure(it.throwable) - }.exhaustive - } - viewModel.requestPasswordLiveData.observeEvent(this) { - maybeShowDeleteDeviceWithPasswordDialog() - } - - viewModel.fragmentActionLiveData.observeEvent(this) { async -> - when (async) { - is Success -> { - when (val action = async.invoke()) { - is DevicesAction.PromptRename -> { - action.deviceInfo?.let { deviceInfo -> - displayDeviceRenameDialog(deviceInfo) - } - } - is DevicesAction.VerifyMyDevice -> { - if (context is VectorBaseActivity) { - VerificationBottomSheet.withArgs( - roomId = null, - otherUserId = action.userId!!, - transactionId = action.transactionId!! - ).show(childFragmentManager, "REQPOP") - } - } - } + is DevicesViewEvents.Loading -> showLoading(it.message) + is DevicesViewEvents.Failure -> showFailure(it.throwable) + is DevicesViewEvents.RequestPassword -> maybeShowDeleteDeviceWithPasswordDialog() + is DevicesViewEvents.PromptRenameDevice -> displayDeviceRenameDialog(it.deviceInfo) + is DevicesViewEvents.ShowVerifyDevice -> { + // TODO Valere: We should pass the deviceId here + VerificationBottomSheet.withArgs( + roomId = null, + otherUserId = it.userId, + transactionId = it.transactionId + ).show(childFragmentManager, "REQPOP") } - } + }.exhaustive } } @@ -152,7 +134,7 @@ class VectorSettingsDevicesFragment @Inject constructor( .setPositiveButton(R.string.ok) { _, _ -> val newName = input.text.toString() - viewModel.handle(DevicesAction.Rename(deviceInfo, newName)) + viewModel.handle(DevicesAction.Rename(deviceInfo.deviceId!!, newName)) } .setNegativeButton(R.string.cancel, null) .show() From 256a6e43221fc96dedd1863b67446ee212ff9267 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 17:34:26 +0100 Subject: [PATCH 11/28] Convert to ViewEvents -> RoomDetailViewModel --- .../home/room/detail/RoomDetailFragment.kt | 143 +++++++++--------- .../home/room/detail/RoomDetailViewEvents.kt | 3 + .../home/room/detail/RoomDetailViewModel.kt | 27 ++-- 3 files changed, 82 insertions(+), 91 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 0d6dd292e9..7ec6f184ff 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -307,14 +307,12 @@ class RoomDetailFragment @Inject constructor( syncStateView.render(syncState) } - roomDetailViewModel.requestLiveData.observeEvent(this) { - displayRoomDetailActionResult(it) - } - roomDetailViewModel.observeViewEvents { when (it) { is RoomDetailViewEvents.Failure -> showErrorInSnackbar(it.throwable) is RoomDetailViewEvents.OnNewTimelineEvents -> scrollOnNewMessageCallback.addNewTimelineEventIds(it.eventIds) + is RoomDetailViewEvents.ActionSuccess -> displayRoomDetailActionSuccess(it) + is RoomDetailViewEvents.ActionFailure -> displayRoomDetailActionFailure(it) }.exhaustive } } @@ -793,84 +791,81 @@ class RoomDetailFragment @Inject constructor( .show() } - private fun displayRoomDetailActionResult(result: Async) { - when (result) { - is Fail -> { - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.dialog_title_error) - .setMessage(errorFormatter.toHumanReadable(result.error)) - .setPositiveButton(R.string.ok, null) - .show() - } - is Success -> { - when (val data = result.invoke()) { - is RoomDetailAction.ReportContent -> { - when { - data.spam -> { - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.content_reported_as_spam_title) - .setMessage(R.string.content_reported_as_spam_content) - .setPositiveButton(R.string.ok, null) - .setNegativeButton(R.string.block_user) { _, _ -> - roomDetailViewModel.handle(RoomDetailAction.IgnoreUser(data.senderId)) - } - .show() - .withColoredButton(DialogInterface.BUTTON_NEGATIVE) - } - data.inappropriate -> { - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.content_reported_as_inappropriate_title) - .setMessage(R.string.content_reported_as_inappropriate_content) - .setPositiveButton(R.string.ok, null) - .setNegativeButton(R.string.block_user) { _, _ -> - roomDetailViewModel.handle(RoomDetailAction.IgnoreUser(data.senderId)) - } - .show() - .withColoredButton(DialogInterface.BUTTON_NEGATIVE) - } - else -> { - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.content_reported_title) - .setMessage(R.string.content_reported_content) - .setPositiveButton(R.string.ok, null) - .setNegativeButton(R.string.block_user) { _, _ -> - roomDetailViewModel.handle(RoomDetailAction.IgnoreUser(data.senderId)) - } - .show() - .withColoredButton(DialogInterface.BUTTON_NEGATIVE) - } - } + private fun displayRoomDetailActionFailure(result: RoomDetailViewEvents.ActionFailure) { + AlertDialog.Builder(requireActivity()) + .setTitle(R.string.dialog_title_error) + .setMessage(errorFormatter.toHumanReadable(result.throwable)) + .setPositiveButton(R.string.ok, null) + .show() + } + + private fun displayRoomDetailActionSuccess(result: RoomDetailViewEvents.ActionSuccess) { + when (val data = result.action) { + is RoomDetailAction.ReportContent -> { + when { + data.spam -> { + AlertDialog.Builder(requireActivity()) + .setTitle(R.string.content_reported_as_spam_title) + .setMessage(R.string.content_reported_as_spam_content) + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.block_user) { _, _ -> + roomDetailViewModel.handle(RoomDetailAction.IgnoreUser(data.senderId)) + } + .show() + .withColoredButton(DialogInterface.BUTTON_NEGATIVE) } - is RoomDetailAction.RequestVerification -> { - Timber.v("## SAS RequestVerification action") - VerificationBottomSheet.withArgs( - roomDetailArgs.roomId, - data.userId - ).show(parentFragmentManager, "REQ") + data.inappropriate -> { + AlertDialog.Builder(requireActivity()) + .setTitle(R.string.content_reported_as_inappropriate_title) + .setMessage(R.string.content_reported_as_inappropriate_content) + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.block_user) { _, _ -> + roomDetailViewModel.handle(RoomDetailAction.IgnoreUser(data.senderId)) + } + .show() + .withColoredButton(DialogInterface.BUTTON_NEGATIVE) } - is RoomDetailAction.AcceptVerificationRequest -> { - Timber.v("## SAS AcceptVerificationRequest action") - VerificationBottomSheet.withArgs( - roomDetailArgs.roomId, - data.otherUserId, - data.transactionId - ).show(parentFragmentManager, "REQ") - } - is RoomDetailAction.ResumeVerification -> { - val otherUserId = data.otherUserId ?: return - VerificationBottomSheet().apply { - arguments = Bundle().apply { - putParcelable(MvRx.KEY_ARG, VerificationBottomSheet.VerificationArgs( - otherUserId, data.transactionId, roomId = roomDetailArgs.roomId)) - } - }.show(parentFragmentManager, "REQ") + else -> { + AlertDialog.Builder(requireActivity()) + .setTitle(R.string.content_reported_title) + .setMessage(R.string.content_reported_content) + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.block_user) { _, _ -> + roomDetailViewModel.handle(RoomDetailAction.IgnoreUser(data.senderId)) + } + .show() + .withColoredButton(DialogInterface.BUTTON_NEGATIVE) } } } + is RoomDetailAction.RequestVerification -> { + Timber.v("## SAS RequestVerification action") + VerificationBottomSheet.withArgs( + roomDetailArgs.roomId, + data.userId + ).show(parentFragmentManager, "REQ") + } + is RoomDetailAction.AcceptVerificationRequest -> { + Timber.v("## SAS AcceptVerificationRequest action") + VerificationBottomSheet.withArgs( + roomDetailArgs.roomId, + data.otherUserId, + data.transactionId + ).show(parentFragmentManager, "REQ") + } + is RoomDetailAction.ResumeVerification -> { + val otherUserId = data.otherUserId ?: return + VerificationBottomSheet().apply { + arguments = Bundle().apply { + putParcelable(MvRx.KEY_ARG, VerificationBottomSheet.VerificationArgs( + otherUserId, data.transactionId, roomId = roomDetailArgs.roomId)) + } + }.show(parentFragmentManager, "REQ") + } } } -// TimelineEventController.Callback ************************************************************ + // TimelineEventController.Callback ************************************************************ override fun onUrlClicked(url: String): Boolean { permalinkHandler diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt index 6470e0c338..13e77d1974 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt @@ -24,4 +24,7 @@ import im.vector.riotx.core.platform.VectorViewEvents sealed class RoomDetailViewEvents : VectorViewEvents { data class Failure(val throwable: Throwable) : RoomDetailViewEvents() data class OnNewTimelineEvents(val eventIds: List) : RoomDetailViewEvents() + + data class ActionSuccess(val action: RoomDetailAction) : RoomDetailViewEvents() + data class ActionFailure(val action: RoomDetailAction, val throwable: Throwable) : RoomDetailViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 2bee55bce3..fda6e44771 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -20,8 +20,6 @@ import android.net.Uri import androidx.annotation.IdRes import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.airbnb.mvrx.Async -import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success @@ -32,6 +30,7 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixPatterns +import im.vector.matrix.android.api.NoOpMatrixCallback import im.vector.matrix.android.api.query.QueryStringValue import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.events.model.EventType @@ -66,12 +65,11 @@ import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.core.resources.UserPreferencesProvider import im.vector.riotx.core.utils.LiveEvent -import im.vector.matrix.android.api.NoOpMatrixCallback import im.vector.riotx.core.utils.subscribeLogError import im.vector.riotx.features.command.CommandParser import im.vector.riotx.features.command.ParsedCommand -import im.vector.riotx.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.riotx.features.crypto.verification.supportedVerificationMethods +import im.vector.riotx.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents import im.vector.riotx.features.home.room.typing.TypingHelper import im.vector.riotx.features.settings.VectorPreferences @@ -116,11 +114,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro var timeline = room.createTimeline(eventId, timelineSettings) private set - // Can be used for several actions, for a one shot result - private val _requestLiveData = MutableLiveData>>() - val requestLiveData: LiveData>> - get() = _requestLiveData - // Slot to keep a pending action during permission request var pendingAction: RoomDetailAction? = null // Slot to keep a pending uri during permission request @@ -821,11 +814,11 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro private fun handleReportContent(action: RoomDetailAction.ReportContent) { room.reportContent(action.eventId, -100, action.reason, object : MatrixCallback { override fun onSuccess(data: Unit) { - _requestLiveData.postValue(LiveEvent(Success(action))) + _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action)) } override fun onFailure(failure: Throwable) { - _requestLiveData.postValue(LiveEvent(Fail(failure))) + _viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure)) } }) } @@ -837,11 +830,11 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro session.ignoreUserIds(listOf(action.userId), object : MatrixCallback { override fun onSuccess(data: Unit) { - _requestLiveData.postValue(LiveEvent(Success(action))) + _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action)) } override fun onFailure(failure: Throwable) { - _requestLiveData.postValue(LiveEvent(Fail(failure))) + _viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure)) } }) } @@ -853,7 +846,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro action.otherUserId, room.roomId, action.transactionId)) { - _requestLiveData.postValue(LiveEvent(Success(action))) + _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action)) } else { // TODO } @@ -869,7 +862,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro private fun handleRequestVerification(action: RoomDetailAction.RequestVerification) { if (action.userId == session.myUserId) return - _requestLiveData.postValue(LiveEvent(Success(action))) + _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action)) } private fun handleResumeRequestVerification(action: RoomDetailAction.ResumeVerification) { @@ -877,9 +870,9 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro session.getVerificationService().getExistingVerificationRequestInRoom(room.roomId, action.transactionId)?.let { if (it.handledByOtherSession) return if (!it.isFinished) { - _requestLiveData.postValue(LiveEvent(Success(action.copy( + _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action.copy( otherUserId = it.otherUserId - )))) + ))) } } } From 24667f38b8b3a9fe0fb33616884d2c7c5e5d579a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 17:47:37 +0100 Subject: [PATCH 12/28] Convert to ViewEvents -> RoomMemberProfileViewModel --- .../RoomMemberProfileAction.kt | 7 ++- .../RoomMemberProfileFragment.kt | 45 ++++++++----------- .../RoomMemberProfileViewEvents.kt | 5 +++ .../RoomMemberProfileViewModel.kt | 24 +++------- 4 files changed, 33 insertions(+), 48 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileAction.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileAction.kt index 5b890d1ef6..e352683841 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileAction.kt @@ -20,8 +20,7 @@ package im.vector.riotx.features.roommemberprofile import im.vector.riotx.core.platform.VectorViewModelAction sealed class RoomMemberProfileAction : VectorViewModelAction { - - object RetryFetchingInfo: RoomMemberProfileAction() - object IgnoreUser: RoomMemberProfileAction() - data class VerifyUser(val userId: String? = null, val roomId: String? = null, val canCrossSign: Boolean? = true): RoomMemberProfileAction() + object RetryFetchingInfo : RoomMemberProfileAction() + object IgnoreUser : RoomMemberProfileAction() + object VerifyUser : RoomMemberProfileAction() } diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileFragment.kt index e9ecbf78e3..89b37400f1 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -35,7 +35,6 @@ import im.vector.riotx.core.animations.MatrixItemAppBarStateChangeListener import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith import im.vector.riotx.core.extensions.exhaustive -import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.extensions.setTextOrHide import im.vector.riotx.core.platform.StateView import im.vector.riotx.core.platform.VectorBaseFragment @@ -94,33 +93,27 @@ class RoomMemberProfileFragment @Inject constructor( is RoomMemberProfileViewEvents.Loading -> showLoading(it.message) is RoomMemberProfileViewEvents.Failure -> showFailure(it.throwable) is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit + is RoomMemberProfileViewEvents.StartVerification -> handleStartVerification(it) }.exhaustive } - viewModel.actionResultLiveData.observeEvent(this) { async -> - when (async) { - is Success -> { - when (val action = async.invoke()) { - is RoomMemberProfileAction.VerifyUser -> { - if (action.canCrossSign == true) { - VerificationBottomSheet - .withArgs(roomId = null, otherUserId = action.userId!!) - .show(parentFragmentManager, "VERIF") - } else { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.dialog_title_warning) - .setMessage(R.string.verify_cannot_cross_sign) - .setPositiveButton(R.string.verification_profile_verify) { _, _ -> - VerificationBottomSheet - .withArgs(roomId = null, otherUserId = action.userId!!) - .show(parentFragmentManager, "VERIF") - } - .setNegativeButton(R.string.cancel, null) - .show() - } - } + } + + private fun handleStartVerification(startVerification: RoomMemberProfileViewEvents.StartVerification) { + if (startVerification.canCrossSign) { + VerificationBottomSheet + .withArgs(roomId = null, otherUserId = startVerification.userId) + .show(parentFragmentManager, "VERIF") + } else { + AlertDialog.Builder(requireContext()) + .setTitle(R.string.dialog_title_warning) + .setMessage(R.string.verify_cannot_cross_sign) + .setPositiveButton(R.string.verification_profile_verify) { _, _ -> + VerificationBottomSheet + .withArgs(roomId = null, otherUserId = startVerification.userId) + .show(parentFragmentManager, "VERIF") } - } - } + .setNegativeButton(R.string.cancel, null) + .show() } } @@ -197,7 +190,7 @@ class RoomMemberProfileFragment @Inject constructor( } override fun onTapVerify() { - viewModel.handle(RoomMemberProfileAction.VerifyUser()) + viewModel.handle(RoomMemberProfileAction.VerifyUser) } override fun onShowDeviceList() = withState(viewModel) { diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileViewEvents.kt index 4647c124a6..5b7f5bf54c 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileViewEvents.kt @@ -26,4 +26,9 @@ sealed class RoomMemberProfileViewEvents : VectorViewEvents { data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents() object OnIgnoreActionSuccess : RoomMemberProfileViewEvents() + + data class StartVerification( + val userId: String, + val canCrossSign: Boolean + ) : RoomMemberProfileViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileViewModel.kt index 2af7a6ec35..e3dd53104c 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileViewModel.kt @@ -17,10 +17,7 @@ package im.vector.riotx.features.roommemberprofile -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success @@ -49,7 +46,6 @@ import im.vector.matrix.rx.unwrap import im.vector.riotx.R import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.resources.StringProvider -import im.vector.riotx.core.utils.LiveEvent import io.reactivex.Observable import io.reactivex.functions.BiFunction import kotlinx.coroutines.Dispatchers @@ -75,10 +71,6 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v } } - private val _actionResultLiveData = MutableLiveData>>() - val actionResultLiveData: LiveData>> - get() = _actionResultLiveData - private val room = if (initialState.roomId != null) { session.getRoom(initialState.roomId) } else { @@ -145,23 +137,19 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v when (action) { is RoomMemberProfileAction.RetryFetchingInfo -> fetchProfileInfo() is RoomMemberProfileAction.IgnoreUser -> handleIgnoreAction() - is RoomMemberProfileAction.VerifyUser -> prepareVerification(action) + is RoomMemberProfileAction.VerifyUser -> prepareVerification() } } - private fun prepareVerification(action: RoomMemberProfileAction.VerifyUser) = withState { state -> + private fun prepareVerification() = withState { state -> // Sanity if (state.isRoomEncrypted) { if (!state.isMine && state.userMXCrossSigningInfo?.isTrusted() == false) { // ok, let's find or create the DM room - _actionResultLiveData.postValue( - LiveEvent(Success( - action.copy( - userId = state.userId, - canCrossSign = session.getCrossSigningService().canCrossSign() - ) - )) - ) + _viewEvents.post(RoomMemberProfileViewEvents.StartVerification( + userId = state.userId, + canCrossSign = session.getCrossSigningService().canCrossSign() + )) } } } From 33b123f719cc7fb128e0b46d6064309324bdf151 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 18:02:42 +0100 Subject: [PATCH 13/28] Convert to ViewEvents -> GroupListViewModel --- .../features/grouplist/GroupListFragment.kt | 8 +++-- .../features/grouplist/GroupListViewEvents.kt | 29 +++++++++++++++++++ .../features/grouplist/GroupListViewModel.kt | 17 ++++------- 3 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewEvents.kt diff --git a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListFragment.kt b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListFragment.kt index c9c98a58ab..e884761cdf 100644 --- a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListFragment.kt @@ -26,7 +26,7 @@ import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.riotx.R import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith -import im.vector.riotx.core.extensions.observeEvent +import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.StateView import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.features.home.HomeActivitySharedAction @@ -51,8 +51,10 @@ class GroupListFragment @Inject constructor( stateView.contentView = groupListView groupListView.configureWith(groupController) viewModel.subscribe { renderState(it) } - viewModel.openGroupLiveData.observeEvent(this) { - sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup) + viewModel.observeViewEvents { + when (it) { + is GroupListViewEvents.OpenGroupSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup) + }.exhaustive } } diff --git a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewEvents.kt new file mode 100644 index 0000000000..92e4a5c6e3 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewEvents.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 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.grouplist + +import im.vector.riotx.core.platform.VectorViewEvents + +/** + * Transient events for group list screen + */ +sealed class GroupListViewEvents : VectorViewEvents { + // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() + // data class Failure(val throwable: Throwable) : GroupListViewEvents() + + object OpenGroupSummary : GroupListViewEvents() +} diff --git a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewModel.kt b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewModel.kt index c31a30b432..f14583c5d5 100644 --- a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewModel.kt @@ -17,8 +17,6 @@ package im.vector.riotx.features.grouplist -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import arrow.core.Option import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory @@ -32,11 +30,8 @@ import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.rx.rx import im.vector.riotx.R -import im.vector.riotx.core.extensions.postLiveEvent -import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.resources.StringProvider -import im.vector.riotx.core.utils.LiveEvent import io.reactivex.Observable import io.reactivex.functions.BiFunction @@ -46,7 +41,7 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro private val selectedGroupStore: SelectedGroupDataSource, private val session: Session, private val stringProvider: StringProvider -) : VectorViewModel(initialState) { +) : VectorViewModel(initialState) { @AssistedInject.Factory interface Factory { @@ -62,9 +57,7 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro } } - private val _openGroupLiveData = MutableLiveData>() - val openGroupLiveData: LiveData> - get() = _openGroupLiveData + private var currentGroupId = "" init { observeGroupSummaries() @@ -74,10 +67,10 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro private fun observeSelectionState() { selectSubscribe(GroupListViewState::selectedGroup) { groupSummary -> if (groupSummary != null) { - val selectedGroup = _openGroupLiveData.value?.peekContent() // We only want to open group if the updated selectedGroup is a different one. - if (selectedGroup?.groupId != groupSummary.groupId) { - _openGroupLiveData.postLiveEvent(groupSummary) + if (currentGroupId != groupSummary.groupId) { + currentGroupId = groupSummary.groupId + _viewEvents.post(GroupListViewEvents.OpenGroupSummary) } val optionGroup = Option.just(groupSummary) selectedGroupStore.post(optionGroup) From 35054dc5e88578ba240db380482f59f8fca18e46 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 18:11:53 +0100 Subject: [PATCH 14/28] Convert to ViewEvents -> CreateDirectRoomViewModel --- .../CreateDirectRoomKnownUsersFragment.kt | 14 +++++--- .../createdirect/CreateDirectRoomViewModel.kt | 21 ++---------- .../createdirect/CreateDirectViewEvents.kt | 34 +++++++++++++++++++ 3 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectViewEvents.kt diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt index 1fcc8d443b..370cac0100 100644 --- a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt @@ -31,7 +31,11 @@ import com.google.android.material.chip.ChipGroup import com.jakewharton.rxbinding3.widget.textChanges import im.vector.matrix.android.api.session.user.model.User import im.vector.riotx.R -import im.vector.riotx.core.extensions.* +import im.vector.riotx.core.extensions.cleanup +import im.vector.riotx.core.extensions.configureWith +import im.vector.riotx.core.extensions.exhaustive +import im.vector.riotx.core.extensions.hideKeyboard +import im.vector.riotx.core.extensions.setupAsSearch import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.core.utils.DimensionConverter import kotlinx.android.synthetic.main.fragment_create_direct_room.* @@ -57,8 +61,10 @@ class CreateDirectRoomKnownUsersFragment @Inject constructor( setupFilterView() setupAddByMatrixIdView() setupCloseView() - viewModel.selectUserEvent.observeEvent(this) { - updateChipsView(it) + viewModel.observeViewEvents { + when (it) { + is CreateDirectViewEvents.SelectUserAction -> updateChipsView(it) + }.exhaustive } viewModel.selectSubscribe(this, CreateDirectRoomViewState::selectedUsers) { renderSelectedUsers(it) @@ -132,7 +138,7 @@ class CreateDirectRoomKnownUsersFragment @Inject constructor( knownUsersController.setData(it) } - private fun updateChipsView(data: SelectUserAction) { + private fun updateChipsView(data: CreateDirectViewEvents.SelectUserAction) { if (data.isAdded) { addChipToGroup(data.user, chipGroup) } else { diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt index 6456acaf22..79bbdb9ffb 100644 --- a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt @@ -18,8 +18,6 @@ package im.vector.riotx.features.createdirect -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import arrow.core.Option import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory @@ -32,10 +30,7 @@ import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.session.user.model.User import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.rx.rx -import im.vector.riotx.core.extensions.postLiveEvent -import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.VectorViewModel -import im.vector.riotx.core.utils.LiveEvent import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import java.util.concurrent.TimeUnit @@ -43,16 +38,10 @@ import java.util.concurrent.TimeUnit private typealias KnowUsersFilter = String private typealias DirectoryUsersSearch = String -data class SelectUserAction( - val user: User, - val isAdded: Boolean, - val index: Int -) - class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateDirectRoomViewState, private val session: Session) - : VectorViewModel(initialState) { + : VectorViewModel(initialState) { @AssistedInject.Factory interface Factory { @@ -62,10 +51,6 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted private val knownUsersFilter = BehaviorRelay.createDefault>(Option.empty()) private val directoryUsersSearch = BehaviorRelay.create() - private val _selectUserEvent = MutableLiveData>() - val selectUserEvent: LiveData> - get() = _selectUserEvent - companion object : MvRxViewModelFactory { @JvmStatic @@ -109,7 +94,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted val index = state.selectedUsers.indexOfFirst { it.userId == action.user.userId } val selectedUsers = state.selectedUsers.minus(action.user) setState { copy(selectedUsers = selectedUsers) } - _selectUserEvent.postLiveEvent(SelectUserAction(action.user, false, index)) + _viewEvents.post(CreateDirectViewEvents.SelectUserAction(action.user, false, index)) } private fun handleSelectUser(action: CreateDirectRoomAction.SelectUser) = withState { state -> @@ -129,7 +114,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted isAddOperation = false } setState { copy(selectedUsers = selectedUsers) } - _selectUserEvent.postLiveEvent(SelectUserAction(action.user, isAddOperation, changeIndex)) + _viewEvents.post(CreateDirectViewEvents.SelectUserAction(action.user, isAddOperation, changeIndex)) } private fun observeDirectoryUsers() { diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectViewEvents.kt new file mode 100644 index 0000000000..4ef2fcd966 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectViewEvents.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 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.createdirect + +import im.vector.matrix.android.api.session.user.model.User +import im.vector.riotx.core.platform.VectorViewEvents + +/** + * Transient events for create direct room screen + */ +sealed class CreateDirectViewEvents : VectorViewEvents { + // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() + // data class Failure(val throwable: Throwable) : CreateDirectViewEvents() + + data class SelectUserAction( + val user: User, + val isAdded: Boolean, + val index: Int + ) : CreateDirectViewEvents() +} From a930313bf3683e46a0909aadbe9a4e56baadbdff Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 18:27:13 +0100 Subject: [PATCH 15/28] Convert to ViewEvents -> VerificationBottomSheetViewModel --- .../VectorBaseBottomSheetDialogFragment.kt | 36 +++++++++++++++++++ .../verification/VerificationBottomSheet.kt | 19 ++++------ .../VerificationBottomSheetViewEvents.kt | 29 +++++++++++++++ .../VerificationBottomSheetViewModel.kt | 13 ++----- 4 files changed, 73 insertions(+), 24 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewEvents.kt diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseBottomSheetDialogFragment.kt index 9b86782c42..fbc4bc5292 100644 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseBottomSheetDialogFragment.kt @@ -37,6 +37,9 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import im.vector.riotx.core.di.DaggerScreenComponent import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.utils.DimensionConverter +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable import timber.log.Timber /** @@ -87,10 +90,18 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment() return view } + @CallSuper override fun onDestroyView() { super.onDestroyView() unBinder?.unbind() unBinder = null + uiDisposables.clear() + } + + @CallSuper + override fun onDestroy() { + uiDisposables.dispose() + super.onDestroy() } override fun onAttach(context: Context) { @@ -146,4 +157,29 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment() protected fun setArguments(args: Parcelable? = null) { arguments = args?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } } } + + /* ========================================================================================== + * Disposable + * ========================================================================================== */ + + private val uiDisposables = CompositeDisposable() + + protected fun Disposable.disposeOnDestroyView(): Disposable { + uiDisposables.add(this) + return this + } + + /* ========================================================================================== + * ViewEvents + * ========================================================================================== */ + + protected fun VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) { + viewEvents + .observe() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + observer(it) + } + .disposeOnDestroyView() + } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt index b767f74fea..75983a1969 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt @@ -23,18 +23,17 @@ import android.widget.TextView import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.isVisible import androidx.fragment.app.Fragment -import androidx.lifecycle.Observer import androidx.transition.AutoTransition import androidx.transition.TransitionManager import butterknife.BindView import com.airbnb.mvrx.MvRx -import com.airbnb.mvrx.Success import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.matrix.android.api.session.crypto.sas.VerificationTxState import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.extensions.commitTransactionNow +import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.riotx.features.crypto.verification.choose.VerificationChooseMethodFragment import im.vector.riotx.features.crypto.verification.conclusion.VerificationConclusionFragment @@ -84,17 +83,11 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.requestLiveData.observe(viewLifecycleOwner, Observer { - it.peekContent().let { va -> - when (va) { - is Success -> { - if (va.invoke() is VerificationAction.GotItConclusion) { - dismiss() - } - } - } - } - }) + viewModel.observeViewEvents { + when (it) { + is VerificationBottomSheetViewEvents.Dismiss -> dismiss() + }.exhaustive + } } override fun invalidate() = withState(viewModel) { state -> diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewEvents.kt new file mode 100644 index 0000000000..99417c6ca2 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewEvents.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 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.crypto.verification + +import im.vector.riotx.core.platform.VectorViewEvents + +/** + * Transient events for the verification bottom sheet + */ +sealed class VerificationBottomSheetViewEvents : VectorViewEvents { + // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() + // data class Failure(val throwable: Throwable) : CreateDirectViewEvents() + + object Dismiss : VerificationBottomSheetViewEvents() +} diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt index 5e11570ced..a9f9987c7f 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt @@ -15,8 +15,6 @@ */ package im.vector.riotx.features.crypto.verification -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext @@ -43,9 +41,7 @@ import im.vector.matrix.android.api.util.MatrixItem import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest import im.vector.riotx.core.extensions.exhaustive -import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.VectorViewModel -import im.vector.riotx.core.utils.LiveEvent data class VerificationBottomSheetViewState( val otherUserMxItem: MatrixItem? = null, @@ -63,14 +59,9 @@ data class VerificationBottomSheetViewState( class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: VerificationBottomSheetViewState, @Assisted args: VerificationBottomSheet.VerificationArgs, private val session: Session) - : VectorViewModel(initialState), + : VectorViewModel(initialState), VerificationService.VerificationListener { - // Can be used for several actions, for a one shot result - private val _requestLiveData = MutableLiveData>>() - val requestLiveData: LiveData>> - get() = _requestLiveData - init { session.getVerificationService().addListener(this) @@ -255,7 +246,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini ?.shortCodeDoesNotMatch() } is VerificationAction.GotItConclusion -> { - _requestLiveData.postValue(LiveEvent(Success(action))) + _viewEvents.post(VerificationBottomSheetViewEvents.Dismiss) } }.exhaustive } From 70973c3302da1028c8baa8f30dbc71377b5c96bd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 18:47:54 +0100 Subject: [PATCH 16/28] Convert to ViewEvents -> CrossSigningSettingsViewModel --- .../CrossSigningSettingsFragment.kt | 34 ++++------ .../CrossSigningSettingsViewEvents.kt | 29 +++++++++ .../CrossSigningSettingsViewModel.kt | 65 ++++++++++--------- 3 files changed, 74 insertions(+), 54 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsFragment.kt index fef10019a5..ec56929002 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsFragment.kt @@ -18,16 +18,13 @@ package im.vector.riotx.features.settings.crosssigning import android.os.Bundle import android.view.View import androidx.appcompat.app.AlertDialog -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Success import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState -import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth import im.vector.riotx.R import im.vector.riotx.core.dialogs.PromptPasswordDialog import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith -import im.vector.riotx.core.extensions.observeEvent +import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorBaseActivity import im.vector.riotx.core.platform.VectorBaseFragment import kotlinx.android.synthetic.main.fragment_generic_recycler.* @@ -44,23 +41,20 @@ class CrossSigningSettingsFragment @Inject constructor( override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - viewModel.requestLiveData.observeEvent(this) { + viewModel.observeViewEvents { when (it) { - is Fail -> { + is CrossSigningSettingsViewEvents.Failure -> { AlertDialog.Builder(requireContext()) .setTitle(R.string.dialog_title_error) - .setMessage(it.error.message) + .setMessage(errorFormatter.toHumanReadable(it.throwable)) .setPositiveButton(R.string.ok, null) .show() + Unit } - is Success -> { - when (val action = it.invoke()) { - is CrossSigningAction.RequestPasswordAuth -> { - requestPassword(action.sessionId) - } - } + is CrossSigningSettingsViewEvents.RequestPassword -> { + requestPassword() } - } + }.exhaustive } } @@ -89,18 +83,14 @@ class CrossSigningSettingsFragment @Inject constructor( super.onDestroyView() } - private fun requestPassword(sessionId: String) { + private fun requestPassword() { PromptPasswordDialog().show(requireActivity()) { password -> - // TODO sessionId should never get out the ViewModel - viewModel.handle(CrossSigningAction.InitializeCrossSigning(UserPasswordAuth( - session = sessionId, - password = password - ))) + viewModel.handle(CrossSigningAction.PasswordEntered(password)) } } override fun onInitializeCrossSigningKeys() { - viewModel.handle(CrossSigningAction.InitializeCrossSigning()) + viewModel.handle(CrossSigningAction.InitializeCrossSigning) } override fun onResetCrossSigningKeys() { @@ -108,7 +98,7 @@ class CrossSigningSettingsFragment @Inject constructor( .setTitle(R.string.dialog_title_confirmation) .setMessage(R.string.are_you_sure) .setPositiveButton(R.string.ok) { _, _ -> - viewModel.handle(CrossSigningAction.InitializeCrossSigning()) + viewModel.handle(CrossSigningAction.InitializeCrossSigning) } .show() } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt new file mode 100644 index 0000000000..1e93eca41f --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 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.settings.crosssigning + +import im.vector.riotx.core.platform.VectorViewEvents + +/** + * Transient events for cross signing settings screen + */ +sealed class CrossSigningSettingsViewEvents : VectorViewEvents { + // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() + data class Failure(val throwable: Throwable) : CrossSigningSettingsViewEvents() + + object RequestPassword : CrossSigningSettingsViewEvents() +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt index e95bf50de9..2ad2e8c1ca 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewModel.kt @@ -15,14 +15,9 @@ */ package im.vector.riotx.features.settings.crosssigning -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import com.airbnb.mvrx.Async -import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory -import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject @@ -36,11 +31,9 @@ import im.vector.matrix.android.internal.crypto.crosssigning.isVerified import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.rx.rx -import im.vector.riotx.core.platform.EmptyViewEvents +import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModelAction -import im.vector.riotx.core.resources.StringProvider -import im.vector.riotx.core.utils.LiveEvent data class CrossSigningSettingsViewState( val crossSigningInfo: MXCrossSigningInfo? = null, @@ -51,19 +44,13 @@ data class CrossSigningSettingsViewState( ) : MvRxState sealed class CrossSigningAction : VectorViewModelAction { - data class InitializeCrossSigning(val auth: UserPasswordAuth? = null) : CrossSigningAction() - data class RequestPasswordAuth(val sessionId: String) : CrossSigningAction() + object InitializeCrossSigning : CrossSigningAction() + data class PasswordEntered(val password: String) : CrossSigningAction() } class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted private val initialState: CrossSigningSettingsViewState, - private val stringProvider: StringProvider, private val session: Session) - : VectorViewModel(initialState) { - - // Can be used for several actions, for a one shot result - private val _requestLiveData = MutableLiveData>>() - val requestLiveData: LiveData>> - get() = _requestLiveData + : VectorViewModel(initialState) { init { session.rx().liveCrossSigningInfo(session.myUserId) @@ -81,6 +68,9 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat } } + // Storage when password is required + private var _pendingSession: String? = null + @AssistedInject.Factory interface Factory { fun create(initialState: CrossSigningSettingsViewState): CrossSigningSettingsViewModel @@ -89,26 +79,37 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat override fun handle(action: CrossSigningAction) { when (action) { is CrossSigningAction.InitializeCrossSigning -> { - initializeCrossSigning(action.auth?.copy(user = session.myUserId)) + initializeCrossSigning(null) } - } + is CrossSigningAction.PasswordEntered -> { + initializeCrossSigning(UserPasswordAuth( + session = _pendingSession, + user = session.myUserId, + password = action.password + )) + } + }.exhaustive } private fun initializeCrossSigning(auth: UserPasswordAuth?) { + _pendingSession = null + setState { copy(isUploadingKeys = true) } session.getCrossSigningService().initializeCrossSigning(auth, object : MatrixCallback { override fun onSuccess(data: Unit) { + _pendingSession = null + setState { copy(isUploadingKeys = false) } } override fun onFailure(failure: Throwable) { - if (failure is Failure.OtherServerError - && failure.httpCode == 401 - ) { + _pendingSession = null + + if (failure is Failure.OtherServerError && failure.httpCode == 401) { try { MoshiProvider.providesMoshi() .adapter(RegistrationFlowResponse::class.java) @@ -118,23 +119,23 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat }?.let { flowResponse -> // Retry with authentication if (flowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } == true) { - _requestLiveData.postValue(LiveEvent(Success(CrossSigningAction.RequestPasswordAuth(flowResponse.session ?: "")))) + _pendingSession = flowResponse.session ?: "" + _viewEvents.post(CrossSigningSettingsViewEvents.RequestPassword) return } else { - _requestLiveData.postValue(LiveEvent(Fail(Throwable("You cannot do that from mobile")))) // can't do this from here + _viewEvents.post(CrossSigningSettingsViewEvents.Failure(Throwable("You cannot do that from mobile"))) + + setState { + copy(isUploadingKeys = false) + } return } } } - when (failure) { - is Failure.ServerError -> { - _requestLiveData.postValue(LiveEvent(Fail(Throwable(failure.error.message)))) - } - else -> { - _requestLiveData.postValue(LiveEvent(Fail(failure))) - } - } + + _viewEvents.post(CrossSigningSettingsViewEvents.Failure(failure)) + setState { copy(isUploadingKeys = false) } From c8ff8d3c9e76e7131eb260c4af463e8dc52919ce Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 18:59:31 +0100 Subject: [PATCH 17/28] Convert to ViewEvents -> DeviceListBottomSheetViewModel --- .../devices/DeviceListBottomSheet.kt | 26 +++++++---------- .../DeviceListBottomSheetViewEvents.kt | 29 +++++++++++++++++++ .../devices/DeviceListBottomSheetViewModel.kt | 20 +++---------- 3 files changed, 43 insertions(+), 32 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewEvents.kt diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheet.kt index dc8ed66fb8..3f21aa3168 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheet.kt @@ -21,15 +21,13 @@ import android.os.Bundle import android.view.KeyEvent import androidx.fragment.app.Fragment import com.airbnb.mvrx.MvRx -import com.airbnb.mvrx.Success 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.extensions.commitTransaction -import im.vector.riotx.core.extensions.observeEvent +import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment -import im.vector.riotx.features.crypto.verification.VerificationAction import im.vector.riotx.features.crypto.verification.VerificationBottomSheet import javax.inject.Inject import kotlin.reflect.KClass @@ -48,20 +46,16 @@ class DeviceListBottomSheet : VectorBaseBottomSheetDialogFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - viewModel.requestLiveData.observeEvent(this) { async -> - when (async) { - is Success -> { - when (val action = async.invoke()) { - is VerificationAction.StartSASVerification -> { - VerificationBottomSheet.withArgs( - roomId = null, - otherUserId = action.otherUserId, - transactionId = action.pendingRequestTransactionId - ).show(requireActivity().supportFragmentManager, "REQPOP") - } - } + viewModel.observeViewEvents { + when (it) { + is DeviceListBottomSheetViewEvents.Verify -> { + VerificationBottomSheet.withArgs( + roomId = null, + otherUserId = it.userId, + transactionId = it.txID + ).show(requireActivity().supportFragmentManager, "REQPOP") } - } + }.exhaustive } } diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewEvents.kt new file mode 100644 index 0000000000..6d7348577e --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewEvents.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 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.roommemberprofile.devices + +import im.vector.riotx.core.platform.VectorViewEvents + +/** + * Transient events for device list screen + */ +sealed class DeviceListBottomSheetViewEvents : VectorViewEvents { + // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() + // data class Failure(val throwable: Throwable) : DeviceListBottomSheetViewEvents() + + data class Verify(val userId: String, val txID: String) : DeviceListBottomSheetViewEvents() +} diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt index 667c3b6cdc..6d37cbbd43 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt @@ -16,14 +16,11 @@ */ package im.vector.riotx.features.roommemberprofile.devices -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory -import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject @@ -36,11 +33,7 @@ import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo import im.vector.matrix.rx.rx import im.vector.riotx.core.di.HasScreenInjector import im.vector.riotx.core.platform.EmptyAction -import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.VectorViewModel -import im.vector.riotx.core.resources.StringProvider -import im.vector.riotx.core.utils.LiveEvent -import im.vector.riotx.features.crypto.verification.VerificationAction data class DeviceListViewState( val userItem: MatrixItem? = null, @@ -52,14 +45,8 @@ data class DeviceListViewState( class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted private val initialState: DeviceListViewState, @Assisted private val userId: String, - private val stringProvider: StringProvider, private val session: Session) - : VectorViewModel(initialState) { - - // Can be used for several actions, for a one shot result - private val _requestLiveData = MutableLiveData>>() - val requestLiveData: LiveData>> - get() = _requestLiveData + : VectorViewModel(initialState) { @AssistedInject.Factory interface Factory { @@ -67,7 +54,6 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva } init { - session.rx().liveUserCryptoDevices(userId) .execute { copy(cryptoDevices = it).also { @@ -93,15 +79,17 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva } } + // TODO Use handle() fun selectDevice(device: CryptoDeviceInfo?) { setState { copy(selectedDevice = device) } } + // TODO Use handle() fun manuallyVerify(device: CryptoDeviceInfo) { session.getVerificationService().beginKeyVerification(VerificationMethod.SAS, userId, device.deviceId, null)?.let { txID -> - _requestLiveData.postValue(LiveEvent(Success(VerificationAction.StartSASVerification(userId, txID)))) + _viewEvents.post(DeviceListBottomSheetViewEvents.Verify(userId, txID)) } } From 0dd3894a4984d3c57fefc29a3073eaaf11e7b4e4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 19:20:02 +0100 Subject: [PATCH 18/28] Use handle() pattern --- .../devices/DeviceListAction.kt | 30 +++++++++++++++++ .../devices/DeviceListBottomSheet.kt | 2 +- .../devices/DeviceListBottomSheetViewModel.kt | 32 +++++++++++++------ .../devices/DeviceListFragment.kt | 2 +- .../devices/DeviceTrustInfoActionFragment.kt | 2 +- 5 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListAction.kt diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListAction.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListAction.kt new file mode 100644 index 0000000000..f298985120 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListAction.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 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.roommemberprofile.devices + +import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo +import im.vector.riotx.core.platform.VectorViewModelAction + +sealed class DeviceListAction : VectorViewModelAction { + // TODO Valere, this is not used? + object Refresh : DeviceListAction() + + data class SelectDevice(val device: CryptoDeviceInfo) : DeviceListAction() + object DeselectDevice : DeviceListAction() + + data class ManuallyVerify(val deviceId: String) : DeviceListAction() +} diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheet.kt index 3f21aa3168..591b014c72 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheet.kt @@ -63,7 +63,7 @@ class DeviceListBottomSheet : VectorBaseBottomSheetDialogFragment() { withState(viewModel) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (it.selectedDevice != null) { - viewModel.selectDevice(null) + viewModel.handle(DeviceListAction.DeselectDevice) return@withState true } else { return@withState false diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt index 6d37cbbd43..6c3b52b00b 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt @@ -32,7 +32,7 @@ import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo import im.vector.matrix.rx.rx import im.vector.riotx.core.di.HasScreenInjector -import im.vector.riotx.core.platform.EmptyAction +import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorViewModel data class DeviceListViewState( @@ -46,7 +46,7 @@ data class DeviceListViewState( class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted private val initialState: DeviceListViewState, @Assisted private val userId: String, private val session: Session) - : VectorViewModel(initialState) { + : VectorViewModel(initialState) { @AssistedInject.Factory interface Factory { @@ -67,6 +67,16 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva } } + override fun handle(action: DeviceListAction) { + when (action) { + is DeviceListAction.Refresh -> refreshSelectedId() + is DeviceListAction.SelectDevice -> selectDevice(action) + is DeviceListAction.DeselectDevice -> deselectDevice() + is DeviceListAction.ManuallyVerify -> manuallyVerify(action) + }.exhaustive + } + + // TODO Valere: not used? private fun refreshSelectedId() = withState { state -> if (state.selectedDevice != null) { state.cryptoDevices.invoke()?.firstOrNull { state.selectedDevice.deviceId == it.deviceId }?.let { @@ -79,22 +89,24 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva } } - // TODO Use handle() - fun selectDevice(device: CryptoDeviceInfo?) { + private fun selectDevice(action: DeviceListAction.SelectDevice) { setState { - copy(selectedDevice = device) + copy(selectedDevice = action.device) } } - // TODO Use handle() - fun manuallyVerify(device: CryptoDeviceInfo) { - session.getVerificationService().beginKeyVerification(VerificationMethod.SAS, userId, device.deviceId, null)?.let { txID -> + private fun deselectDevice() { + setState { + copy(selectedDevice = null) + } + } + + private fun manuallyVerify(action: DeviceListAction.ManuallyVerify) { + session.getVerificationService().beginKeyVerification(VerificationMethod.SAS, userId, action.deviceId, null)?.let { txID -> _viewEvents.post(DeviceListBottomSheetViewEvents.Verify(userId, txID)) } } - override fun handle(action: EmptyAction) {} - companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: DeviceListViewState): DeviceListBottomSheetViewModel? { diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListFragment.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListFragment.kt index c598d051f7..93c51b2008 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListFragment.kt @@ -62,6 +62,6 @@ class DeviceListFragment @Inject constructor( } override fun onDeviceSelected(device: CryptoDeviceInfo) { - viewModel.selectDevice(device) + viewModel.handle(DeviceListAction.SelectDevice(device)) } } diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt index 6c9de742bc..d955e4c9dc 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt @@ -62,6 +62,6 @@ class DeviceTrustInfoActionFragment @Inject constructor( } override fun onVerifyManually(device: CryptoDeviceInfo) { - viewModel.manuallyVerify(device) + viewModel.handle(DeviceListAction.ManuallyVerify(device.deviceId)) } } From 0338535efa842bf45cd7802b509a54a3a19b556c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 19:27:18 +0100 Subject: [PATCH 19/28] Convert to ViewEvents -> RoomDetailViewModel part 1 --- .../riotx/features/home/room/detail/RoomDetailFragment.kt | 5 +---- .../riotx/features/home/room/detail/RoomDetailViewEvents.kt | 2 ++ .../riotx/features/home/room/detail/RoomDetailViewModel.kt | 4 ---- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 7ec6f184ff..92cc86db2c 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -255,10 +255,6 @@ class RoomDetailFragment @Inject constructor( roomDetailViewModel.subscribe { renderState(it) } roomDetailViewModel.sendMessageResultLiveData.observeEvent(viewLifecycleOwner) { renderSendMessageResult(it) } - roomDetailViewModel.nonBlockingPopAlert.observeEvent(this) { pair -> - val message = getString(pair.first, *pair.second.toTypedArray()) - showSnackWithMessage(message, Snackbar.LENGTH_LONG) - } sharedActionViewModel .observe() .subscribe { @@ -313,6 +309,7 @@ class RoomDetailFragment @Inject constructor( is RoomDetailViewEvents.OnNewTimelineEvents -> scrollOnNewMessageCallback.addNewTimelineEventIds(it.eventIds) is RoomDetailViewEvents.ActionSuccess -> displayRoomDetailActionSuccess(it) is RoomDetailViewEvents.ActionFailure -> displayRoomDetailActionFailure(it) + is RoomDetailViewEvents.ShowMessage -> showSnackWithMessage(it.message, Snackbar.LENGTH_LONG) }.exhaustive } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt index 13e77d1974..96ca7bf24e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt @@ -27,4 +27,6 @@ sealed class RoomDetailViewEvents : VectorViewEvents { data class ActionSuccess(val action: RoomDetailAction) : RoomDetailViewEvents() data class ActionFailure(val action: RoomDetailAction, val throwable: Throwable) : RoomDetailViewEvents() + + data class ShowMessage(val message: String) : RoomDetailViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index fda6e44771..f42baff59e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -314,10 +314,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } // TODO Cleanup this and use ViewEvents - private val _nonBlockingPopAlert = MutableLiveData>>>() - val nonBlockingPopAlert: LiveData>>> - get() = _nonBlockingPopAlert - private val _sendMessageResultLiveData = MutableLiveData>() val sendMessageResultLiveData: LiveData> get() = _sendMessageResultLiveData From bdb1f850b2f8dd208273aef51c11578853d98585 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 19:37:30 +0100 Subject: [PATCH 20/28] Convert to ViewEvents -> RoomDetailViewModel part 2 --- .../home/room/detail/RoomDetailFragment.kt | 20 +++---- .../home/room/detail/RoomDetailViewEvents.kt | 13 ++++ .../home/room/detail/RoomDetailViewModel.kt | 60 +++++++++---------- .../home/room/detail/SendMessageResult.kt | 31 ---------- 4 files changed, 51 insertions(+), 73 deletions(-) delete mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/detail/SendMessageResult.kt diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 92cc86db2c..9ef92a345b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -253,7 +253,6 @@ class RoomDetailFragment @Inject constructor( navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId) } roomDetailViewModel.subscribe { renderState(it) } - roomDetailViewModel.sendMessageResultLiveData.observeEvent(viewLifecycleOwner) { renderSendMessageResult(it) } sharedActionViewModel .observe() @@ -310,6 +309,7 @@ class RoomDetailFragment @Inject constructor( is RoomDetailViewEvents.ActionSuccess -> displayRoomDetailActionSuccess(it) is RoomDetailViewEvents.ActionFailure -> displayRoomDetailActionFailure(it) is RoomDetailViewEvents.ShowMessage -> showSnackWithMessage(it.message, Snackbar.LENGTH_LONG) + is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it) }.exhaustive } } @@ -734,31 +734,31 @@ class RoomDetailFragment @Inject constructor( } } - private fun renderSendMessageResult(sendMessageResult: SendMessageResult) { + private fun renderSendMessageResult(sendMessageResult: RoomDetailViewEvents.SendMessageResult) { when (sendMessageResult) { - is SendMessageResult.MessageSent -> { + is RoomDetailViewEvents.MessageSent -> { updateComposerText("") } - is SendMessageResult.SlashCommandHandled -> { + is RoomDetailViewEvents.SlashCommandHandled -> { sendMessageResult.messageRes?.let { showSnackWithMessage(getString(it)) } updateComposerText("") } - is SendMessageResult.SlashCommandError -> { + is RoomDetailViewEvents.SlashCommandError -> { displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command)) } - is SendMessageResult.SlashCommandUnknown -> { + is RoomDetailViewEvents.SlashCommandUnknown -> { displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command)) } - is SendMessageResult.SlashCommandResultOk -> { + is RoomDetailViewEvents.SlashCommandResultOk -> { updateComposerText("") } - is SendMessageResult.SlashCommandResultError -> { + is RoomDetailViewEvents.SlashCommandResultError -> { displayCommandError(sendMessageResult.throwable.localizedMessage) } - is SendMessageResult.SlashCommandNotImplemented -> { + is RoomDetailViewEvents.SlashCommandNotImplemented -> { displayCommandError(getString(R.string.not_implemented)) } - } + } // .exhaustive lockSendButton = false } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt index 96ca7bf24e..63f3cdded9 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt @@ -16,7 +16,9 @@ package im.vector.riotx.features.home.room.detail +import androidx.annotation.StringRes import im.vector.riotx.core.platform.VectorViewEvents +import im.vector.riotx.features.command.Command /** * Transient events for RoomDetail @@ -29,4 +31,15 @@ sealed class RoomDetailViewEvents : VectorViewEvents { data class ActionFailure(val action: RoomDetailAction, val throwable: Throwable) : RoomDetailViewEvents() data class ShowMessage(val message: String) : RoomDetailViewEvents() + + abstract class SendMessageResult : RoomDetailViewEvents() + + object MessageSent : SendMessageResult() + class SlashCommandError(val command: Command) : SendMessageResult() + class SlashCommandUnknown(val command: String) : SendMessageResult() + data class SlashCommandHandled(@StringRes val messageRes: Int? = null) : SendMessageResult() + object SlashCommandResultOk : SendMessageResult() + class SlashCommandResultError(val throwable: Throwable) : SendMessageResult() + // TODO Remove + object SlashCommandNotImplemented : SendMessageResult() } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index f42baff59e..50422d9199 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -314,10 +314,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } // TODO Cleanup this and use ViewEvents - private val _sendMessageResultLiveData = MutableLiveData>() - val sendMessageResultLiveData: LiveData> - get() = _sendMessageResultLiveData - private val _navigateToEvent = MutableLiveData>() val navigateToEvent: LiveData> get() = _navigateToEvent @@ -349,17 +345,17 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro is ParsedCommand.ErrorNotACommand -> { // Send the text message to the room room.sendTextMessage(action.text, autoMarkdown = action.autoMarkdown) - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.MessageSent) + _viewEvents.post(RoomDetailViewEvents.MessageSent) popDraft() } is ParsedCommand.ErrorSyntax -> { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandError(slashCommandResult.command)) + _viewEvents.post(RoomDetailViewEvents.SlashCommandError(slashCommandResult.command)) } is ParsedCommand.ErrorEmptySlashCommand -> { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandUnknown("/")) + _viewEvents.post(RoomDetailViewEvents.SlashCommandUnknown("/")) } is ParsedCommand.ErrorUnknownSlashCommand -> { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandUnknown(slashCommandResult.slashCommand)) + _viewEvents.post(RoomDetailViewEvents.SlashCommandUnknown(slashCommandResult.slashCommand)) } is ParsedCommand.Invite -> { handleInviteSlashCommand(slashCommandResult) @@ -367,55 +363,55 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } is ParsedCommand.SetUserPowerLevel -> { // TODO - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented) + _viewEvents.post(RoomDetailViewEvents.SlashCommandNotImplemented) } is ParsedCommand.ClearScalarToken -> { // TODO - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented) + _viewEvents.post(RoomDetailViewEvents.SlashCommandNotImplemented) } is ParsedCommand.SetMarkdown -> { vectorPreferences.setMarkdownEnabled(slashCommandResult.enable) - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled( + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled( if (slashCommandResult.enable) R.string.markdown_has_been_enabled else R.string.markdown_has_been_disabled)) popDraft() } is ParsedCommand.UnbanUser -> { // TODO - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented) + _viewEvents.post(RoomDetailViewEvents.SlashCommandNotImplemented) } is ParsedCommand.BanUser -> { // TODO - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented) + _viewEvents.post(RoomDetailViewEvents.SlashCommandNotImplemented) } is ParsedCommand.KickUser -> { // TODO - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented) + _viewEvents.post(RoomDetailViewEvents.SlashCommandNotImplemented) } is ParsedCommand.JoinRoom -> { // TODO - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented) + _viewEvents.post(RoomDetailViewEvents.SlashCommandNotImplemented) } is ParsedCommand.PartRoom -> { // TODO - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented) + _viewEvents.post(RoomDetailViewEvents.SlashCommandNotImplemented) } is ParsedCommand.SendEmote -> { room.sendTextMessage(slashCommandResult.message, msgType = MessageType.MSGTYPE_EMOTE) - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled()) + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) popDraft() } is ParsedCommand.SendRainbow -> { slashCommandResult.message.toString().let { room.sendFormattedTextMessage(it, rainbowGenerator.generate(it)) } - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled()) + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) popDraft() } is ParsedCommand.SendRainbowEmote -> { slashCommandResult.message.toString().let { room.sendFormattedTextMessage(it, rainbowGenerator.generate(it), MessageType.MSGTYPE_EMOTE) } - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled()) + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) popDraft() } is ParsedCommand.SendSpoiler -> { @@ -423,7 +419,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro "[${stringProvider.getString(R.string.spoiler)}](${slashCommandResult.message})", "${slashCommandResult.message}" ) - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled()) + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) popDraft() } is ParsedCommand.SendShrug -> { @@ -435,12 +431,12 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } } room.sendTextMessage(sequence) - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled()) + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) popDraft() } is ParsedCommand.VerifyUser -> { session.getVerificationService().requestKeyVerificationInDMs(supportedVerificationMethods, slashCommandResult.userId, room.roomId) - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled()) + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) popDraft() } is ParsedCommand.ChangeTopic -> { @@ -449,7 +445,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } is ParsedCommand.ChangeDisplayName -> { // TODO - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented) + _viewEvents.post(RoomDetailViewEvents.SlashCommandNotImplemented) } }.exhaustive } @@ -476,7 +472,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro Timber.w("Same message content, do not send edition") } } - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.MessageSent) + _viewEvents.post(RoomDetailViewEvents.MessageSent) popDraft() } is SendMode.QUOTE -> { @@ -499,13 +495,13 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } else { room.sendFormattedTextMessage(finalText, htmlText) } - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.MessageSent) + _viewEvents.post(RoomDetailViewEvents.MessageSent) popDraft() } is SendMode.REPLY -> { state.sendMode.timelineEvent.let { room.replyToMessage(it, action.text.toString(), action.autoMarkdown) - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.MessageSent) + _viewEvents.post(RoomDetailViewEvents.MessageSent) popDraft() } } @@ -538,29 +534,29 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } private fun handleChangeTopicSlashCommand(changeTopic: ParsedCommand.ChangeTopic) { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled()) + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) room.updateTopic(changeTopic.topic, object : MatrixCallback { override fun onSuccess(data: Unit) { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandResultOk) + _viewEvents.post(RoomDetailViewEvents.SlashCommandResultOk) } override fun onFailure(failure: Throwable) { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandResultError(failure)) + _viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure)) } }) } private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled()) + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) room.invite(invite.userId, invite.reason, object : MatrixCallback { override fun onSuccess(data: Unit) { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandResultOk) + _viewEvents.post(RoomDetailViewEvents.SlashCommandResultOk) } override fun onFailure(failure: Throwable) { - _sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandResultError(failure)) + _viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure)) } }) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/SendMessageResult.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/SendMessageResult.kt deleted file mode 100644 index 9f8d7304f5..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/SendMessageResult.kt +++ /dev/null @@ -1,31 +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.features.home.room.detail - -import androidx.annotation.StringRes -import im.vector.riotx.features.command.Command - -sealed class SendMessageResult { - object MessageSent : SendMessageResult() - class SlashCommandError(val command: Command) : SendMessageResult() - class SlashCommandUnknown(val command: String) : SendMessageResult() - data class SlashCommandHandled(@StringRes val messageRes: Int? = null) : SendMessageResult() - object SlashCommandResultOk : SendMessageResult() - class SlashCommandResultError(val throwable: Throwable) : SendMessageResult() - // TODO Remove - object SlashCommandNotImplemented : SendMessageResult() -} From 27e217fce51648a1ab18bcf129b58e33dae64d02 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 19:41:23 +0100 Subject: [PATCH 21/28] Convert to ViewEvents -> RoomDetailViewModel part 3 --- .../home/room/detail/RoomDetailFragment.kt | 21 ++++++++++--------- .../home/room/detail/RoomDetailViewEvents.kt | 2 ++ .../home/room/detail/RoomDetailViewModel.kt | 6 +----- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 9ef92a345b..620f980ada 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -261,16 +261,6 @@ class RoomDetailFragment @Inject constructor( } .disposeOnDestroyView() - roomDetailViewModel.navigateToEvent.observeEvent(this) { - val scrollPosition = timelineEventController.searchPositionOfEvent(it) - if (scrollPosition == null) { - scrollOnHighlightedEventCallback.scheduleScrollTo(it) - } else { - recyclerView.stopScroll() - layoutManager.scrollToPosition(scrollPosition) - } - } - roomDetailViewModel.fileTooBigEvent.observeEvent(this) { displayFileTooBigWarning(it) } @@ -309,6 +299,7 @@ class RoomDetailFragment @Inject constructor( is RoomDetailViewEvents.ActionSuccess -> displayRoomDetailActionSuccess(it) is RoomDetailViewEvents.ActionFailure -> displayRoomDetailActionFailure(it) is RoomDetailViewEvents.ShowMessage -> showSnackWithMessage(it.message, Snackbar.LENGTH_LONG) + is RoomDetailViewEvents.NavigateToEvent -> navigateToEvent(it) is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it) }.exhaustive } @@ -364,6 +355,16 @@ class RoomDetailFragment @Inject constructor( jumpToReadMarkerView.callback = this } + private fun navigateToEvent(action: RoomDetailViewEvents.NavigateToEvent) { + val scrollPosition = timelineEventController.searchPositionOfEvent(action.eventId) + if (scrollPosition == null) { + scrollOnHighlightedEventCallback.scheduleScrollTo(action.eventId) + } else { + recyclerView.stopScroll() + layoutManager.scrollToPosition(scrollPosition) + } + } + private fun displayFileTooBigWarning(error: FileTooBigError) { AlertDialog.Builder(requireActivity()) .setTitle(R.string.dialog_title_error) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt index 63f3cdded9..62a9e324d1 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt @@ -32,6 +32,8 @@ sealed class RoomDetailViewEvents : VectorViewEvents { data class ShowMessage(val message: String) : RoomDetailViewEvents() + data class NavigateToEvent(val eventId: String) : RoomDetailViewEvents() + abstract class SendMessageResult : RoomDetailViewEvents() object MessageSent : SendMessageResult() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 50422d9199..5237679b0c 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -314,10 +314,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } // TODO Cleanup this and use ViewEvents - private val _navigateToEvent = MutableLiveData>() - val navigateToEvent: LiveData> - get() = _navigateToEvent - private val _fileTooBigEvent = MutableLiveData>() val fileTooBigEvent: LiveData> get() = _fileTooBigEvent @@ -735,7 +731,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro if (action.highlight) { setState { copy(highlightedEventId = correctedEventId) } } - _navigateToEvent.postLiveEvent(correctedEventId) + _viewEvents.post(RoomDetailViewEvents.NavigateToEvent(correctedEventId)) } private fun handleResendEvent(action: RoomDetailAction.ResendMessage) { From 84e1169525d5e7a9cec9ce881bf53d4db1fcd3de Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 19:45:54 +0100 Subject: [PATCH 22/28] Convert to ViewEvents -> RoomDetailViewModel part 4 --- .../home/room/detail/FileTooBigError.kt | 23 ------------------- .../home/room/detail/RoomDetailFragment.kt | 13 ++++------- .../home/room/detail/RoomDetailViewEvents.kt | 6 +++++ .../home/room/detail/RoomDetailViewModel.kt | 11 ++++----- 4 files changed, 16 insertions(+), 37 deletions(-) delete mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/detail/FileTooBigError.kt diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/FileTooBigError.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/FileTooBigError.kt deleted file mode 100644 index 0f9bfebb47..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/FileTooBigError.kt +++ /dev/null @@ -1,23 +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.features.home.room.detail - -data class FileTooBigError( - val filename: String, - val fileSizeInBytes: Long, - val homeServerLimitInBytes: Long -) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 620f980ada..61ea7da608 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -261,10 +261,6 @@ class RoomDetailFragment @Inject constructor( } .disposeOnDestroyView() - roomDetailViewModel.fileTooBigEvent.observeEvent(this) { - displayFileTooBigWarning(it) - } - roomDetailViewModel.selectSubscribe(this, RoomDetailViewState::tombstoneEventHandling, uniqueOnly("tombstoneEventHandling")) { renderTombstoneEventHandling(it) } @@ -300,6 +296,7 @@ class RoomDetailFragment @Inject constructor( is RoomDetailViewEvents.ActionFailure -> displayRoomDetailActionFailure(it) is RoomDetailViewEvents.ShowMessage -> showSnackWithMessage(it.message, Snackbar.LENGTH_LONG) is RoomDetailViewEvents.NavigateToEvent -> navigateToEvent(it) + is RoomDetailViewEvents.FileTooBigError -> displayFileTooBigError(it) is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it) }.exhaustive } @@ -365,13 +362,13 @@ class RoomDetailFragment @Inject constructor( } } - private fun displayFileTooBigWarning(error: FileTooBigError) { + private fun displayFileTooBigError(action: RoomDetailViewEvents.FileTooBigError) { AlertDialog.Builder(requireActivity()) .setTitle(R.string.dialog_title_error) .setMessage(getString(R.string.error_file_too_big, - error.filename, - TextUtils.formatFileSize(requireContext(), error.fileSizeInBytes), - TextUtils.formatFileSize(requireContext(), error.homeServerLimitInBytes) + action.filename, + TextUtils.formatFileSize(requireContext(), action.fileSizeInBytes), + TextUtils.formatFileSize(requireContext(), action.homeServerLimitInBytes) )) .setPositiveButton(R.string.ok, null) .show() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt index 62a9e324d1..f3c8333554 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt @@ -34,6 +34,12 @@ sealed class RoomDetailViewEvents : VectorViewEvents { data class NavigateToEvent(val eventId: String) : RoomDetailViewEvents() + data class FileTooBigError( + val filename: String, + val fileSizeInBytes: Long, + val homeServerLimitInBytes: Long + ) : RoomDetailViewEvents() + abstract class SendMessageResult : RoomDetailViewEvents() object MessageSent : SendMessageResult() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 5237679b0c..ef3afa8272 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -314,10 +314,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } // TODO Cleanup this and use ViewEvents - private val _fileTooBigEvent = MutableLiveData>() - val fileTooBigEvent: LiveData> - get() = _fileTooBigEvent - private val _downloadedFileEvent = MutableLiveData>() val downloadedFileEvent: LiveData> get() = _downloadedFileEvent @@ -589,8 +585,11 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } else { when (val tooBigFile = attachments.find { it.size > maxUploadFileSize }) { null -> room.sendMedias(attachments) - else -> _fileTooBigEvent.postValue(LiveEvent(FileTooBigError(tooBigFile.name - ?: tooBigFile.path, tooBigFile.size, maxUploadFileSize))) + else -> _viewEvents.post(RoomDetailViewEvents.FileTooBigError( + tooBigFile.name ?: tooBigFile.path, + tooBigFile.size, + maxUploadFileSize + )) } } } From abeb741cad9c35af7fba5594c5937d7910efb52b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 19:50:15 +0100 Subject: [PATCH 23/28] Convert to ViewEvents -> RoomDetailViewModel part 5 --- .../home/room/detail/DownloadFileState.kt | 25 ------------------- .../home/room/detail/RoomDetailFragment.kt | 22 ++++++++-------- .../home/room/detail/RoomDetailViewEvents.kt | 7 ++++++ .../home/room/detail/RoomDetailViewModel.kt | 13 ++-------- 4 files changed, 20 insertions(+), 47 deletions(-) delete mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/detail/DownloadFileState.kt diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/DownloadFileState.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/DownloadFileState.kt deleted file mode 100644 index 717c59aade..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/DownloadFileState.kt +++ /dev/null @@ -1,25 +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.features.home.room.detail - -import java.io.File - -data class DownloadFileState( - val mimeType: String, - val file: File?, - val throwable: Throwable? - ) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 61ea7da608..9e4d7d8163 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -89,7 +89,6 @@ import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.extensions.hideKeyboard -import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.extensions.setTextOrHide import im.vector.riotx.core.extensions.showKeyboard import im.vector.riotx.core.files.addEntryToDownloadManager @@ -265,16 +264,6 @@ class RoomDetailFragment @Inject constructor( renderTombstoneEventHandling(it) } - roomDetailViewModel.downloadedFileEvent.observeEvent(this) { downloadFileState -> - val activity = requireActivity() - if (downloadFileState.throwable != null) { - activity.toast(errorFormatter.toHumanReadable(downloadFileState.throwable)) - } else if (downloadFileState.file != null) { - activity.toast(getString(R.string.downloaded_file, downloadFileState.file.path)) - addEntryToDownloadManager(activity, downloadFileState.file, downloadFileState.mimeType) - } - } - roomDetailViewModel.selectSubscribe(RoomDetailViewState::sendMode) { mode -> when (mode) { is SendMode.REGULAR -> renderRegularMode(mode.text) @@ -297,6 +286,7 @@ class RoomDetailFragment @Inject constructor( is RoomDetailViewEvents.ShowMessage -> showSnackWithMessage(it.message, Snackbar.LENGTH_LONG) is RoomDetailViewEvents.NavigateToEvent -> navigateToEvent(it) is RoomDetailViewEvents.FileTooBigError -> displayFileTooBigError(it) + is RoomDetailViewEvents.DownloadFileState -> handleDownloadFileState(it) is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it) }.exhaustive } @@ -374,6 +364,16 @@ class RoomDetailFragment @Inject constructor( .show() } + private fun handleDownloadFileState(action: RoomDetailViewEvents.DownloadFileState) { + val activity = requireActivity() + if (action.throwable != null) { + activity.toast(errorFormatter.toHumanReadable(action.throwable)) + } else if (action.file != null) { + activity.toast(getString(R.string.downloaded_file, action.file.path)) + addEntryToDownloadManager(activity, action.file, action.mimeType) + } + } + private fun setupNotificationView() { notificationAreaView.delegate = object : NotificationAreaView.Delegate { override fun onTombstoneEventClicked(tombstoneEvent: Event) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt index f3c8333554..fcbe7f37c0 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewEvents.kt @@ -19,6 +19,7 @@ package im.vector.riotx.features.home.room.detail import androidx.annotation.StringRes import im.vector.riotx.core.platform.VectorViewEvents import im.vector.riotx.features.command.Command +import java.io.File /** * Transient events for RoomDetail @@ -40,6 +41,12 @@ sealed class RoomDetailViewEvents : VectorViewEvents { val homeServerLimitInBytes: Long ) : RoomDetailViewEvents() + data class DownloadFileState( + val mimeType: String, + val file: File?, + val throwable: Throwable? + ) : RoomDetailViewEvents() + abstract class SendMessageResult : RoomDetailViewEvents() object MessageSent : SendMessageResult() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index ef3afa8272..710c70a948 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -18,8 +18,6 @@ package im.vector.riotx.features.home.room.detail import android.net.Uri import androidx.annotation.IdRes -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success @@ -60,11 +58,9 @@ import im.vector.matrix.rx.rx import im.vector.matrix.rx.unwrap import im.vector.riotx.R import im.vector.riotx.core.extensions.exhaustive -import im.vector.riotx.core.extensions.postLiveEvent import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.core.resources.UserPreferencesProvider -import im.vector.riotx.core.utils.LiveEvent import im.vector.riotx.core.utils.subscribeLogError import im.vector.riotx.features.command.CommandParser import im.vector.riotx.features.command.ParsedCommand @@ -313,11 +309,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } } - // TODO Cleanup this and use ViewEvents - private val _downloadedFileEvent = MutableLiveData>() - val downloadedFileEvent: LiveData> - get() = _downloadedFileEvent - fun isMenuItemVisible(@IdRes itemId: Int) = when (itemId) { R.id.clear_message_queue -> /* For now always disable on production, worker cancellation is not working properly */ @@ -701,7 +692,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro action.messageFileContent.encryptedFileInfo?.toElementToDecrypt(), object : MatrixCallback { override fun onSuccess(data: File) { - _downloadedFileEvent.postLiveEvent(DownloadFileState( + _viewEvents.post(RoomDetailViewEvents.DownloadFileState( action.messageFileContent.getMimeType(), data, null @@ -709,7 +700,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } override fun onFailure(failure: Throwable) { - _downloadedFileEvent.postLiveEvent(DownloadFileState( + _viewEvents.post(RoomDetailViewEvents.DownloadFileState( action.messageFileContent.getMimeType(), null, failure From 5b13be633211ce215680d803b183ca8eaf4bf210 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Feb 2020 19:58:14 +0100 Subject: [PATCH 24/28] Rename --- .../createdirect/CreateDirectRoomKnownUsersFragment.kt | 4 ++-- ...ateDirectViewEvents.kt => CreateDirectRoomViewEvents.kt} | 4 ++-- .../features/createdirect/CreateDirectRoomViewModel.kt | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) rename vector/src/main/java/im/vector/riotx/features/createdirect/{CreateDirectViewEvents.kt => CreateDirectRoomViewEvents.kt} (91%) diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt index 370cac0100..e06df21be5 100644 --- a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt @@ -63,7 +63,7 @@ class CreateDirectRoomKnownUsersFragment @Inject constructor( setupCloseView() viewModel.observeViewEvents { when (it) { - is CreateDirectViewEvents.SelectUserAction -> updateChipsView(it) + is CreateDirectRoomViewEvents.SelectUserAction -> updateChipsView(it) }.exhaustive } viewModel.selectSubscribe(this, CreateDirectRoomViewState::selectedUsers) { @@ -138,7 +138,7 @@ class CreateDirectRoomKnownUsersFragment @Inject constructor( knownUsersController.setData(it) } - private fun updateChipsView(data: CreateDirectViewEvents.SelectUserAction) { + private fun updateChipsView(data: CreateDirectRoomViewEvents.SelectUserAction) { if (data.isAdded) { addChipToGroup(data.user, chipGroup) } else { diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewEvents.kt similarity index 91% rename from vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectViewEvents.kt rename to vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewEvents.kt index 4ef2fcd966..a836e82304 100644 --- a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewEvents.kt @@ -22,7 +22,7 @@ import im.vector.riotx.core.platform.VectorViewEvents /** * Transient events for create direct room screen */ -sealed class CreateDirectViewEvents : VectorViewEvents { +sealed class CreateDirectRoomViewEvents : VectorViewEvents { // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() // data class Failure(val throwable: Throwable) : CreateDirectViewEvents() @@ -30,5 +30,5 @@ sealed class CreateDirectViewEvents : VectorViewEvents { val user: User, val isAdded: Boolean, val index: Int - ) : CreateDirectViewEvents() + ) : CreateDirectRoomViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt index 79bbdb9ffb..b115a623a8 100644 --- a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewModel.kt @@ -41,7 +41,7 @@ private typealias DirectoryUsersSearch = String class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateDirectRoomViewState, private val session: Session) - : VectorViewModel(initialState) { + : VectorViewModel(initialState) { @AssistedInject.Factory interface Factory { @@ -94,7 +94,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted val index = state.selectedUsers.indexOfFirst { it.userId == action.user.userId } val selectedUsers = state.selectedUsers.minus(action.user) setState { copy(selectedUsers = selectedUsers) } - _viewEvents.post(CreateDirectViewEvents.SelectUserAction(action.user, false, index)) + _viewEvents.post(CreateDirectRoomViewEvents.SelectUserAction(action.user, false, index)) } private fun handleSelectUser(action: CreateDirectRoomAction.SelectUser) = withState { state -> @@ -114,7 +114,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted isAddOperation = false } setState { copy(selectedUsers = selectedUsers) } - _viewEvents.post(CreateDirectViewEvents.SelectUserAction(action.user, isAddOperation, changeIndex)) + _viewEvents.post(CreateDirectRoomViewEvents.SelectUserAction(action.user, isAddOperation, changeIndex)) } private fun observeDirectoryUsers() { From 7e362be568d317d54004e323c91f20a2990c170e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 10 Feb 2020 16:10:57 +0100 Subject: [PATCH 25/28] Convert to ViewEvents -> Cleanup after review --- .../riotx/features/createdirect/CreateDirectRoomViewEvents.kt | 3 --- .../crypto/verification/VerificationBottomSheetViewEvents.kt | 3 --- .../im/vector/riotx/features/grouplist/GroupListViewEvents.kt | 3 --- .../riotx/features/roomdirectory/RoomDirectoryViewEvents.kt | 1 - .../features/roommemberprofile/devices/DeviceListAction.kt | 3 --- .../devices/DeviceListBottomSheetViewEvents.kt | 3 --- .../devices/DeviceListBottomSheetViewModel.kt | 2 -- .../settings/crosssigning/CrossSigningSettingsViewEvents.kt | 1 - .../riotx/features/settings/devices/DevicesViewEvents.kt | 1 - .../vector/riotx/features/settings/devices/DevicesViewModel.kt | 1 - .../features/settings/devices/VectorSettingsDevicesFragment.kt | 1 - 11 files changed, 22 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewEvents.kt index a836e82304..168f23c9f7 100644 --- a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomViewEvents.kt @@ -23,9 +23,6 @@ import im.vector.riotx.core.platform.VectorViewEvents * Transient events for create direct room screen */ sealed class CreateDirectRoomViewEvents : VectorViewEvents { - // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() - // data class Failure(val throwable: Throwable) : CreateDirectViewEvents() - data class SelectUserAction( val user: User, val isAdded: Boolean, diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewEvents.kt index 99417c6ca2..5509ecbe16 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewEvents.kt @@ -22,8 +22,5 @@ import im.vector.riotx.core.platform.VectorViewEvents * Transient events for the verification bottom sheet */ sealed class VerificationBottomSheetViewEvents : VectorViewEvents { - // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() - // data class Failure(val throwable: Throwable) : CreateDirectViewEvents() - object Dismiss : VerificationBottomSheetViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewEvents.kt index 92e4a5c6e3..3638934473 100644 --- a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListViewEvents.kt @@ -22,8 +22,5 @@ import im.vector.riotx.core.platform.VectorViewEvents * Transient events for group list screen */ sealed class GroupListViewEvents : VectorViewEvents { - // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() - // data class Failure(val throwable: Throwable) : GroupListViewEvents() - object OpenGroupSummary : GroupListViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewEvents.kt index 2fb46efd81..499e8d390d 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewEvents.kt @@ -22,6 +22,5 @@ import im.vector.riotx.core.platform.VectorViewEvents * Transient events for room directory screen */ sealed class RoomDirectoryViewEvents : VectorViewEvents { - // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() data class Failure(val throwable: Throwable) : RoomDirectoryViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListAction.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListAction.kt index f298985120..58a486c1b6 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListAction.kt @@ -20,9 +20,6 @@ import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo import im.vector.riotx.core.platform.VectorViewModelAction sealed class DeviceListAction : VectorViewModelAction { - // TODO Valere, this is not used? - object Refresh : DeviceListAction() - data class SelectDevice(val device: CryptoDeviceInfo) : DeviceListAction() object DeselectDevice : DeviceListAction() diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewEvents.kt index 6d7348577e..39758671c8 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewEvents.kt @@ -22,8 +22,5 @@ import im.vector.riotx.core.platform.VectorViewEvents * Transient events for device list screen */ sealed class DeviceListBottomSheetViewEvents : VectorViewEvents { - // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() - // data class Failure(val throwable: Throwable) : DeviceListBottomSheetViewEvents() - data class Verify(val userId: String, val txID: String) : DeviceListBottomSheetViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt index 6c3b52b00b..b12ed58a73 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt @@ -69,14 +69,12 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva override fun handle(action: DeviceListAction) { when (action) { - is DeviceListAction.Refresh -> refreshSelectedId() is DeviceListAction.SelectDevice -> selectDevice(action) is DeviceListAction.DeselectDevice -> deselectDevice() is DeviceListAction.ManuallyVerify -> manuallyVerify(action) }.exhaustive } - // TODO Valere: not used? private fun refreshSelectedId() = withState { state -> if (state.selectedDevice != null) { state.cryptoDevices.invoke()?.firstOrNull { state.selectedDevice.deviceId == it.deviceId }?.let { diff --git a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt index 1e93eca41f..b03707b363 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/crosssigning/CrossSigningSettingsViewEvents.kt @@ -22,7 +22,6 @@ import im.vector.riotx.core.platform.VectorViewEvents * Transient events for cross signing settings screen */ sealed class CrossSigningSettingsViewEvents : VectorViewEvents { - // data class Loading(val message: CharSequence? = null) : RoomDirectoryViewEvents() data class Failure(val throwable: Throwable) : CrossSigningSettingsViewEvents() object RequestPassword : CrossSigningSettingsViewEvents() diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewEvents.kt index b5788366f3..075eb2050e 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewEvents.kt @@ -33,7 +33,6 @@ sealed class DevicesViewEvents : VectorViewEvents { data class ShowVerifyDevice( val userId: String, - val deviceId: String, val transactionId: String? ) : DevicesViewEvents() } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewModel.kt index a7a25caed3..333249f3de 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/devices/DevicesViewModel.kt @@ -176,7 +176,6 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic val txID = session.getVerificationService().requestKeyVerification(supportedVerificationMethods, session.myUserId, listOf(action.deviceId)) _viewEvents.post(DevicesViewEvents.ShowVerifyDevice( session.myUserId, - action.deviceId, txID.transactionId )) } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devices/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/devices/VectorSettingsDevicesFragment.kt index 76496fc3de..603b0b6b78 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/devices/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/devices/VectorSettingsDevicesFragment.kt @@ -67,7 +67,6 @@ class VectorSettingsDevicesFragment @Inject constructor( is DevicesViewEvents.RequestPassword -> maybeShowDeleteDeviceWithPasswordDialog() is DevicesViewEvents.PromptRenameDevice -> displayDeviceRenameDialog(it.deviceInfo) is DevicesViewEvents.ShowVerifyDevice -> { - // TODO Valere: We should pass the deviceId here VerificationBottomSheet.withArgs( roomId = null, otherUserId = it.userId, From 2e7fa23ce70b16a83191dc0742d4eac796d5095e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 10 Feb 2020 19:13:35 +0100 Subject: [PATCH 26/28] Fix #980 --- .../android/internal/database/mapper/PushRulesMapper.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt index 26cde21842..a0f644a7cf 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/PushRulesMapper.kt @@ -38,7 +38,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.EventMatch.name, "content.body", pushrule.pattern) + PushCondition(Condition.Kind.EventMatch.value, "content.body", pushrule.pattern) ) ) } @@ -59,7 +59,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.EventMatch.name, "room_id", pushrule.ruleId) + PushCondition(Condition.Kind.EventMatch.value, "room_id", pushrule.ruleId) ) ) } @@ -71,7 +71,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.EventMatch.name, "user_id", pushrule.ruleId) + PushCondition(Condition.Kind.EventMatch.value, "user_id", pushrule.ruleId) ) ) } From d71797319c64206a007557add160acd44a9a654e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 10 Feb 2020 21:40:27 +0100 Subject: [PATCH 27/28] Prepare release 0.15.0 --- CHANGES.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1a373da04c..d083a5f2f5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,6 @@ -Changes in RiotX 0.15.0 (2020-XX-XX) +Changes in RiotX 0.15.0 (2020-02-10) =================================================== -Features ✨: - - - Improvements 🙌: - Improve navigation to the timeline (#789, #862) - Improve network detection. It is now based on the sync request status (#873, #882) @@ -15,12 +12,6 @@ Bugfix 🐛: - Ask for permission before opening the camera (#934) - Encrypt for invited users by default, if the room state allows it (#803) -Translations 🗣: - - - -Build 🧱: - - - Changes in RiotX 0.14.3 (2020-02-03) =================================================== From a7274b9df00ee6a4b27fcff62b3107c73436c76d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 10 Feb 2020 21:41:59 +0100 Subject: [PATCH 28/28] Version++ --- CHANGES.md | 21 +++++++++++++++++++++ vector/build.gradle | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index d083a5f2f5..ce10d8cc9a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,24 @@ +Changes in RiotX 0.16.0 (2020-XX-XX) +=================================================== + +Features ✨: + - + +Improvements 🙌: + - + +Other changes: + - + +Bugfix 🐛: + - + +Translations 🗣: + - + +Build 🧱: + - + Changes in RiotX 0.15.0 (2020-02-10) =================================================== diff --git a/vector/build.gradle b/vector/build.gradle index fca82f935e..0517482904 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -15,7 +15,7 @@ androidExtensions { } ext.versionMajor = 0 -ext.versionMinor = 15 +ext.versionMinor = 16 ext.versionPatch = 0 static def getGitTimestamp() {