diff --git a/CHANGES.md b/CHANGES.md index 63ccaea83a..07eab082d0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,25 @@ -Changes in RiotX 0.6.0 (2019-XX-XX) +Changes in RiotX 0.7.0 (2019-XX-XX) +=================================================== + +Features: + - + +Improvements: + - + +Other changes: + - + +Bugfix: + - + +Translations: + - + +Build: + - + +Changes in RiotX 0.6.0 (2019-09-24) =================================================== Features: @@ -10,14 +31,15 @@ Improvements: - Remove any notification of a redacted event (#563) Other changes: - - + - Fix a few accessibility issues Bugfix: - Fix characters erased from the Search field when the result are coming (#545) - "No connection" banner was displayed by mistake - -Translations: - - + - Leaving community (from another client) has no effect on RiotX (#497) + - Push rules was not retrieved after a clear cache + - m.notice messages trigger push notifications (#238) + - Embiggen messages with multiple emojis also for edited messages (#458) Build: - Fix (again) issue with bad versionCode generated by Buildkite (#553) @@ -26,7 +48,7 @@ Changes in RiotX 0.5.0 (2019-09-17) =================================================== Features: - - Implementation of login to homeserver with SSO + - Implementation of login to homeserver with SSO (#557) - Handle M_CONSENT_NOT_GIVEN error (#64) - Auto configure homeserver and identity server URLs of LoginActivity with a magic link diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Action.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Action.kt index 797830f491..b34d2d0d34 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Action.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/Action.kt @@ -19,77 +19,92 @@ import im.vector.matrix.android.api.pushrules.rest.PushRule import timber.log.Timber -class Action(val type: Type) { - - enum class Type(val value: String) { - NOTIFY("notify"), - DONT_NOTIFY("dont_notify"), - COALESCE("coalesce"), - SET_TWEAK("set_tweak"); - - companion object { - - fun safeValueOf(value: String): Type? { - try { - return valueOf(value) - } catch (e: IllegalArgumentException) { - return null - } - } - } - } - - var tweak_action: String? = null - var stringValue: String? = null - var boolValue: Boolean? = null - - companion object { - fun mapFrom(pushRule: PushRule): List? { - val actions = ArrayList() - pushRule.actions.forEach { actionStrOrObj -> - if (actionStrOrObj is String) { - when (actionStrOrObj) { - Action.Type.NOTIFY.value -> Action(Action.Type.NOTIFY) - Action.Type.DONT_NOTIFY.value -> Action(Action.Type.DONT_NOTIFY) - else -> { - Timber.w("Unsupported action type ${actionStrOrObj}") - null - } - }?.let { - actions.add(it) - } - } else if (actionStrOrObj is Map<*, *>) { - val tweakAction = actionStrOrObj["set_tweak"] as? String - when (tweakAction) { - "sound" -> { - (actionStrOrObj["value"] as? String)?.let { stringValue -> - Action(Action.Type.SET_TWEAK).also { - it.tweak_action = "sound" - it.stringValue = stringValue - actions.add(it) - } - } - } - "highlight" -> { - (actionStrOrObj["value"] as? Boolean)?.let { boolValue -> - Action(Action.Type.SET_TWEAK).also { - it.tweak_action = "highlight" - it.boolValue = boolValue - actions.add(it) - } - } - } - else -> { - Timber.w("Unsupported action type ${actionStrOrObj}") - } - } - } else { - Timber.w("Unsupported action type ${actionStrOrObj}") - return null - } - } - return if (actions.isEmpty()) null else actions - } - } +sealed class Action { + object Notify : Action() + object DoNotNotify : Action() + data class Sound(val sound: String) : Action() + data class Highlight(val highlight: Boolean) : Action() +} + + +private const val ACTION_NOTIFY = "notify" +private const val ACTION_DONT_NOTIFY = "dont_notify" +private const val ACTION_COALESCE = "coalesce" + +// Ref: https://matrix.org/docs/spec/client_server/latest#tweaks +private const val ACTION_OBJECT_SET_TWEAK_KEY = "set_tweak" + +private const val ACTION_OBJECT_SET_TWEAK_VALUE_SOUND = "sound" +private const val ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT = "highlight" + +private const val ACTION_OBJECT_VALUE_KEY = "value" +private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default" + +/** + * Ref: https://matrix.org/docs/spec/client_server/latest#actions + * + * Convert + *
+ * "actions": [
+ *     "notify",
+ *     {
+ *         "set_tweak": "sound",
+ *         "value": "default"
+ *     },
+ *     {
+ *         "set_tweak": "highlight"
+ *     }
+ *   ]
+ *
+ * To
+ * [
+ *     Action.Notify,
+ *     Action.Sound("default"),
+ *     Action.Highlight(true)
+ * ]
+ *
+ * 
+ */ +fun PushRule.getActions(): List { + val result = ArrayList() + + actions.forEach { actionStrOrObj -> + when (actionStrOrObj) { + ACTION_NOTIFY -> Action.Notify + ACTION_DONT_NOTIFY -> Action.DoNotNotify + is Map<*, *> -> { + when (actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]) { + ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> { + (actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue -> + Action.Sound(stringValue) + } + // When the value is not there, default sound (not specified by the spec) + ?: Action.Sound(ACTION_OBJECT_VALUE_VALUE_DEFAULT) + + } + ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT -> { + (actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? Boolean)?.let { boolValue -> + Action.Highlight(boolValue) + } + // When the value is not there, default is true, says the spec + ?: Action.Highlight(true) + } + else -> { + Timber.w("Unsupported set_tweak value ${actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]}") + null + } + } + } + else -> { + Timber.w("Unsupported action type $actionStrOrObj") + null + } + }?.let { + result.add(it) + } + } + + + return result } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt index 05396cb219..c0204d181d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt @@ -25,14 +25,14 @@ interface PushRuleService { /** * Fetch the push rules from the server */ - fun fetchPushRules(scope: String = "global") + fun fetchPushRules(scope: String = RuleScope.GLOBAL) //TODO get push rule set - fun getPushRules(scope: String = "global"): List + fun getPushRules(scope: String = RuleScope.GLOBAL): List //TODO update rule - fun updatePushRuleEnableStatus(kind: String, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable + fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable fun addPushRuleListener(listener: PushRuleListener) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleIds.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleIds.kt index 38a64adf27..cf05e9252d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleIds.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleIds.kt @@ -37,7 +37,7 @@ object RuleIds { // Default Underride Rules const val RULE_ID_CALL = ".m.rule.call" - const val RULE_ID_one_to_one_encrypted_room = ".m.rule.encrypted_room_one_to_one" + const val RULE_ID_ONE_TO_ONE_ENCRYPTED_ROOM = ".m.rule.encrypted_room_one_to_one" const val RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one" const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message" const val RULE_ID_ENCRYPTED = ".m.rule.encrypted" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RulesetKey.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleScope.kt similarity index 78% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RulesetKey.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleScope.kt index 834bdf2add..19aa2a4d43 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RulesetKey.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleScope.kt @@ -15,12 +15,6 @@ */ package im.vector.matrix.android.api.pushrules - -enum class RulesetKey(val value: String) { - CONTENT("content"), - OVERRIDE("override"), - ROOM("room"), - SENDER("sender"), - UNDERRIDE("underride"), - UNKNOWN("") -} \ No newline at end of file +object RuleScope { + const val GLOBAL = "global" +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleSetKey.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleSetKey.kt new file mode 100644 index 0000000000..e8862ad343 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/RuleSetKey.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.api.pushrules + +/** + * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules + */ +enum class RuleSetKey(val value: String) { + CONTENT("content"), + OVERRIDE("override"), + ROOM("room"), + SENDER("sender"), + UNDERRIDE("underride") +} + +/** + * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules-scope-kind-ruleid + */ +typealias RuleKind = RuleSetKey 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 8f69401653..7b71a344a0 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 @@ -71,7 +71,7 @@ data class PushCondition( this.key?.let { SenderNotificationPermissionCondition(it) } } Condition.Kind.UNRECOGNIZE -> { - Timber.e("Unknwon kind $kind") + Timber.e("Unknown kind $kind") null } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt index 3089d83dde..328ca746a6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt @@ -16,12 +16,15 @@ package im.vector.matrix.android.api.session.group.model +import im.vector.matrix.android.api.session.room.model.Membership + /** * This class holds some data of a group. * It can be retrieved through [im.vector.matrix.android.api.session.group.GroupService] */ data class GroupSummary( val groupId: String, + val membership: Membership, val displayName: String = "", val shortDescription: String = "", val avatarUrl: String = "", diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/Pusher.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/Pusher.kt index 7b1fa3bb52..baedce9693 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/Pusher.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/pushers/Pusher.kt @@ -16,9 +16,6 @@ package im.vector.matrix.android.api.session.pushers data class Pusher( - - val userId: String, - val pushKey: String, val kind: String, val appId: String, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt index cdc1c9527e..c707f3c3ef 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/create/CreateRoomParams.kt @@ -20,7 +20,6 @@ import android.util.Patterns import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.MatrixPatterns.isUserId -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType @@ -219,7 +218,7 @@ class CreateRoomParams { * @param ids the participant ids to add. */ fun addParticipantIds(hsConfig: HomeServerConnectionConfig, - credentials: Credentials, + userId: String, ids: List) { for (id in ids) { if (Patterns.EMAIL_ADDRESS.matcher(id).matches() && hsConfig.identityServerUri != null) { @@ -233,7 +232,7 @@ class CreateRoomParams { invite3pids!!.add(pid) } else if (isUserId(id)) { // do not invite oneself - if (credentials.userId != id) { + if (userId != id) { if (null == invitedUserIds) { invitedUserIds = ArrayList() } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt index d5c41769ef..078d016e42 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt @@ -16,14 +16,14 @@ package im.vector.matrix.android.internal.crypto.actions -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore +import im.vector.matrix.android.internal.di.UserId import timber.log.Timber import javax.inject.Inject internal class SetDeviceVerificationAction @Inject constructor(private val cryptoStore: IMXCryptoStore, - private val credentials: Credentials, + @UserId private val userId: String, private val keysBackup: KeysBackup) { fun handle(verificationStatus: Int, deviceId: String, userId: String) { @@ -39,7 +39,7 @@ internal class SetDeviceVerificationAction @Inject constructor(private val crypt device.verified = verificationStatus cryptoStore.storeUserDevice(userId, device) - if (userId == credentials.userId) { + if (userId == this.userId) { // If one of the user's own devices is being marked as verified / unverified, // check the key backup status, since whether or not we use this depends on // whether it has a signature from a verified device diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index 47bf9956b9..c518872d44 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -18,7 +18,6 @@ package im.vector.matrix.android.internal.crypto.algorithms.megolm import android.text.TextUtils -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.crypto.MXCryptoError import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType @@ -40,7 +39,7 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import timber.log.Timber -internal class MXMegolmDecryption(private val credentials: Credentials, +internal class MXMegolmDecryption(private val userId: String, private val olmDevice: MXOlmDevice, private val deviceListManager: DeviceListManager, private val outgoingRoomKeyRequestManager: OutgoingRoomKeyRequestManager, @@ -146,11 +145,11 @@ internal class MXMegolmDecryption(private val credentials: Credentials, val selfMap = HashMap() // TODO Replace this hard coded keys (see OutgoingRoomKeyRequestManager) - selfMap["userId"] = credentials.userId + selfMap["userId"] = userId selfMap["deviceId"] = "*" recipients.add(selfMap) - if (!TextUtils.equals(sender, credentials.userId)) { + if (!TextUtils.equals(sender, userId)) { val senderMap = HashMap() senderMap["userId"] = sender senderMap["deviceId"] = encryptedEventContent.deviceId!! diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt index 11c43649e9..54c412526d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.crypto.algorithms.megolm -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.crypto.DeviceListManager import im.vector.matrix.android.internal.crypto.MXOlmDevice import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequestManager @@ -24,10 +23,11 @@ import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevi import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject -internal class MXMegolmDecryptionFactory @Inject constructor(private val credentials: Credentials, +internal class MXMegolmDecryptionFactory @Inject constructor(@UserId private val userId: String, private val olmDevice: MXOlmDevice, private val deviceListManager: DeviceListManager, private val outgoingRoomKeyRequestManager: OutgoingRoomKeyRequestManager, @@ -39,7 +39,7 @@ internal class MXMegolmDecryptionFactory @Inject constructor(private val credent fun create(): MXMegolmDecryption { return MXMegolmDecryption( - credentials, + userId, olmDevice, deviceListManager, outgoingRoomKeyRequestManager, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryption.kt index ede99e4b94..9433e364cb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryption.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryption.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.crypto.algorithms.olm -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.crypto.MXCryptoError import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.toModel @@ -35,8 +34,8 @@ import timber.log.Timber internal class MXOlmDecryption( // The olm device interface private val olmDevice: MXOlmDevice, - // the matrix credentials - private val credentials: Credentials) + // the matrix userId + private val userId: String) : IMXDecrypting { override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult { @@ -97,9 +96,9 @@ internal class MXOlmDecryption( throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY, reason) } - if (olmPayloadContent.recipient != credentials.userId) { + if (olmPayloadContent.recipient != userId) { Timber.e("## decryptEvent() : Event ${event.eventId}:" + - " Intended recipient ${olmPayloadContent.recipient} does not match our id ${credentials.userId}") + " Intended recipient ${olmPayloadContent.recipient} does not match our id $userId") throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_RECIPIENT, String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient)) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt index afe4b36e97..12937a2b2e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt @@ -16,16 +16,16 @@ package im.vector.matrix.android.internal.crypto.algorithms.olm -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.crypto.MXOlmDevice +import im.vector.matrix.android.internal.di.UserId import javax.inject.Inject internal class MXOlmDecryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice, - private val credentials: Credentials) { + @UserId private val userId: String) { fun create(): MXOlmDecryption { return MXOlmDecryption( olmDevice, - credentials) + userId) } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt index 060b57baa4..eb23f02275 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt @@ -16,11 +16,11 @@ package im.vector.matrix.android.internal.crypto.tasks -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.auth.data.LoginFlowTypes import im.vector.matrix.android.internal.crypto.api.CryptoApi import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceAuth import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceParams +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import javax.inject.Inject @@ -34,7 +34,7 @@ internal interface DeleteDeviceWithUserPasswordTask : Task = RealmList(), - var userIds: RealmList = RealmList() + var displayName: String = "", + var shortDescription: String = "", + var avatarUrl: String = "", + var roomIds: RealmList = RealmList(), + var userIds: RealmList = RealmList() ) : RealmObject() { + private var membershipStr: String = Membership.NONE.name + var membership: Membership + get() { + return Membership.valueOf(membershipStr) + } + set(value) { + membershipStr = value.name + } + companion object } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRulesEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRulesEntity.kt index f504192550..e0acfa49ae 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRulesEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRulesEntity.kt @@ -15,17 +15,24 @@ */ package im.vector.matrix.android.internal.database.model +import im.vector.matrix.android.api.pushrules.RuleKind import io.realm.RealmList import io.realm.RealmObject -import io.realm.annotations.Index internal open class PushRulesEntity( - @Index var userId: String = "", var scope: String = "", - // "content", etc. - var rulesetKey: String = "", var pushRules: RealmList = RealmList() ) : RealmObject() { + + private var kindStr: String = RuleKind.CONTENT.name + var kind: RuleKind + get() { + return RuleKind.valueOf(kindStr) + } + set(value) { + kindStr = value.name + } + companion object } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherEntity.kt index a9d33c86bc..6ec9d4b0de 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PusherEntity.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.database.model import im.vector.matrix.android.api.session.pushers.PusherState import io.realm.RealmObject -import io.realm.annotations.Index //TODO // at java.lang.Thread.run(Thread.java:764) @@ -29,7 +28,6 @@ import io.realm.annotations.Index // at im.vector.matrix.android.internal.session.pushers.AddHttpPusherWorker$doWork$$inlined$fold$lambda$2.execute(AddHttpPusherWorker.kt:70) // at io.realm.Realm.executeTransaction(Realm.java:1493) internal open class PusherEntity( - @Index var userId: String = "", var pushKey: String = "", var kind: String? = null, var appId: String = "", diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt index 33c9d868e1..802bfbeae6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt @@ -23,9 +23,9 @@ import io.realm.Realm import io.realm.RealmQuery import io.realm.kotlin.where -internal fun GroupEntity.Companion.where(realm: Realm, roomId: String): RealmQuery { +internal fun GroupEntity.Companion.where(realm: Realm, groupId: String): RealmQuery { return realm.where() - .equalTo(GroupEntityFields.GROUP_ID, roomId) + .equalTo(GroupEntityFields.GROUP_ID, groupId) } internal fun GroupEntity.Companion.where(realm: Realm, membership: Membership? = null): RealmQuery { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupSummaryEntityQueries.kt index d0351eec54..601da098ca 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupSummaryEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupSummaryEntityQueries.kt @@ -30,3 +30,7 @@ internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupId: String? = return query } +internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupIds: List): RealmQuery { + return realm.where() + .`in`(GroupSummaryEntityFields.GROUP_ID, groupIds.toTypedArray()) +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/PushersQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/PushersQueries.kt index b7f54f17ea..4ecb40a7e1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/PushersQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/PushersQueries.kt @@ -15,6 +15,7 @@ */ package im.vector.matrix.android.internal.database.query +import im.vector.matrix.android.api.pushrules.RuleKind import im.vector.matrix.android.internal.database.model.PushRulesEntity import im.vector.matrix.android.internal.database.model.PushRulesEntityFields import im.vector.matrix.android.internal.database.model.PusherEntity @@ -24,10 +25,8 @@ import io.realm.RealmQuery import io.realm.kotlin.where internal fun PusherEntity.Companion.where(realm: Realm, - userId: String, pushKey: String? = null): RealmQuery { return realm.where() - .equalTo(PusherEntityFields.USER_ID, userId) .apply { if (pushKey != null) { equalTo(PusherEntityFields.PUSH_KEY, pushKey) @@ -36,11 +35,9 @@ internal fun PusherEntity.Companion.where(realm: Realm, } internal fun PushRulesEntity.Companion.where(realm: Realm, - userId: String, scope: String, - ruleSetKey: String): RealmQuery { + kind: RuleKind): RealmQuery { return realm.where() - .equalTo(PushRulesEntityFields.USER_ID, userId) .equalTo(PushRulesEntityFields.SCOPE, scope) - .equalTo(PushRulesEntityFields.RULESET_KEY, ruleSetKey) + .equalTo(PushRulesEntityFields.KIND_STR, kind.name) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt index 82ab72db26..bd7e3a7a5e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt @@ -30,12 +30,18 @@ internal fun isEventRead(monarchy: Monarchy, var isEventRead = false monarchy.doWithRealm { realm -> - val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() ?: return@doWithRealm val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId) ?: return@doWithRealm - val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex ?: Int.MIN_VALUE - val eventToCheckIndex = liveChunk.timelineEvents.find(eventId)?.root?.displayIndex ?: Int.MAX_VALUE + val eventToCheck = liveChunk.timelineEvents.find(eventId)?.root - isEventRead = eventToCheckIndex <= readReceiptIndex + isEventRead = if (eventToCheck?.sender == userId) { + true + } else { + val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() ?: return@doWithRealm + val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex ?: Int.MIN_VALUE + val eventToCheckIndex = eventToCheck?.displayIndex ?: Int.MAX_VALUE + + eventToCheckIndex <= readReceiptIndex + } } return isEventRead diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt index e430329892..81de47948c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt @@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter import im.vector.matrix.android.internal.session.sync.model.UserAccountData import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback +import im.vector.matrix.android.internal.session.sync.model.UserAccountDataPushRules object MoshiProvider { @@ -31,6 +32,7 @@ object MoshiProvider { .add(UriMoshiAdapter()) .add(RuntimeJsonAdapterFactory.of(UserAccountData::class.java, "type", UserAccountDataFallback::class.java) .registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES) + .registerSubtype(UserAccountDataPushRules::class.java, UserAccountData.TYPE_PUSH_RULES) ) .add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java) .registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/StringQualifiers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/StringQualifiers.kt index 8ca81a1dab..0e38618590 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/StringQualifiers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/StringQualifiers.kt @@ -18,6 +18,16 @@ package im.vector.matrix.android.internal.di import javax.inject.Qualifier +/** + * Used to inject the userId + */ @Qualifier @Retention(AnnotationRetention.RUNTIME) -annotation class UserMd5 +internal annotation class UserId + +/** + * Used to inject the md5 of the userId + */ +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +internal annotation class UserMd5 diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConnectivityChecker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConnectivityChecker.kt index 88229db325..be012dd308 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConnectivityChecker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/NetworkConnectivityChecker.kt @@ -20,6 +20,7 @@ import android.content.Context import com.novoda.merlin.Merlin import com.novoda.merlin.MerlinsBeard import im.vector.matrix.android.internal.di.MatrixScope +import im.vector.matrix.android.internal.util.BackgroundDetectionObserver import timber.log.Timber import java.util.* import javax.inject.Inject @@ -27,7 +28,9 @@ import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine @MatrixScope -internal class NetworkConnectivityChecker @Inject constructor(context: Context) { +internal class NetworkConnectivityChecker @Inject constructor(context: Context, + backgroundDetectionObserver: BackgroundDetectionObserver) + : BackgroundDetectionObserver.Listener { private val merlin = Merlin.Builder() .withConnectableCallbacks() @@ -41,7 +44,12 @@ internal class NetworkConnectivityChecker @Inject constructor(context: Context) private set init { + backgroundDetectionObserver.register(this) + } + + override fun onMoveToForeground() { merlin.bind() + merlin.registerDisconnectable { if (hasInternetAccess) { Timber.v("On Disconnect") @@ -64,6 +72,10 @@ internal class NetworkConnectivityChecker @Inject constructor(context: Context) } } + override fun onMoveToBackground() { + merlin.unbind() + } + suspend fun waitUntilConnected() { if (hasInternetAccess) { return diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultFileService.kt index 0f1554ea42..456e7873bb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultFileService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultFileService.kt @@ -20,11 +20,11 @@ import android.content.Context import android.os.Environment import arrow.core.Try import im.vector.matrix.android.api.MatrixCallback -import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments +import im.vector.matrix.android.internal.di.UserMd5 import im.vector.matrix.android.internal.extensions.foldToCallback import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.md5 @@ -40,7 +40,7 @@ import java.io.IOException import javax.inject.Inject internal class DefaultFileService @Inject constructor(private val context: Context, - private val sessionParams: SessionParams, + @UserMd5 private val userMd5: String, private val contentUrlResolver: ContentUrlResolver, private val coroutineDispatchers: MatrixCoroutineDispatchers) : FileService { @@ -105,7 +105,7 @@ internal class DefaultFileService @Inject constructor(private val context: Conte // Create dir tree (MF stands for Matrix File): // /MF/// val tmpFolderRoot = File(context.cacheDir, "MF") - val tmpFolderUser = File(tmpFolderRoot, sessionParams.credentials.userId.md5()) + val tmpFolderUser = File(tmpFolderRoot, userMd5) File(tmpFolderUser, id.md5()) } FileService.DownloadMode.TO_EXPORT -> { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index 180cdb6ea2..a08c7e4ab7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -67,11 +67,18 @@ internal abstract class SessionModule { return sessionParams.credentials } + @JvmStatic + @UserId + @Provides + fun providesUserId(credentials: Credentials): String { + return credentials.userId + } + @JvmStatic @UserMd5 @Provides - fun providesUserMd5(sessionParams: SessionParams): String { - return sessionParams.credentials.userId.md5() + fun providesUserMd5(@UserId userId: String): String { + return userId.md5() } @JvmStatic diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultSaveFilterTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultSaveFilterTask.kt index a5da026aec..8df7426263 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultSaveFilterTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultSaveFilterTask.kt @@ -16,7 +16,7 @@ package im.vector.matrix.android.internal.session.filter -import im.vector.matrix.android.api.auth.data.SessionParams +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import javax.inject.Inject @@ -33,7 +33,7 @@ internal interface SaveFilterTask : Task { } -internal class DefaultSaveFilterTask @Inject constructor(private val sessionParams: SessionParams, +internal class DefaultSaveFilterTask @Inject constructor(@UserId private val userId: String, private val filterAPI: FilterApi, private val filterRepository: FilterRepository ) : SaveFilterTask { @@ -41,7 +41,7 @@ internal class DefaultSaveFilterTask @Inject constructor(private val sessionPara override suspend fun execute(params: SaveFilterTask.Params) { val filterResponse = executeRequest { // TODO auto retry - apiCall = filterAPI.uploadFilter(sessionParams.credentials.userId, params.filter) + apiCall = filterAPI.uploadFilter(userId, params.filter) } filterRepository.storeFilterId(params.filter, filterResponse.filterId) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt index 6964ccf83c..003f6a8c61 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt @@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.session.group import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.internal.database.model.GroupSummaryEntity import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.network.executeRequest @@ -64,8 +65,7 @@ internal class DefaultGetGroupDataTask @Inject constructor( groupSummaryEntity.avatarUrl = groupSummary.profile?.avatarUrl ?: "" val name = groupSummary.profile?.name groupSummaryEntity.displayName = if (name.isNullOrEmpty()) groupId else name - groupSummaryEntity.shortDescription = groupSummary.profile?.shortDescription - ?: "" + groupSummaryEntity.shortDescription = groupSummary.profile?.shortDescription ?: "" val roomIds = groupRooms.rooms.map { it.roomId } groupSummaryEntity.roomIds.clear() @@ -74,8 +74,12 @@ internal class DefaultGetGroupDataTask @Inject constructor( val userIds = groupUsers.users.map { it.userId } groupSummaryEntity.userIds.clear() groupSummaryEntity.userIds.addAll(userIds) + + groupSummaryEntity.membership = when (groupSummary.user?.membership) { + Membership.JOIN.value -> Membership.JOIN + Membership.INVITE.value -> Membership.INVITE + else -> Membership.LEAVE + } } } - - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt index 47905ecc37..12a256e7dc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt @@ -20,35 +20,48 @@ import android.content.Context import androidx.work.ExistingWorkPolicy import androidx.work.WorkManager import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.internal.database.RealmLiveEntityObserver import im.vector.matrix.android.internal.database.model.GroupEntity +import im.vector.matrix.android.internal.database.model.GroupSummaryEntity import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.di.SessionDatabase +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.worker.WorkManagerUtil import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder import im.vector.matrix.android.internal.worker.WorkerParamsFactory import io.realm.OrderedCollectionChangeSet -import io.realm.RealmConfiguration import io.realm.RealmResults import javax.inject.Inject private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER" internal class GroupSummaryUpdater @Inject constructor(private val context: Context, - private val credentials: Credentials, - @SessionDatabase realmConfiguration: RealmConfiguration) - : RealmLiveEntityObserver(realmConfiguration) { + @UserId private val userId: String, + private val monarchy: Monarchy) + : RealmLiveEntityObserver(monarchy.realmConfiguration) { - override val query = Monarchy.Query { GroupEntity.where(it) } + override val query = Monarchy.Query { GroupEntity.where(it) } override fun onChange(results: RealmResults, changeSet: OrderedCollectionChangeSet) { - val newGroupIds = changeSet.insertions + // `insertions` for new groups and `changes` to handle left groups + val modifiedGroupEntity = (changeSet.insertions + changeSet.changes) .asSequence() - .mapNotNull { results[it]?.groupId} - .toList() + .mapNotNull { results[it] } + + fetchGroupsData(modifiedGroupEntity + .filter { it.membership == Membership.JOIN || it.membership == Membership.INVITE } + .map { it.groupId } + .toList()) + + deleteGroups(modifiedGroupEntity + .filter { it.membership == Membership.LEAVE } + .map { it.groupId } + .toList()) + } + + private fun fetchGroupsData(groupIds: List) { + val getGroupDataWorkerParams = GetGroupDataWorker.Params(userId, groupIds) - val getGroupDataWorkerParams = GetGroupDataWorker.Params(credentials.userId, newGroupIds) val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams) val sendWork = matrixOneTimeWorkRequestBuilder() @@ -61,4 +74,15 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont .enqueue() } + /** + * Delete the GroupSummaryEntity of left groups + */ + private fun deleteGroups(groupIds: List) { + monarchy + .writeAsync { realm -> + GroupSummaryEntity.where(realm, groupIds) + .findAll() + .deleteAllFromRealm() + } + } } \ No newline at end of file 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 7cccd0dc3e..fb436c3b21 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 @@ -17,9 +17,10 @@ package im.vector.matrix.android.internal.session.notification import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.MatrixCallback -import im.vector.matrix.android.api.auth.data.SessionParams -import im.vector.matrix.android.api.pushrules.Action import im.vector.matrix.android.api.pushrules.PushRuleService +import im.vector.matrix.android.api.pushrules.RuleKind +import im.vector.matrix.android.api.pushrules.RuleSetKey +import im.vector.matrix.android.api.pushrules.getActions 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.util.Cancelable @@ -35,53 +36,60 @@ import timber.log.Timber import javax.inject.Inject @SessionScope -internal class DefaultPushRuleService @Inject constructor( - private val sessionParams: SessionParams, - private val pushRulesTask: GetPushRulesTask, - private val updatePushRuleEnableStatusTask: UpdatePushRuleEnableStatusTask, - private val taskExecutor: TaskExecutor, - private val monarchy: Monarchy +internal class DefaultPushRuleService @Inject constructor(private val getPushRulesTask: GetPushRulesTask, + private val updatePushRuleEnableStatusTask: UpdatePushRuleEnableStatusTask, + private val taskExecutor: TaskExecutor, + private val monarchy: Monarchy ) : PushRuleService { private var listeners = ArrayList() override fun fetchPushRules(scope: String) { - pushRulesTask + getPushRulesTask .configureWith(GetPushRulesTask.Params(scope)) .executeBy(taskExecutor) } override fun getPushRules(scope: String): List { - var contentRules: List = emptyList() var overrideRules: List = emptyList() var roomRules: List = emptyList() var senderRules: List = emptyList() var underrideRules: List = emptyList() - // TODO Create const for ruleSetKey monarchy.doWithRealm { realm -> - PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "content").findFirst()?.let { re -> - contentRules = re.pushRules.map { PushRulesMapper.mapContentRule(it) } - } - PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "override").findFirst()?.let { re -> - overrideRules = re.pushRules.map { PushRulesMapper.map(it) } - } - PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "room").findFirst()?.let { re -> - roomRules = re.pushRules.map { PushRulesMapper.mapRoomRule(it) } - } - PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "sender").findFirst()?.let { re -> - senderRules = re.pushRules.map { PushRulesMapper.mapSenderRule(it) } - } - PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "underride").findFirst()?.let { re -> - underrideRules = re.pushRules.map { PushRulesMapper.map(it) } - } + PushRulesEntity.where(realm, scope, RuleSetKey.CONTENT) + .findFirst() + ?.let { pushRulesEntity -> + contentRules = pushRulesEntity.pushRules.map { PushRulesMapper.mapContentRule(it) } + } + PushRulesEntity.where(realm, scope, RuleSetKey.OVERRIDE) + .findFirst() + ?.let { pushRulesEntity -> + overrideRules = pushRulesEntity.pushRules.map { PushRulesMapper.map(it) } + } + PushRulesEntity.where(realm, scope, RuleSetKey.ROOM) + .findFirst() + ?.let { pushRulesEntity -> + roomRules = pushRulesEntity.pushRules.map { PushRulesMapper.mapRoomRule(it) } + } + PushRulesEntity.where(realm, scope, RuleSetKey.SENDER) + .findFirst() + ?.let { pushRulesEntity -> + senderRules = pushRulesEntity.pushRules.map { PushRulesMapper.mapSenderRule(it) } + } + PushRulesEntity.where(realm, scope, RuleSetKey.UNDERRIDE) + .findFirst() + ?.let { pushRulesEntity -> + underrideRules = pushRulesEntity.pushRules.map { PushRulesMapper.map(it) } + } } - return contentRules + overrideRules + roomRules + senderRules + underrideRules + // Ref. for the order: https://matrix.org/docs/spec/client_server/latest#push-rules + return overrideRules + contentRules + roomRules + senderRules + underrideRules } - override fun updatePushRuleEnableStatus(kind: String, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable { + override fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable { return updatePushRuleEnableStatusTask .configureWith(UpdatePushRuleEnableStatusTask.Params(kind, pushRule, enabled)) { this.callback = callback @@ -114,8 +122,9 @@ internal class DefaultPushRuleService @Inject constructor( fun dispatchBing(event: Event, rule: PushRule) { try { + val actionsList = rule.getActions() listeners.forEach { - it.onMatchRule(event, Action.mapFrom(rule) ?: emptyList()) + it.onMatchRule(event, actionsList) } } catch (e: Throwable) { Timber.e(e, "Error while dispatching bing") 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 064f1e3f46..e2db0362bb 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,11 +16,11 @@ package im.vector.matrix.android.internal.session.notification -import im.vector.matrix.android.api.auth.data.SessionParams 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 @@ -37,7 +37,7 @@ internal interface ProcessEventForPushTask : Task false } }.filter { - it.senderId != sessionParams.credentials.userId + it.senderId != userId } Timber.v("[PushRules] Found ${allEvents.size} out of ${(newJoinEvents + inviteEvents).size}" + " to check for push rules with ${params.rules.size} rules") @@ -101,7 +101,8 @@ internal class DefaultProcessEventForPushTask @Inject constructor( } private fun fulfilledBingRule(event: Event, rules: List): PushRule? { - val conditionResolver = DefaultConditionResolver(event, roomService, sessionParams) + // TODO This should be injected + val conditionResolver = DefaultConditionResolver(event, roomService, userId) rules.filter { it.enabled }.forEach { rule -> val isFullfilled = rule.conditions?.map { it.asExecutableCondition()?.isSatisfied(conditionResolver) ?: false diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddHttpPusherWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddHttpPusherWorker.kt index bc587d91d1..e230c02e49 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddHttpPusherWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddHttpPusherWorker.kt @@ -57,14 +57,14 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) return Result.failure() } return try { - setPusher(pusher, params.userId) + setPusher(pusher) Result.success() } catch (exception: Throwable) { when (exception) { is Failure.NetworkConnection -> Result.retry() else -> { monarchy.awaitTransaction { realm -> - PusherEntity.where(realm, params.userId, pusher.pushKey).findFirst()?.let { + PusherEntity.where(realm, pusher.pushKey).findFirst()?.let { //update it it.state = PusherState.FAILED_TO_REGISTER } @@ -76,12 +76,12 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) } } - private suspend fun setPusher(pusher: JsonPusher, userId: String) { + private suspend fun setPusher(pusher: JsonPusher) { executeRequest { apiCall = pushersAPI.setPusher(pusher) } monarchy.awaitTransaction { realm -> - val echo = PusherEntity.where(realm, userId, pusher.pushKey).findFirst() + val echo = PusherEntity.where(realm, pusher.pushKey).findFirst() if (echo != null) { //update it echo.appDisplayName = pusher.appDisplayName @@ -93,7 +93,7 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) echo.data?.url = pusher.data?.url echo.state = PusherState.REGISTERED } else { - pusher.toEntity(userId).also { + pusher.toEntity().also { it.state = PusherState.REGISTERED realm.insertOrUpdate(it) } 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 a05cfb6cac..a40c5e801b 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,15 +15,16 @@ */ package im.vector.matrix.android.internal.session.pushers -import im.vector.matrix.android.api.auth.data.SessionParams import 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.di.UserId import timber.log.Timber +// TODO Inject constructor internal class DefaultConditionResolver(private val event: Event, private val roomService: RoomService, - private val sessionParams: SessionParams) : ConditionResolver { + @UserId private val userId: String) : ConditionResolver { override fun resolveEventMatchCondition(eventMatchCondition: EventMatchCondition): Boolean { @@ -45,8 +46,7 @@ internal class DefaultConditionResolver(private val event: Event, override fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition): Boolean { val roomId = event.roomId ?: return false val room = roomService.getRoom(roomId) ?: return false - val myDisplayName = room.getRoomMember(sessionParams.credentials.userId)?.displayName - ?: return false + val myDisplayName = room.getRoomMember(userId)?.displayName ?: return false return containsDisplayNameCondition.isSatisfied(event, myDisplayName) } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt index 995d93311d..12f6ee9f01 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt @@ -21,29 +21,28 @@ import androidx.work.BackoffPolicy import androidx.work.WorkManager import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.MatrixCallback -import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.pushers.Pusher import im.vector.matrix.android.api.session.pushers.PushersService import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.PusherEntity import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.worker.WorkManagerUtil import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder import im.vector.matrix.android.internal.worker.WorkerParamsFactory -import java.util.UUID +import java.util.* import java.util.concurrent.TimeUnit import javax.inject.Inject -internal class DefaultPusherService @Inject constructor( - private val context: Context, - private val monarchy: Monarchy, - private val sessionParam: SessionParams, - private val getPusherTask: GetPushersTask, - private val removePusherTask: RemovePusherTask, - private val taskExecutor: TaskExecutor +internal class DefaultPusherService @Inject constructor(private val context: Context, + private val monarchy: Monarchy, + @UserId private val userId: String, + private val getPusherTask: GetPushersTask, + private val removePusherTask: RemovePusherTask, + private val taskExecutor: TaskExecutor ) : PushersService { @@ -70,7 +69,7 @@ internal class DefaultPusherService @Inject constructor( append = append) - val params = AddHttpPusherWorker.Params(pusher, sessionParam.credentials.userId) + val params = AddHttpPusherWorker.Params(pusher, userId) val request = matrixOneTimeWorkRequestBuilder() .setConstraints(WorkManagerUtil.workConstraints) @@ -82,7 +81,7 @@ internal class DefaultPusherService @Inject constructor( } override fun removeHttpPusher(pushkey: String, appId: String, callback: MatrixCallback) { - val params = RemovePusherTask.Params(sessionParam.credentials.userId, pushkey, appId) + val params = RemovePusherTask.Params(pushkey, appId) removePusherTask .configureWith(params) { this.callback = callback @@ -93,12 +92,12 @@ internal class DefaultPusherService @Inject constructor( override fun livePushers(): LiveData> { return monarchy.findAllMappedWithChanges( - { realm -> PusherEntity.where(realm, sessionParam.credentials.userId) }, + { realm -> PusherEntity.where(realm) }, { it.asDomain() } ) } override fun pushers(): List { - return monarchy.fetchAllCopiedSync { PusherEntity.where(it, sessionParam.credentials.userId) }.map { it.asDomain() } + return monarchy.fetchAllCopiedSync { PusherEntity.where(it) }.map { it.asDomain() } } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushRulesTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushRulesTask.kt index 627c6f89fa..d542a8fffc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushRulesTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushRulesTask.kt @@ -15,80 +15,27 @@ */ package im.vector.matrix.android.internal.session.pushers -import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse -import im.vector.matrix.android.internal.database.mapper.PushRulesMapper -import im.vector.matrix.android.internal.database.model.PushRulesEntity -import im.vector.matrix.android.internal.database.model.PusherEntityFields import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task -import im.vector.matrix.android.internal.util.awaitTransaction import javax.inject.Inject internal interface GetPushRulesTask : Task { - data class Params(val scope: String) - } - +/** + * We keep this task, but it should not be used anymore, the push rules comes from the sync response + */ internal class DefaultGetPushRulesTask @Inject constructor(private val pushRulesApi: PushRulesApi, - private val monarchy: Monarchy, - private val sessionParams: SessionParams) : GetPushRulesTask { + private val savePushRulesTask: SavePushRulesTask) : GetPushRulesTask { override suspend fun execute(params: GetPushRulesTask.Params) { val response = executeRequest { apiCall = pushRulesApi.getAllRules() } - val scope = params.scope - monarchy.awaitTransaction { realm -> - //clear existings? - //TODO - realm.where(PushRulesEntity::class.java) - .equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId) - .findAll().deleteAllFromRealm() - val content = PushRulesEntity(sessionParams.credentials.userId, scope, "content") - response.global.content?.forEach { rule -> - PushRulesMapper.map(rule).also { - content.pushRules.add(it) - } - } - realm.insertOrUpdate(content) - - val override = PushRulesEntity(sessionParams.credentials.userId, scope, "override") - response.global.override?.forEach { rule -> - PushRulesMapper.map(rule).also { - override.pushRules.add(it) - } - } - realm.insertOrUpdate(override) - - val rooms = PushRulesEntity(sessionParams.credentials.userId, scope, "room") - response.global.room?.forEach { rule -> - PushRulesMapper.map(rule).also { - rooms.pushRules.add(it) - } - } - realm.insertOrUpdate(rooms) - - val senders = PushRulesEntity(sessionParams.credentials.userId, scope, "sender") - response.global.sender?.forEach { rule -> - PushRulesMapper.map(rule).also { - senders.pushRules.add(it) - } - } - realm.insertOrUpdate(senders) - - val underrides = PushRulesEntity(sessionParams.credentials.userId, scope, "underride") - response.global.underride?.forEach { rule -> - PushRulesMapper.map(rule).also { - underrides.pushRules.add(it) - } - } - realm.insertOrUpdate(underrides) - } + savePushRulesTask.execute(SavePushRulesTask.Params(response)) } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersTask.kt index b3199ea370..8fd1a5b3be 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/GetPushersTask.kt @@ -16,11 +16,9 @@ package im.vector.matrix.android.internal.session.pushers import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.pushers.PusherState import im.vector.matrix.android.internal.database.mapper.toEntity import im.vector.matrix.android.internal.database.model.PusherEntity -import im.vector.matrix.android.internal.database.model.PusherEntityFields import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.awaitTransaction @@ -29,8 +27,7 @@ import javax.inject.Inject internal interface GetPushersTask : Task internal class DefaultGetPusherTask @Inject constructor(private val pushersAPI: PushersAPI, - private val monarchy: Monarchy, - private val sessionParams: SessionParams) : GetPushersTask { + private val monarchy: Monarchy) : GetPushersTask { override suspend fun execute(params: Unit) { val response = executeRequest { @@ -39,10 +36,9 @@ internal class DefaultGetPusherTask @Inject constructor(private val pushersAPI: monarchy.awaitTransaction { realm -> //clear existings? realm.where(PusherEntity::class.java) - .equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId) .findAll().deleteAllFromRealm() response.pushers?.forEach { jsonPusher -> - jsonPusher.toEntity(sessionParams.credentials.userId).also { + jsonPusher.toEntity().also { it.state = PusherState.REGISTERED realm.insertOrUpdate(it) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt index 0d00c9bbd6..784a140b19 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt @@ -59,6 +59,9 @@ internal abstract class PushersModule { @Binds abstract fun bindGetPushRulesTask(getPushRulesTask: DefaultGetPushRulesTask): GetPushRulesTask + @Binds + abstract fun bindSavePushRulesTask(savePushRulesTask: DefaultSavePushRulesTask): SavePushRulesTask + @Binds abstract fun bindRemovePusherTask(removePusherTask: DefaultRemovePusherTask): RemovePusherTask diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePusherTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePusherTask.kt index 0ed7175e9a..d22447586c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePusherTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePusherTask.kt @@ -28,8 +28,7 @@ import io.realm.Realm import javax.inject.Inject internal interface RemovePusherTask : Task { - data class Params(val userId: String, - val pushKey: String, + data class Params(val pushKey: String, val pushAppId: String) } @@ -40,12 +39,12 @@ internal class DefaultRemovePusherTask @Inject constructor( override suspend fun execute(params: RemovePusherTask.Params) { monarchy.awaitTransaction { realm -> - val existingEntity = PusherEntity.where(realm, params.userId, params.pushKey).findFirst() + val existingEntity = PusherEntity.where(realm, params.pushKey).findFirst() existingEntity?.state = PusherState.UNREGISTERING } val existing = Realm.getInstance(monarchy.realmConfiguration).use { realm -> - PusherEntity.where(realm, params.userId, params.pushKey).findFirst()?.asDomain() + PusherEntity.where(realm, params.pushKey).findFirst()?.asDomain() } ?: throw Exception("No existing pusher") val deleteBody = JsonPusher( @@ -64,7 +63,7 @@ internal class DefaultRemovePusherTask @Inject constructor( apiCall = pushersAPI.setPusher(deleteBody) } monarchy.awaitTransaction { - PusherEntity.where(it, params.userId, params.pushKey).findFirst()?.deleteFromRealm() + PusherEntity.where(it, params.pushKey).findFirst()?.deleteFromRealm() } } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/SavePushRulesTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/SavePushRulesTask.kt new file mode 100644 index 0000000000..b658858e47 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/SavePushRulesTask.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.matrix.android.internal.session.pushers + +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.pushrules.RuleScope +import im.vector.matrix.android.api.pushrules.RuleSetKey +import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse +import im.vector.matrix.android.internal.database.mapper.PushRulesMapper +import im.vector.matrix.android.internal.database.model.PushRulesEntity +import im.vector.matrix.android.internal.task.Task +import im.vector.matrix.android.internal.util.awaitTransaction +import javax.inject.Inject + + +/** + * Save the push rules in DB + */ +internal interface SavePushRulesTask : Task { + data class Params(val pushRules: GetPushRulesResponse) +} + +internal class DefaultSavePushRulesTask @Inject constructor(private val monarchy: Monarchy) : SavePushRulesTask { + + override suspend fun execute(params: SavePushRulesTask.Params) { + monarchy.awaitTransaction { realm -> + // clear current push rules + realm.where(PushRulesEntity::class.java) + .findAll() + .deleteAllFromRealm() + + // Save only global rules for the moment + val globalRules = params.pushRules.global + + val content = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.CONTENT } + globalRules.content?.forEach { rule -> + content.pushRules.add(PushRulesMapper.map(rule)) + } + realm.insertOrUpdate(content) + + val override = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.OVERRIDE } + globalRules.override?.forEach { rule -> + PushRulesMapper.map(rule).also { + override.pushRules.add(it) + } + } + realm.insertOrUpdate(override) + + val rooms = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.ROOM } + globalRules.room?.forEach { rule -> + rooms.pushRules.add(PushRulesMapper.map(rule)) + } + realm.insertOrUpdate(rooms) + + val senders = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.SENDER } + globalRules.sender?.forEach { rule -> + senders.pushRules.add(PushRulesMapper.map(rule)) + } + realm.insertOrUpdate(senders) + + val underrides = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.UNDERRIDE } + globalRules.underride?.forEach { rule -> + underrides.pushRules.add(PushRulesMapper.map(rule)) + } + realm.insertOrUpdate(underrides) + } + } +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt index 828d9e71ae..f3077e6837 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt @@ -15,6 +15,7 @@ */ package im.vector.matrix.android.internal.session.pushers +import im.vector.matrix.android.api.pushrules.RuleKind import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.task.Task @@ -22,7 +23,7 @@ import javax.inject.Inject internal interface UpdatePushRuleEnableStatusTask : Task { - data class Params(val kind: String, + data class Params(val kind: RuleKind, val pushRule: PushRule, val enabled: Boolean) } @@ -32,7 +33,7 @@ internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor(private override suspend fun execute(params: UpdatePushRuleEnableStatusTask.Params) { return executeRequest { - apiCall = pushRulesApi.updateEnableRuleStatus(params.kind, params.pushRule.ruleId, params.enabled) + apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.pushRule.ruleId, params.enabled) } } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt index 9d642d3a89..97bbe62b11 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt @@ -16,13 +16,13 @@ package im.vector.matrix.android.internal.session.room import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.internal.database.RealmLiveEntityObserver import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.query.types import im.vector.matrix.android.internal.di.SessionDatabase +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import io.realm.OrderedCollectionChangeSet @@ -38,7 +38,7 @@ import javax.inject.Inject */ internal class EventRelationsAggregationUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, - private val credentials: Credentials, + @UserId private val userId: String, private val task: EventRelationsAggregationTask, private val taskExecutor: TaskExecutor) : RealmLiveEntityObserver(realmConfiguration) { @@ -61,7 +61,7 @@ internal class EventRelationsAggregationUpdater @Inject constructor(@SessionData .toList() val params = EventRelationsAggregationTask.Params( insertedDomains, - credentials.userId + userId ) task.configureWith(params).executeBy(taskExecutor) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt index 9161fb25a1..0b18279aa8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.session.room import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Credentials 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.RoomAvatarContent @@ -27,11 +26,12 @@ import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.EventEntityFields import im.vector.matrix.android.internal.database.query.prev import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.room.membership.RoomMembers import javax.inject.Inject internal class RoomAvatarResolver @Inject constructor(private val monarchy: Monarchy, - private val credentials: Credentials) { + @UserId private val userId: String) { /** * Compute the room avatar url @@ -52,7 +52,7 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona if (members.size == 1) { res = members.firstOrNull()?.toRoomMember()?.avatarUrl } else if (members.size == 2) { - val firstOtherMember = members.where().notEqualTo(EventEntityFields.STATE_KEY, credentials.userId).findFirst() + val firstOtherMember = members.where().notEqualTo(EventEntityFields.STATE_KEY, userId).findFirst() res = firstOtherMember?.toRoomMember()?.avatarUrl } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt index a8814771cf..f92f2ccc1e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.session.room import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.Membership @@ -31,6 +30,7 @@ import im.vector.matrix.android.internal.database.query.isEventRead import im.vector.matrix.android.internal.database.query.latestEvent import im.vector.matrix.android.internal.database.query.prev import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver import im.vector.matrix.android.internal.session.room.membership.RoomMembers import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary @@ -39,7 +39,7 @@ import io.realm.Realm import io.realm.kotlin.createObject import javax.inject.Inject -internal class RoomSummaryUpdater @Inject constructor(private val credentials: Credentials, +internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId: String, private val roomDisplayNameResolver: RoomDisplayNameResolver, private val roomAvatarResolver: RoomAvatarResolver, private val monarchy: Monarchy) { @@ -92,11 +92,11 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0 //avoid this call if we are sure there are unread events - || !isEventRead(monarchy, credentials.userId, roomId, latestPreviewableEvent?.eventId) + || !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId) val otherRoomMembers = RoomMembers(realm, roomId) .queryRoomMembersEvent() - .notEqualTo(EventEntityFields.STATE_KEY, credentials.userId) + .notEqualTo(EventEntityFields.STATE_KEY, userId) .findAll() .asSequence() .map { it.stateKey } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt index 815fc96e8e..37adba0df8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.session.room.membership import android.content.Context import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.R -import im.vector.matrix.android.api.auth.data.Credentials 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.* @@ -30,6 +29,7 @@ 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.query.prev import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import javax.inject.Inject /** @@ -37,7 +37,7 @@ import javax.inject.Inject */ internal class RoomDisplayNameResolver @Inject constructor(private val context: Context, private val monarchy: Monarchy, - private val credentials: Credentials + @UserId private val userId: String ) { /** @@ -79,7 +79,7 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context: if (roomEntity?.membership == Membership.INVITE) { - val inviteMeEvent = roomMembers.queryRoomMemberEvent(credentials.userId).findFirst() + val inviteMeEvent = roomMembers.queryRoomMemberEvent(userId).findFirst() val inviterId = inviteMeEvent?.sender name = if (inviterId != null) { val inviterMemberEvent = loadedMembers.where() @@ -97,7 +97,7 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context: } } else { loadedMembers.where() - .notEqualTo(EventEntityFields.STATE_KEY, credentials.userId) + .notEqualTo(EventEntityFields.STATE_KEY, userId) .limit(3) .findAll() } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt index c63733f3d2..ac3c7a4e22 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt @@ -17,13 +17,13 @@ package im.vector.matrix.android.internal.session.room.prune import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.internal.database.RealmLiveEntityObserver import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.query.types import im.vector.matrix.android.internal.di.SessionDatabase +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import io.realm.OrderedCollectionChangeSet @@ -37,7 +37,7 @@ import javax.inject.Inject * As it will actually delete the content, it should be called last in the list of listener. */ internal class EventsPruner @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, - private val credentials: Credentials, + @UserId private val userId: String, private val pruneEventTask: PruneEventTask, private val taskExecutor: TaskExecutor) : RealmLiveEntityObserver(realmConfiguration) { @@ -54,7 +54,7 @@ internal class EventsPruner @Inject constructor(@SessionDatabase realmConfigurat val params = PruneEventTask.Params( insertedDomains, - credentials.userId + userId ) pruneEventTask.configureWith(params).executeBy(taskExecutor) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt index d6d43ae926..c158f09e19 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt @@ -22,7 +22,6 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.MatrixCallback -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.room.model.ReadReceipt import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.util.Optional @@ -33,6 +32,7 @@ import im.vector.matrix.android.internal.database.model.ReadReceiptEntity import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity import im.vector.matrix.android.internal.database.query.isEventRead import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith @@ -41,7 +41,7 @@ internal class DefaultReadService @AssistedInject constructor(@Assisted private private val taskExecutor: TaskExecutor, private val setReadMarkersTask: SetReadMarkersTask, private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper, - private val credentials: Credentials + @UserId private val userId: String ) : ReadService { @AssistedInject.Factory @@ -78,7 +78,7 @@ internal class DefaultReadService @AssistedInject constructor(@Assisted private override fun isEventRead(eventId: String): Boolean { - return isEventRead(monarchy, credentials.userId, roomId, eventId) + return isEventRead(monarchy, userId, roomId, eventId) } override fun getReadMarkerLive(): LiveData> { @@ -92,7 +92,7 @@ internal class DefaultReadService @AssistedInject constructor(@Assisted private override fun getMyReadReceiptLive(): LiveData> { val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm -> - ReadReceiptEntity.where(realm, roomId = roomId, userId = credentials.userId) + ReadReceiptEntity.where(realm, roomId = roomId, userId = userId) } return Transformations.map(liveRealmData) { results -> Optional.from(results.firstOrNull()?.eventId) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt index f9c704cf0b..6a875b0563 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt @@ -17,16 +17,15 @@ package im.vector.matrix.android.internal.session.room.read import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.ReadMarkerEntity import im.vector.matrix.android.internal.database.model.ReadReceiptEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity -import im.vector.matrix.android.internal.database.query.find -import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom +import im.vector.matrix.android.internal.database.query.* import im.vector.matrix.android.internal.database.query.latestEvent import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.room.RoomAPI import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory @@ -52,11 +51,11 @@ private const val READ_MARKER = "m.fully_read" private const val READ_RECEIPT = "m.read" internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI: RoomAPI, - private val credentials: Credentials, private val monarchy: Monarchy, private val roomFullyReadHandler: RoomFullyReadHandler, - private val readReceiptHandler: ReadReceiptHandler -) : SetReadMarkersTask { + private val readReceiptHandler: ReadReceiptHandler, + @UserId private val userId: String) + : SetReadMarkersTask { override suspend fun execute(params: SetReadMarkersTask.Params) { val markers = HashMap() @@ -84,7 +83,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI } if (readReceiptEventId != null - && !isEventRead(params.roomId, readReceiptEventId)) { + && !isEventRead(monarchy, userId, params.roomId, readReceiptEventId)) { if (LocalEchoEventFactory.isLocalEchoId(readReceiptEventId)) { Timber.w("Can't set read receipt for local event $readReceiptEventId") } else { @@ -108,12 +107,12 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI roomFullyReadHandler.handle(realm, roomId, FullyReadContent(readMarkerId)) } if (readReceiptId != null) { - val readReceiptContent = ReadReceiptHandler.createContent(credentials.userId, readReceiptId) + val readReceiptContent = ReadReceiptHandler.createContent(userId, readReceiptId) readReceiptHandler.handle(realm, roomId, readReceiptContent, false) val isLatestReceived = TimelineEventEntity.latestEvent(realm, roomId = roomId, includesSending = false)?.eventId == readReceiptId if (isLatestReceived) { val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() - ?: return@awaitTransaction + ?: return@awaitTransaction roomSummary.notificationCount = 0 roomSummary.highlightCount = 0 roomSummary.hasUnreadMessages = false @@ -133,19 +132,4 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI } } - private fun isEventRead(roomId: String, eventId: String): Boolean { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> - val readReceipt = ReadReceiptEntity.where(realm, roomId, credentials.userId).findFirst() - ?: return false - val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId) - ?: return false - val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex - ?: Int.MIN_VALUE - val eventToCheckIndex = liveChunk.timelineEvents.find(eventId)?.root?.displayIndex - ?: Int.MAX_VALUE - eventToCheckIndex <= readReceiptIndex - } - } - - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt index 0c8695cbcf..a1abc94f29 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt @@ -23,7 +23,6 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.MatrixCallback -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary @@ -37,6 +36,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.room.send.EncryptEventWorker import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory import im.vector.matrix.android.internal.session.room.send.RedactEventWorker @@ -50,7 +50,7 @@ import timber.log.Timber internal class DefaultRelationService @AssistedInject constructor(@Assisted private val roomId: String, private val context: Context, - private val credentials: Credentials, + @UserId private val userId: String, private val eventFactory: LocalEchoEventFactory, private val cryptoService: CryptoService, private val findReactionEventForUndoTask: FindReactionEventForUndoTask, @@ -111,7 +111,7 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv //TODO duplicate with send service? private fun createRedactEventWork(localEvent: Event, eventId: String, reason: String?): OneTimeWorkRequest { val sendContentWorkerParams = RedactEventWorker.Params( - credentials.userId, + userId, localEvent.eventId!!, roomId, eventId, @@ -199,13 +199,13 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv private fun createEncryptEventWork(event: Event, keepKeys: List?): OneTimeWorkRequest { // Same parameter - val params = EncryptEventWorker.Params(credentials.userId, roomId, event, keepKeys) + val params = EncryptEventWorker.Params(userId, roomId, event, keepKeys) val sendWorkData = WorkerParamsFactory.toData(params) return TimelineSendEventWorkCommon.createWork(sendWorkData, true) } private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest { - val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event) + val sendContentWorkerParams = SendEventWorker.Params(userId, roomId, event) val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) return TimelineSendEventWorkCommon.createWork(sendWorkData, startChain) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt index a97d03d734..a342d3fe72 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt @@ -17,14 +17,10 @@ package im.vector.matrix.android.internal.session.room.send import android.content.Context -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations import androidx.work.* import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.BuildConfig -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.content.ContentAttachmentData import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.events.model.* @@ -32,16 +28,16 @@ import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.model.message.MessageType import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.session.room.send.SendState -import im.vector.matrix.android.api.session.room.send.UserDraft import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.api.util.CancelableBag -import im.vector.matrix.android.internal.database.RealmLiveData -import im.vector.matrix.android.internal.database.mapper.DraftMapper import im.vector.matrix.android.internal.database.mapper.asDomain -import im.vector.matrix.android.internal.database.model.* +import im.vector.matrix.android.internal.database.model.EventEntity +import im.vector.matrix.android.internal.database.model.RoomEntity +import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.query.findAllInRoomWithSendStates import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.content.UploadContentWorker import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon import im.vector.matrix.android.internal.util.CancelableWork @@ -59,7 +55,7 @@ private const val BACKOFF_DELAY = 10_000L internal class DefaultSendService @AssistedInject constructor(@Assisted private val roomId: String, private val context: Context, - private val credentials: Credentials, + @UserId private val userId: String, private val localEchoEventFactory: LocalEchoEventFactory, private val cryptoService: CryptoService, private val monarchy: Monarchy @@ -292,7 +288,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private private fun createEncryptEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest { // Same parameter - val params = EncryptEventWorker.Params(credentials.userId, roomId, event) + val params = EncryptEventWorker.Params(userId, roomId, event) val sendWorkData = WorkerParamsFactory.toData(params) return matrixOneTimeWorkRequestBuilder() @@ -304,7 +300,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private } private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest { - val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event) + val sendContentWorkerParams = SendEventWorker.Params(userId, roomId, event) val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) return TimelineSendEventWorkCommon.createWork(sendWorkData, startChain) @@ -314,7 +310,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private val redactEvent = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason).also { saveLocalEcho(it) } - val sendContentWorkerParams = RedactEventWorker.Params(credentials.userId, redactEvent.eventId!!, roomId, event.eventId, reason) + val sendContentWorkerParams = RedactEventWorker.Params(userId, redactEvent.eventId!!, roomId, event.eventId, reason) val redactWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) return TimelineSendEventWorkCommon.createWork(redactWorkData, true) } @@ -323,7 +319,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private attachment: ContentAttachmentData, isRoomEncrypted: Boolean, startChain: Boolean): OneTimeWorkRequest { - val uploadMediaWorkerParams = UploadContentWorker.Params(credentials.userId, roomId, event, attachment, isRoomEncrypted) + val uploadMediaWorkerParams = UploadContentWorker.Params(userId, roomId, event, attachment, isRoomEncrypted) val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams) return matrixOneTimeWorkRequestBuilder() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt index b0351dca4f..ffc539471b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.session.room.send import android.media.MediaMetadataRetriever import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.R -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.permalinks.PermalinkFactory import im.vector.matrix.android.api.session.content.ContentAttachmentData import im.vector.matrix.android.api.session.events.model.* @@ -33,12 +32,13 @@ import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent import im.vector.matrix.android.internal.database.helper.addSendingEvent import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.content.ThumbnailExtractor import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater import im.vector.matrix.android.internal.util.StringProvider import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer -import java.util.UUID +import java.util.* import javax.inject.Inject /** @@ -50,7 +50,7 @@ import javax.inject.Inject * * The transactionID is used as loc */ -internal class LocalEchoEventFactory @Inject constructor(private val credentials: Credentials, +internal class LocalEchoEventFactory @Inject constructor(@UserId private val userId: String, private val stringProvider: StringProvider, private val roomSummaryUpdater: RoomSummaryUpdater) { // TODO Inject @@ -163,7 +163,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials return Event( roomId = roomId, originServerTs = dummyOriginServerTs(), - senderId = credentials.userId, + senderId = userId, eventId = localId, type = EventType.REACTION, content = content.toContent(), @@ -255,7 +255,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials return Event( roomId = roomId, originServerTs = dummyOriginServerTs(), - senderId = credentials.userId, + senderId = userId, eventId = localID, type = EventType.MESSAGE, content = content.toContent(), @@ -373,7 +373,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials return Event( roomId = roomId, originServerTs = dummyOriginServerTs(), - senderId = credentials.userId, + senderId = userId, eventId = localID, type = EventType.REDACTION, redacts = eventId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt index 483a0a4741..64d5f120da 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt @@ -106,7 +106,7 @@ internal class TimelineEventDecryptor( Timber.v("Successfully decrypted event ${eventId}") eventEntity.setDecryptionResult(result) } catch (e: MXCryptoError) { - Timber.v("Failed to decrypte event ${eventId} ${e}") + Timber.v("Failed to decrypt event ${eventId} ${e}") if (e is MXCryptoError.Base && e.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID) { //Keep track of unknown sessions to automatically try to decrypt on new session eventEntity.decryptionErrorCode = e.errorType.name diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt index 18c2de71d3..68536d4f50 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt @@ -17,15 +17,11 @@ package im.vector.matrix.android.internal.session.signout import android.content.Context -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.SessionManager import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.crypto.CryptoModule import im.vector.matrix.android.internal.database.RealmKeysUtils -import im.vector.matrix.android.internal.di.CryptoDatabase -import im.vector.matrix.android.internal.di.SessionDatabase -import im.vector.matrix.android.internal.di.UserCacheDirectory -import im.vector.matrix.android.internal.di.UserMd5 +import im.vector.matrix.android.internal.di.* import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.SessionModule import im.vector.matrix.android.internal.session.cache.ClearCacheTask @@ -38,7 +34,7 @@ import javax.inject.Inject internal interface SignOutTask : Task internal class DefaultSignOutTask @Inject constructor(private val context: Context, - private val credentials: Credentials, + @UserId private val userId: String, private val signOutAPI: SignOutAPI, private val sessionManager: SessionManager, private val sessionParamsStore: SessionParamsStore, @@ -55,13 +51,13 @@ internal class DefaultSignOutTask @Inject constructor(private val context: Conte } Timber.d("SignOut: release session...") - sessionManager.releaseSession(credentials.userId) + sessionManager.releaseSession(userId) Timber.d("SignOut: cancel pending works...") WorkManagerUtil.cancelAllWorks(context) Timber.d("SignOut: delete session params...") - sessionParamsStore.delete(credentials.userId) + sessionParamsStore.delete(userId) Timber.d("SignOut: clear session data...") clearSessionDataTask.execute(Unit) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt index 29b119dd15..9355384ef5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt @@ -64,12 +64,13 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc } } + + /** Note: [im.vector.matrix.android.internal.session.group.GroupSummaryUpdater] is observing changes */ realm.insertOrUpdate(groups) } private fun handleJoinedGroup(realm: Realm, groupId: String): GroupEntity { - val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) groupEntity.membership = Membership.JOIN return groupEntity @@ -77,21 +78,16 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc private fun handleInvitedGroup(realm: Realm, groupId: String): GroupEntity { - val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) groupEntity.membership = Membership.INVITE return groupEntity } - // TODO : handle it private fun handleLeftGroup(realm: Realm, groupId: String): GroupEntity { - val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) groupEntity.membership = Membership.LEAVE return groupEntity } - - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt index 1e7a4b7703..91119f6376 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.sync import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.R +import im.vector.matrix.android.api.pushrules.RuleScope 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 @@ -87,11 +88,11 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch private fun checkPushRules(roomsSyncResponse: RoomsSyncResponse) { Timber.v("[PushRules] --> checkPushRules") if (tokenStore.getLastToken() == null) { - Timber.v("[PushRules] <-- No push tule check on initial sync") + Timber.v("[PushRules] <-- No push rule check on initial sync") return } //nothing on initial sync - val rules = pushRuleService.getPushRules("global") + val rules = pushRuleService.getPushRules(RuleScope.GLOBAL) processForPushTask.configureWith(ProcessEventForPushTask.Params(roomsSyncResponse, rules)) .executeBy(taskExecutor) Timber.v("[PushRules] <-- Push task scheduled") diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt index 584e84c2ae..1b843bda19 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.sync -import arrow.core.Try import im.vector.matrix.android.R import im.vector.matrix.android.internal.crypto.DefaultCryptoService import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService @@ -33,73 +32,70 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl private val cryptoService: DefaultCryptoService, private val initialSyncProgressService: DefaultInitialSyncProgressService) { - fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean): Try { - return Try { - val isInitialSync = fromToken == null - Timber.v("Start handling sync, is InitialSync: $isInitialSync") - val reporter = initialSyncProgressService.takeIf { isInitialSync } + suspend fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean) { + val isInitialSync = fromToken == null + Timber.v("Start handling sync, is InitialSync: $isInitialSync") + val reporter = initialSyncProgressService.takeIf { isInitialSync } + measureTimeMillis { + if (!cryptoService.isStarted()) { + Timber.v("Should start cryptoService") + cryptoService.start(isInitialSync) + } + }.also { + Timber.v("Finish handling start cryptoService in $it ms") + } + val measure = measureTimeMillis { + // Handle the to device events before the room ones + // to ensure to decrypt them properly measureTimeMillis { - if (!cryptoService.isStarted()) { - Timber.v("Should start cryptoService") - cryptoService.start(isInitialSync) + Timber.v("Handle toDevice") + reportSubtask(reporter, R.string.initial_sync_start_importing_account_crypto, 100, 0.1f) { + if (syncResponse.toDevice != null) { + cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter) + } } }.also { - Timber.v("Finish handling start cryptoService in $it ms") + Timber.v("Finish handling toDevice in $it ms") } - val measure = measureTimeMillis { - // Handle the to device events before the room ones - // to ensure to decrypt them properly - measureTimeMillis { - Timber.v("Handle toDevice") - reportSubtask(reporter, R.string.initial_sync_start_importing_account_crypto, 100, 0.1f) { - if (syncResponse.toDevice != null) { - cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter) - } + + measureTimeMillis { + Timber.v("Handle rooms") + + reportSubtask(reporter, R.string.initial_sync_start_importing_account_rooms, 100, 0.7f) { + if (syncResponse.rooms != null) { + roomSyncHandler.handle(syncResponse.rooms, isInitialSync, reporter) } - }.also { - Timber.v("Finish handling toDevice in $it ms") } - - measureTimeMillis { - Timber.v("Handle rooms") - - reportSubtask(reporter, R.string.initial_sync_start_importing_account_rooms, 100, 0.7f) { - if (syncResponse.rooms != null) { - roomSyncHandler.handle(syncResponse.rooms, isInitialSync, reporter) - } - } - }.also { - Timber.v("Finish handling rooms in $it ms") - } - - - measureTimeMillis { - reportSubtask(reporter, R.string.initial_sync_start_importing_account_groups, 100, 0.1f) { - Timber.v("Handle groups") - if (syncResponse.groups != null) { - groupSyncHandler.handle(syncResponse.groups, reporter) - } - } - }.also { - Timber.v("Finish handling groups in $it ms") - } - - measureTimeMillis { - reportSubtask(reporter, R.string.initial_sync_start_importing_account_data, 100, 0.1f) { - Timber.v("Handle accountData") - userAccountDataSyncHandler.handle(syncResponse.accountData, syncResponse.rooms?.invite) - } - }.also { - Timber.v("Finish handling accountData in $it ms") - } - - Timber.v("On sync completed") - cryptoSyncHandler.onSyncCompleted(syncResponse) + }.also { + Timber.v("Finish handling rooms in $it ms") } - Timber.v("Finish handling sync in $measure ms") - syncResponse + + + measureTimeMillis { + reportSubtask(reporter, R.string.initial_sync_start_importing_account_groups, 100, 0.1f) { + Timber.v("Handle groups") + if (syncResponse.groups != null) { + groupSyncHandler.handle(syncResponse.groups, reporter) + } + } + }.also { + Timber.v("Finish handling groups in $it ms") + } + + measureTimeMillis { + reportSubtask(reporter, R.string.initial_sync_start_importing_account_data, 100, 0.1f) { + Timber.v("Handle accountData") + userAccountDataSyncHandler.handle(syncResponse.accountData, syncResponse.rooms?.invite) + } + }.also { + Timber.v("Finish handling accountData in $it ms") + } + + Timber.v("On sync completed") + cryptoSyncHandler.onSyncCompleted(syncResponse) } + Timber.v("Finish handling sync in $measure ms") } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt index ea4efa4740..28d4d5fc48 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt @@ -18,10 +18,10 @@ package im.vector.matrix.android.internal.session.sync import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.R -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.failure.MatrixError import im.vector.matrix.android.internal.auth.SessionParamsStore +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService import im.vector.matrix.android.internal.session.filter.FilterRepository @@ -36,7 +36,7 @@ internal interface SyncTask : Task { } internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI, - private val credentials: Credentials, + @UserId private val userId: String, private val filterRepository: FilterRepository, private val syncResponseHandler: SyncResponseHandler, private val sessionParamsStore: SessionParamsStore, @@ -70,7 +70,7 @@ internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI, // Intercept 401 if (throwable is Failure.ServerError && throwable.error.code == MatrixError.UNKNOWN_TOKEN) { - sessionParamsStore.delete(credentials.userId) + sessionParamsStore.delete(userId) } throw throwable } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt index 6ea4693168..87b4c2d1c1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt @@ -17,16 +17,18 @@ package im.vector.matrix.android.internal.session.sync import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.query.getDirectRooms import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.UserId +import im.vector.matrix.android.internal.session.pushers.SavePushRulesTask import im.vector.matrix.android.internal.session.room.membership.RoomMembers import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages +import im.vector.matrix.android.internal.session.sync.model.UserAccountDataPushRules import im.vector.matrix.android.internal.session.sync.model.UserAccountDataSync import im.vector.matrix.android.internal.session.user.accountdata.DirectChatsHelper import im.vector.matrix.android.internal.session.user.accountdata.UpdateUserAccountDataTask @@ -37,15 +39,17 @@ import timber.log.Timber import javax.inject.Inject internal class UserAccountDataSyncHandler @Inject constructor(private val monarchy: Monarchy, - private val credentials: Credentials, + @UserId private val userId: String, private val directChatsHelper: DirectChatsHelper, private val updateUserAccountDataTask: UpdateUserAccountDataTask, + private val savePushRulesTask: SavePushRulesTask, private val taskExecutor: TaskExecutor) { - fun handle(accountData: UserAccountDataSync?, invites: Map?) { + suspend fun handle(accountData: UserAccountDataSync?, invites: Map?) { accountData?.list?.forEach { when (it) { is UserAccountDataDirectMessages -> handleDirectChatRooms(it) + is UserAccountDataPushRules -> handlePushRules(it) else -> return@forEach } } @@ -54,6 +58,10 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc } } + private suspend fun handlePushRules(userAccountDataPushRules: UserAccountDataPushRules) { + savePushRulesTask.execute(SavePushRulesTask.Params(userAccountDataPushRules.content)) + } + private fun handleDirectChatRooms(directMessages: UserAccountDataDirectMessages) { monarchy.runTransactionSync { realm -> val oldDirectRooms = RoomSummaryEntity.getDirectRooms(realm) @@ -81,11 +89,11 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc val directChats = directChatsHelper.getLocalUserAccount() var hasUpdate = false invites.forEach { (roomId, _) -> - val myUserStateEvent = RoomMembers(realm, roomId).getStateEvent(credentials.userId) + val myUserStateEvent = RoomMembers(realm, roomId).getStateEvent(userId) val inviterId = myUserStateEvent?.sender val myUserRoomMember: RoomMember? = myUserStateEvent?.let { it.asDomain().content?.toModel() } val isDirect = myUserRoomMember?.isDirect - if (inviterId != null && inviterId != credentials.userId && isDirect == true) { + if (inviterId != null && inviterId != userId && isDirect == true) { directChats .getOrPut(inviterId, { arrayListOf() }) .apply { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt index 1cb6575161..f0b33809a1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt @@ -30,7 +30,6 @@ import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.util.BackgroundDetectionObserver -import kotlinx.coroutines.CancellationException import timber.log.Timber import java.net.SocketTimeoutException import java.util.concurrent.CountDownLatch @@ -140,7 +139,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, if (failure is Failure.NetworkConnection && failure.cause is SocketTimeoutException) { // Timeout are not critical Timber.v("Timeout") - } else if (failure is Failure.Unknown && failure.throwable is CancellationException) { + } else if (failure is Failure.Cancelled) { Timber.v("Cancelled") } else if (failure is Failure.ServerError && (failure.error.code == MatrixError.UNKNOWN_TOKEN || failure.error.code == MatrixError.MISSING_TOKEN)) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt index ca5dbd1d37..1362eb9171 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt @@ -23,5 +23,6 @@ internal interface UserAccountData { const val TYPE_DIRECT_MESSAGES = "m.direct" const val TYPE_PREVIEW_URLS = "org.matrix.preview_urls" const val TYPE_WIDGETS = "m.widgets" + const val TYPE_PUSH_RULES = "m.push_rules" } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt new file mode 100644 index 0000000000..e2bd12f79b --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.sync.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse + +@JsonClass(generateAdapter = true) +internal data class UserAccountDataPushRules( + @Json(name = "content") val content: GetPushRulesResponse +) : UserAccountData + diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt index 80fc4cc3b1..aaa82efef0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt @@ -16,7 +16,7 @@ package im.vector.matrix.android.internal.session.user.accountdata -import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.sync.model.UserAccountData import im.vector.matrix.android.internal.task.Task @@ -42,11 +42,11 @@ internal interface UpdateUserAccountDataTask : Task) { + override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback): Cancelable { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + override fun joinRoom(roomId: String, viaServers: List, callback: MatrixCallback): Cancelable { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } override fun getRoom(roomId: String): Room? { @@ -184,7 +202,54 @@ class PushrulesConditionTest { } class MockRoom(override val roomId: String, val _numberOfJoinedMembers: Int) : Room { - override fun getTimeLineEventLive(eventId: String): LiveData { + override fun resendTextMessage(localEcho: TimelineEvent): Cancelable? { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun deleteFailedEcho(localEcho: TimelineEvent) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun clearSendingQueue() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun resendAllFailedMessages() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun saveDraft(draft: UserDraft) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun deleteDraft() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getDraftsLive(): LiveData> { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getEventReadReceiptsLive(eventId: String): LiveData> { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getStateEvent(eventType: String): Event? { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun editReply(replyToEdit: TimelineEvent, originalTimelineEvent: TimelineEvent, newBodyText: String, compatibilityBodyText: String): Cancelable { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun fetchEditHistory(eventId: String, callback: MatrixCallback>) { + } + + override fun liveTimeLineEvent(eventId: String): LiveData { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } @@ -193,7 +258,7 @@ class PushrulesConditionTest { return _numberOfJoinedMembers } - override fun getRoomSummaryLive(): LiveData { + override fun liveRoomSummary(): LiveData { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } @@ -201,7 +266,7 @@ class PushrulesConditionTest { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - override fun createTimeline(eventId: String?, allowedTypes: List?): Timeline { + override fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } @@ -245,7 +310,7 @@ class PushrulesConditionTest { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - override fun loadRoomMembersIfNeeded(): Cancelable { + override fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback): Cancelable { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } @@ -257,15 +322,15 @@ class PushrulesConditionTest { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - override fun invite(userId: String, callback: MatrixCallback) { + override fun invite(userId: String, callback: MatrixCallback): Cancelable { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - override fun join(callback: MatrixCallback) { + override fun join(viaServers: List, callback: MatrixCallback): Cancelable { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - override fun leave(callback: MatrixCallback) { + override fun leave(callback: MatrixCallback): Cancelable { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } diff --git a/vector/build.gradle b/vector/build.gradle index 697d0f36d0..16bf70aef0 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -15,7 +15,7 @@ androidExtensions { } ext.versionMajor = 0 -ext.versionMinor = 6 +ext.versionMinor = 7 ext.versionPatch = 0 static def getGitTimestamp() { diff --git a/vector/src/fdroid/java/im/vector/riotx/fdroid/service/VectorSyncService.kt b/vector/src/fdroid/java/im/vector/riotx/fdroid/service/VectorSyncService.kt index a3f999a001..b2a45eff81 100644 --- a/vector/src/fdroid/java/im/vector/riotx/fdroid/service/VectorSyncService.kt +++ b/vector/src/fdroid/java/im/vector/riotx/fdroid/service/VectorSyncService.kt @@ -21,11 +21,19 @@ import android.content.Intent import android.os.Build import im.vector.matrix.android.internal.session.sync.job.SyncService import im.vector.riotx.R +import im.vector.riotx.core.extensions.vectorComponent import im.vector.riotx.features.notifications.NotificationUtils import timber.log.Timber class VectorSyncService : SyncService() { + private lateinit var notificationUtils: NotificationUtils + + override fun onCreate() { + super.onCreate() + notificationUtils = vectorComponent().notificationUtils() + } + override fun onDestroy() { removeForegroundNotif() super.onDestroy() @@ -43,7 +51,7 @@ class VectorSyncService : SyncService() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Timber.v("VectorSyncService - onStartCommand ") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val notification = NotificationUtils.buildForegroundServiceNotification(applicationContext, R.string.notification_listening_for_events, false) + val notification = notificationUtils.buildForegroundServiceNotification(R.string.notification_listening_for_events, false) startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification) } return super.onStartCommand(intent, flags, startId) diff --git a/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt index d755815595..a76091fb36 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt @@ -27,6 +27,7 @@ import im.vector.riotx.EmojiCompatFontProvider import im.vector.riotx.EmojiCompatWrapper import im.vector.riotx.VectorApplication import im.vector.riotx.core.pushers.PushersManager +import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.features.configuration.VectorConfiguration import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler @@ -63,6 +64,8 @@ interface VectorComponent { fun resources(): Resources + fun dimensionUtils(): DimensionConverter + fun vectorConfiguration(): VectorConfiguration fun avatarRenderer(): AvatarRenderer diff --git a/vector/src/main/java/im/vector/riotx/core/extensions/Session.kt b/vector/src/main/java/im/vector/riotx/core/extensions/Session.kt index 95e17a4b7d..713c764490 100644 --- a/vector/src/main/java/im/vector/riotx/core/extensions/Session.kt +++ b/vector/src/main/java/im/vector/riotx/core/extensions/Session.kt @@ -32,7 +32,6 @@ fun Session.configureAndStart(pushRuleTriggerListener: PushRuleTriggerListener) startSync(isAtLeastStarted) refreshPushers() pushRuleTriggerListener.startWithSession(this) - fetchPushRules() // TODO P1 From HomeActivity // @Inject lateinit var incomingVerificationRequestHandler: IncomingVerificationRequestHandler diff --git a/vector/src/main/java/im/vector/riotx/core/utils/DimensionUtils.kt b/vector/src/main/java/im/vector/riotx/core/utils/DimensionConverter.kt similarity index 77% rename from vector/src/main/java/im/vector/riotx/core/utils/DimensionUtils.kt rename to vector/src/main/java/im/vector/riotx/core/utils/DimensionConverter.kt index 15257f9c5d..3b8e3ed5cb 100644 --- a/vector/src/main/java/im/vector/riotx/core/utils/DimensionUtils.kt +++ b/vector/src/main/java/im/vector/riotx/core/utils/DimensionConverter.kt @@ -15,25 +15,26 @@ */ package im.vector.riotx.core.utils -import android.content.Context +import android.content.res.Resources import android.util.TypedValue +import javax.inject.Inject -object DimensionUtils { +class DimensionConverter @Inject constructor(val resources: Resources) { - fun dpToPx(dp: Int, context: Context): Int { + fun dpToPx(dp: Int): Int { return TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), - context.resources.displayMetrics + resources.displayMetrics ).toInt() } - fun spToPx(sp: Int, context: Context): Int { + fun spToPx(sp: Int): Int { return TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, sp.toFloat(), - context.resources.displayMetrics + resources.displayMetrics ).toInt() } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt index fa10850590..1e2256825f 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt @@ -204,7 +204,7 @@ class KeyRequestHandler @Inject constructor(private val context: Context) Runnable { alert.weakCurrentActivity?.get()?.let { val intent = SASVerificationActivity.outgoingIntent(it, - session?.sessionParams?.credentials?.userId ?: "", + session?.myUserId ?: "", userId, deviceId) it.startActivity(intent) } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt index 98bd8d34ed..a77ce65c63 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt @@ -60,7 +60,7 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context .apply { contentAction = Runnable { val intent = SASVerificationActivity.incomingIntent(context, - session?.sessionParams?.credentials?.userId ?: "", + session?.myUserId ?: "", tx.otherUserId, tx.transactionId) weakCurrentActivity?.get()?.startActivity(intent) @@ -78,7 +78,7 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context context.getString(R.string.action_open), Runnable { val intent = SASVerificationActivity.incomingIntent(context, - session?.sessionParams?.credentials?.userId ?: "", + session?.myUserId ?: "", tx.otherUserId, tx.transactionId) weakCurrentActivity?.get()?.startActivity(intent) diff --git a/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomKnownUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomKnownUsersFragment.kt index 7747336627..c7aeed645b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomKnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomKnownUsersFragment.kt @@ -36,7 +36,7 @@ import im.vector.riotx.core.extensions.hideKeyboard import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.extensions.setupAsSearch import im.vector.riotx.core.platform.VectorBaseFragment -import im.vector.riotx.core.utils.DimensionUtils +import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.features.home.AvatarRenderer import kotlinx.android.synthetic.main.fragment_create_direct_room.* import javax.inject.Inject @@ -51,6 +51,7 @@ class CreateDirectRoomKnownUsersFragment : VectorBaseFragment(), KnownUsersContr @Inject lateinit var directRoomController: KnownUsersController @Inject lateinit var avatarRenderer: AvatarRenderer + @Inject lateinit var dimensionConverter: DimensionConverter private lateinit var navigationViewModel: CreateDirectRoomNavigationViewModel override fun injectWith(injector: ScreenComponent) { @@ -156,7 +157,7 @@ class CreateDirectRoomKnownUsersFragment : VectorBaseFragment(), KnownUsersContr private fun addChipToGroup(user: User, chipGroup: ChipGroup) { val chip = Chip(requireContext()) chip.setChipBackgroundColorResource(android.R.color.transparent) - chip.chipStrokeWidth = DimensionUtils.dpToPx(1, requireContext()).toFloat() + chip.chipStrokeWidth = dimensionConverter.dpToPx(1).toFloat() chip.text = if (user.displayName.isNullOrBlank()) user.userId else user.displayName chip.isClickable = true chip.isCheckable = false diff --git a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt index 7aff4a327d..0be22e411e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt @@ -26,6 +26,7 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session 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 @@ -93,20 +94,20 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro session .rx() .liveGroupSummaries() + // Keep only joined groups. Group invitations will be managed later + .map { it.filter { groupSummary -> groupSummary.membership == Membership.JOIN } } .map { val myUser = session.getUser(session.myUserId) val allCommunityGroup = GroupSummary( groupId = ALL_COMMUNITIES_GROUP_ID, + membership = Membership.JOIN, displayName = stringProvider.getString(R.string.group_all_communities), avatarUrl = myUser?.avatarUrl ?: "") listOf(allCommunityGroup) + it } .execute { async -> - // TODO Phase2 Handle the case where the selected group is deleted on another client val newSelectedGroup = selectedGroup ?: async()?.firstOrNull() copy(asyncGroups = async, selectedGroup = newSelectedGroup) } } - - } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt new file mode 100644 index 0000000000..b38b02d2f5 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt @@ -0,0 +1,82 @@ +/* + * 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.timeline.factory + +import android.view.View +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.timeline.TimelineEvent +import im.vector.matrix.android.internal.crypto.model.event.EncryptionEventContent +import im.vector.riotx.R +import im.vector.riotx.core.resources.StringProvider +import im.vector.riotx.core.utils.DimensionConverter +import im.vector.riotx.features.home.AvatarRenderer +import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController +import im.vector.riotx.features.home.room.detail.timeline.helper.AvatarSizeProvider +import im.vector.riotx.features.home.room.detail.timeline.helper.senderAvatar +import im.vector.riotx.features.home.room.detail.timeline.helper.senderName +import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData +import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem +import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem_ +import javax.inject.Inject + +class EncryptionItemFactory @Inject constructor(private val stringProvider: StringProvider, + private val avatarRenderer: AvatarRenderer, + private val avatarSizeProvider: AvatarSizeProvider) { + + fun create(event: TimelineEvent, + highlight: Boolean, + callback: TimelineEventController.Callback?): NoticeItem? { + + val text = buildNoticeText(event.root, event.senderName) ?: return null + val informationData = MessageInformationData( + eventId = event.root.eventId ?: "?", + senderId = event.root.senderId ?: "", + sendState = event.root.sendState, + avatarUrl = event.senderAvatar(), + memberName = event.senderName(), + showInformation = false + ) + val attributes = NoticeItem.Attributes( + avatarRenderer = avatarRenderer, + informationData = informationData, + noticeText = text, + itemLongClickListener = View.OnLongClickListener { view -> + callback?.onEventLongClicked(informationData, null, view) ?: false + }, + readReceiptsCallback = callback + ) + return NoticeItem_() + .leftGuideline(avatarSizeProvider.leftGuideline) + .highlighted(highlight) + .attributes(attributes) + } + + private fun buildNoticeText(event: Event, senderName: String?): CharSequence? { + return when { + EventType.ENCRYPTION == event.getClearType() -> { + val content = event.content.toModel() ?: return null + stringProvider.getString(R.string.notice_end_to_end, senderName, content.algorithm) + } + else -> null + } + + } + + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt index 2f774cd9ec..f251a70905 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/NoticeItemFactory.kt @@ -27,12 +27,10 @@ import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem_ import javax.inject.Inject -class NoticeItemFactory @Inject constructor( - private val eventFormatter: NoticeEventFormatter, - private val avatarRenderer: AvatarRenderer, - private val informationDataFactory: MessageInformationDataFactory, - private val avatarSizeProvider: AvatarSizeProvider -) { +class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEventFormatter, + private val avatarRenderer: AvatarRenderer, + private val informationDataFactory: MessageInformationDataFactory, + private val avatarSizeProvider: AvatarSizeProvider) { fun create(event: TimelineEvent, highlight: Boolean, diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/AvatarSizeProvider.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/AvatarSizeProvider.kt index 9fcfdcfdf6..f55fd030b7 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/AvatarSizeProvider.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/AvatarSizeProvider.kt @@ -16,20 +16,19 @@ package im.vector.riotx.features.home.room.detail.timeline.helper -import androidx.appcompat.app.AppCompatActivity -import im.vector.riotx.core.utils.DimensionUtils.dpToPx +import im.vector.riotx.core.utils.DimensionConverter import javax.inject.Inject -class AvatarSizeProvider @Inject constructor(private val context: AppCompatActivity) { +class AvatarSizeProvider @Inject constructor(private val dimensionConverter: DimensionConverter) { private val avatarStyle = AvatarStyle.SMALL val leftGuideline: Int by lazy { - dpToPx(avatarStyle.avatarSizeDP + 8, context) + dimensionConverter.dpToPx(avatarStyle.avatarSizeDP + 8) } val avatarSize: Int by lazy { - dpToPx(avatarStyle.avatarSizeDP, context) + dimensionConverter.dpToPx(avatarStyle.avatarSizeDP) } companion object { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt index a97ec23c97..5b0b64fea7 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt @@ -26,8 +26,7 @@ import im.vector.riotx.core.epoxy.VectorEpoxyModel import im.vector.riotx.core.platform.CheckableView import im.vector.riotx.core.ui.views.ReadMarkerView import im.vector.riotx.core.ui.views.ReadReceiptsView -import im.vector.riotx.core.utils.DimensionUtils.dpToPx -import org.w3c.dom.Attr +import im.vector.riotx.core.utils.DimensionConverter /** * Children must override getViewType() @@ -40,6 +39,9 @@ abstract class BaseEventItem : VectorEpoxyModel @EpoxyAttribute open var leftGuideline: Int = 0 + @EpoxyAttribute + lateinit var dimensionConverter: DimensionConverter + override fun bind(holder: H) { super.bind(holder) holder.leftGuideline.setGuidelineBegin(leftGuideline) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageTextItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageTextItem.kt index 0fb8fd3f8f..2ba2337242 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageTextItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MessageTextItem.kt @@ -24,7 +24,6 @@ import androidx.core.widget.TextViewCompat import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.riotx.R -import im.vector.riotx.core.utils.containsOnlyEmojis import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController import im.vector.riotx.features.html.PillImageSpan import kotlinx.coroutines.Dispatchers @@ -39,6 +38,8 @@ abstract class MessageTextItem : AbsMessageItem() { @EpoxyAttribute var message: CharSequence? = null @EpoxyAttribute + var useBigFont: Boolean = false + @EpoxyAttribute var urlClickCallback: TimelineEventController.UrlClickCallback? = null // Better link movement methods fixes the issue when @@ -65,9 +66,7 @@ abstract class MessageTextItem : AbsMessageItem() { super.bind(holder) holder.messageView.movementMethod = mvmtMethod - - val msg = message ?: "" - if (msg.length <= 4 && containsOnlyEmojis(msg.toString())) { + if (useBigFont) { holder.messageView.textSize = 44F } else { holder.messageView.textSize = 14F diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/widget/FabMenuView.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/widget/FabMenuView.kt index e95a0237ad..9f1f6526c9 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/widget/FabMenuView.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/widget/FabMenuView.kt @@ -63,6 +63,18 @@ class FabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSe } } + override fun transitionToEnd() { + super.transitionToEnd() + + createRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_close) + } + + override fun transitionToStart() { + super.transitionToStart() + + createRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_open) + } + fun show() { isVisible = true createRoomButton.show() diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt index 6e559bcbe0..3c477c8a90 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt @@ -18,6 +18,7 @@ package im.vector.riotx.features.login import android.os.Bundle import android.view.View +import android.view.inputmethod.EditorInfo import android.widget.Toast import androidx.core.view.isVisible import androidx.transition.TransitionManager @@ -68,12 +69,19 @@ class LoginFragment : VectorBaseFragment() { homeServerField.focusChanges() .subscribe { if (!it) { - // TODO Also when clicking on button? viewModel.handle(LoginActions.UpdateHomeServer(homeServerField.text.toString())) } } .disposeOnDestroy() + homeServerField.setOnEditorActionListener { _, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_DONE) { + viewModel.handle(LoginActions.UpdateHomeServer(homeServerField.text.toString())) + return@setOnEditorActionListener true + } + return@setOnEditorActionListener false + } + val initHsUrl = viewModel.getInitialHomeServerUrl() if (initHsUrl != null) { homeServerField.setText(initHsUrl) @@ -170,6 +178,10 @@ class LoginFragment : VectorBaseFragment() { passwordContainer.isVisible = true authenticateButton.isVisible = true authenticateButtonSso.isVisible = false + if (loginField.text.isNullOrBlank() && passwordField.text.isNullOrBlank()) { + //Jump focus to login + loginField.requestFocus() + } } LoginMode.Sso -> { loginField.isVisible = false diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt index 7231089379..2367e1be18 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt @@ -137,16 +137,23 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi } - private fun handleUpdateHomeserver(action: LoginActions.UpdateHomeServer) { - currentTask?.cancel() + private fun handleUpdateHomeserver(action: LoginActions.UpdateHomeServer) = withState { state -> + var newConfig : HomeServerConnectionConfig? = null Try { val homeServerUri = action.homeServerUrl - homeServerConnectionConfig = HomeServerConnectionConfig.Builder() + newConfig = HomeServerConnectionConfig.Builder() .withHomeServerUri(homeServerUri) .build() } + //Do not retry if we already have flows for this config -> causes infinite focus loop + if (newConfig?.homeServerUri?.toString() == homeServerConnectionConfig?.homeServerUri?.toString() + && state.asyncHomeServerLoginFlowRequest is Success) return@withState + + currentTask?.cancel() + homeServerConnectionConfig = newConfig + val homeServerConnectionConfigFinal = homeServerConnectionConfig if (homeServerConnectionConfigFinal == null) { diff --git a/vector/src/main/java/im/vector/riotx/features/media/ImageContentRenderer.kt b/vector/src/main/java/im/vector/riotx/features/media/ImageContentRenderer.kt index 7a7c880ca7..55e7891f3c 100644 --- a/vector/src/main/java/im/vector/riotx/features/media/ImageContentRenderer.kt +++ b/vector/src/main/java/im/vector/riotx/features/media/ImageContentRenderer.kt @@ -32,13 +32,14 @@ import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.glide.GlideApp import im.vector.riotx.core.glide.GlideRequest -import im.vector.riotx.core.utils.DimensionUtils.dpToPx +import im.vector.riotx.core.utils.DimensionConverter import kotlinx.android.parcel.Parcelize import timber.log.Timber import java.io.File import javax.inject.Inject -class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder) { +class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder, + private val dimensionConverter: DimensionConverter) { @Parcelize data class Data( @@ -67,10 +68,12 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder: val (width, height) = processSize(data, mode) imageView.layoutParams.height = height imageView.layoutParams.width = width + // a11y + imageView.contentDescription = data.filename createGlideRequest(data, mode, imageView, width, height) .dontAnimate() - .transform(RoundedCorners(dpToPx(8, imageView.context))) + .transform(RoundedCorners(dimensionConverter.dpToPx(8))) .thumbnail(0.3f) .into(imageView) @@ -79,6 +82,9 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder: fun renderFitTarget(data: Data, mode: Mode, imageView: ImageView, callback: ((Boolean) -> Unit)? = null) { val (width, height) = processSize(data, mode) + // a11y + imageView.contentDescription = data.filename + createGlideRequest(data, mode, imageView, width, height) .listener(object : RequestListener { override fun onLoadFailed(e: GlideException?, @@ -126,6 +132,9 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder: } fun render(data: Data, imageView: BigImageView) { + // a11y + imageView.contentDescription = data.filename + val (width, height) = processSize(data, Mode.THUMBNAIL) val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() val fullSize = contentUrlResolver.resolveFullSize(data.url) diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationAction.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationAction.kt index 869a204cf6..6322ecf998 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationAction.kt @@ -19,23 +19,21 @@ import im.vector.matrix.android.api.pushrules.Action data class NotificationAction( val shouldNotify: Boolean, - val highlight: Boolean = false, - val soundName: String? = null -) { - companion object { - fun extractFrom(ruleActions: List): NotificationAction { - var shouldNotify = false - var highlight = false - var sound: String? = null - ruleActions.forEach { - if (it.type == Action.Type.NOTIFY) shouldNotify = true - if (it.type == Action.Type.DONT_NOTIFY) shouldNotify = false - if (it.type == Action.Type.SET_TWEAK) { - if (it.tweak_action == "highlight") highlight = it.boolValue ?: false - if (it.tweak_action == "sound") sound = it.stringValue - } - } - return NotificationAction(shouldNotify, highlight, sound) + val highlight: Boolean, + val soundName: String? +) + +fun List.toNotificationAction(): NotificationAction { + var shouldNotify = false + var highlight = false + var sound: String? = null + forEach { action -> + when (action) { + is Action.Notify -> shouldNotify = true + is Action.DoNotNotify -> shouldNotify = false + is Action.Highlight -> highlight = action.highlight + is Action.Sound -> sound = action.sound } } -} \ No newline at end of file + return NotificationAction(shouldNotify, highlight, sound) +} diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/PushRuleTriggerListener.kt b/vector/src/main/java/im/vector/riotx/features/notifications/PushRuleTriggerListener.kt index 6711d57a22..7f1c501334 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/PushRuleTriggerListener.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/PushRuleTriggerListener.kt @@ -40,7 +40,7 @@ class PushRuleTriggerListener @Inject constructor( Timber.e("Called without active session") return } - val notificationAction = NotificationAction.extractFrom(actions) + val notificationAction = actions.toNotificationAction() if (notificationAction.shouldNotify) { val notifiableEvent = resolver.resolveEvent(event, session!!) if (notifiableEvent == null) { diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationFragment.kt index 6536c170ee..691618a151 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationFragment.kt @@ -21,6 +21,7 @@ import androidx.preference.Preference import androidx.preference.SwitchPreference import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.pushrules.RuleIds +import im.vector.matrix.android.api.pushrules.RuleKind import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.di.ScreenComponent @@ -45,12 +46,13 @@ class VectorSettingsNotificationPreferenceFragment : VectorSettingsBaseFragment( .find { it.ruleId == RuleIds.RULE_ID_DISABLE_ALL } if (mRuleMaster == null) { + // The home server does not support RULE_ID_DISABLE_ALL, so hide the preference pref.isVisible = false return } - val areNotifEnabledAtAccountLevelt = !mRuleMaster.enabled - (pref as SwitchPreference).isChecked = areNotifEnabledAtAccountLevelt + val areNotifEnabledAtAccountLevel = !mRuleMaster.enabled + (pref as SwitchPreference).isChecked = areNotifEnabledAtAccountLevel } } @@ -114,19 +116,21 @@ class VectorSettingsNotificationPreferenceFragment : VectorSettingsBaseFragment( .find { it.ruleId == RuleIds.RULE_ID_DISABLE_ALL } ?.let { //Trick, we must enable this room to disable notifications - pushRuleService.updatePushRuleEnableStatus("override", it, !switchPref.isChecked, - object : MatrixCallback { + pushRuleService.updatePushRuleEnableStatus(RuleKind.OVERRIDE, + it, + !switchPref.isChecked, + object : MatrixCallback { - override fun onSuccess(data: Unit) { - pushRuleService.fetchPushRules() - } + override fun onSuccess(data: Unit) { + // Push rules will be updated form the sync + } - override fun onFailure(failure: Throwable) { - //revert the check box - switchPref.isChecked = !switchPref.isChecked - Toast.makeText(activity, R.string.unknown_error, Toast.LENGTH_SHORT).show() - } - }) + override fun onFailure(failure: Throwable) { + //revert the check box + switchPref.isChecked = !switchPref.isChecked + Toast.makeText(activity, R.string.unknown_error, Toast.LENGTH_SHORT).show() + } + }) } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/push/PushRuleItem.kt b/vector/src/main/java/im/vector/riotx/features/settings/push/PushRuleItem.kt index 47c9a06a09..5e38a7f7ca 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/push/PushRuleItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/push/PushRuleItem.kt @@ -26,11 +26,11 @@ import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelWithHolder -import im.vector.matrix.android.api.pushrules.Action +import im.vector.matrix.android.api.pushrules.getActions import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.riotx.R import im.vector.riotx.core.epoxy.VectorEpoxyHolder -import im.vector.riotx.features.notifications.NotificationAction +import im.vector.riotx.features.notifications.toNotificationAction @EpoxyModelClass(layout = R.layout.item_pushrule_raw) @@ -50,12 +50,12 @@ abstract class PushRuleItem : EpoxyModelWithHolder() { holder.view.setBackgroundColor(ContextCompat.getColor(context, R.color.vector_silver_color)) holder.ruleId.text = "[Disabled] ${pushRule.ruleId}" } - val actions = Action.mapFrom(pushRule) - if (actions.isNullOrEmpty()) { + val actions = pushRule.getActions() + if (actions.isEmpty()) { holder.actionIcon.isInvisible = true } else { holder.actionIcon.isVisible = true - val notifAction = NotificationAction.extractFrom(actions) + val notifAction = actions.toNotificationAction() if (notifAction.shouldNotify && !notifAction.soundName.isNullOrBlank()) { holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_notify_noisy)) diff --git a/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestAccountSettings.kt b/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestAccountSettings.kt index 47d1f6358a..24c9dc1c1a 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestAccountSettings.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestAccountSettings.kt @@ -17,6 +17,7 @@ package im.vector.riotx.features.settings.troubleshoot import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.pushrules.RuleIds +import im.vector.matrix.android.api.pushrules.RuleKind import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.resources.StringProvider @@ -45,8 +46,7 @@ class TestAccountSettings @Inject constructor(private val stringProvider: String override fun doFix() { if (manager?.diagStatus == TestStatus.RUNNING) return //wait before all is finished - // TODO Use constant for kind - session.updatePushRuleEnableStatus("override", defaultRule, !defaultRule.enabled, + session.updatePushRuleEnableStatus(RuleKind.OVERRIDE, defaultRule, !defaultRule.enabled, object : MatrixCallback { override fun onSuccess(data: Unit) { diff --git a/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestBingRulesSettings.kt b/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestBingRulesSettings.kt index 8f353df282..a58d48061d 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestBingRulesSettings.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestBingRulesSettings.kt @@ -15,12 +15,12 @@ */ package im.vector.riotx.features.settings.troubleshoot -import im.vector.matrix.android.api.pushrules.Action import im.vector.matrix.android.api.pushrules.RuleIds +import im.vector.matrix.android.api.pushrules.getActions import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.resources.StringProvider -import im.vector.riotx.features.notifications.NotificationAction +import im.vector.riotx.features.notifications.toNotificationAction import javax.inject.Inject class TestBingRulesSettings @Inject constructor(private val activeSessionHolder: ActiveSessionHolder, @@ -29,15 +29,15 @@ class TestBingRulesSettings @Inject constructor(private val activeSessionHolder: private val testedRules = listOf(RuleIds.RULE_ID_CONTAIN_DISPLAY_NAME, - RuleIds.RULE_ID_CONTAIN_USER_NAME, - RuleIds.RULE_ID_ONE_TO_ONE_ROOM, - RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS) + RuleIds.RULE_ID_CONTAIN_USER_NAME, + RuleIds.RULE_ID_ONE_TO_ONE_ROOM, + RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS) val ruleSettingsName = arrayOf(R.string.settings_containing_my_display_name, - R.string.settings_containing_my_user_name, - R.string.settings_messages_in_one_to_one, - R.string.settings_messages_in_group_chat) + R.string.settings_containing_my_user_name, + R.string.settings_messages_in_one_to_one, + R.string.settings_messages_in_group_chat) override fun perform() { val session = activeSessionHolder.getSafeActiveSession() ?: return @@ -50,8 +50,8 @@ class TestBingRulesSettings @Inject constructor(private val activeSessionHolder: var oneOrMoreRuleAreSilent = false for ((index, ruleId) in testedRules.withIndex()) { pushRules.find { it.ruleId == ruleId }?.let { rule -> - val actions = Action.mapFrom(rule) ?: return@let - val notifAction = NotificationAction.extractFrom(actions) + val actions = rule.getActions() + val notifAction = actions.toNotificationAction() if (!rule.enabled || !notifAction.shouldNotify) { //off oneOrMoreRuleIsOff = true diff --git a/vector/src/main/res/layout/fragment_home_detail.xml b/vector/src/main/res/layout/fragment_home_detail.xml index 8bc0603013..bda23973ee 100644 --- a/vector/src/main/res/layout/fragment_home_detail.xml +++ b/vector/src/main/res/layout/fragment_home_detail.xml @@ -25,6 +25,7 @@ android:id="@+id/groupToolbarAvatarImageView" android:layout_width="32dp" android:layout_height="32dp" + android:contentDescription="@string/a11y_open_drawer" tools:src="@tools:sample/avatars" /> diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index 0259ca1ea2..30ab86d004 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -30,6 +30,8 @@ android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:layout_marginBottom="16dp" + android:accessibilityTraversalBefore="@+id/roomListEpoxyRecyclerView" + android:contentDescription="@string/a11y_create_direct_message" android:scaleType="center" android:src="@drawable/ic_fab_add_chat" android:visibility="gone" @@ -45,6 +47,8 @@ android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:layout_marginBottom="16dp" + android:accessibilityTraversalBefore="@+id/roomListEpoxyRecyclerView" + android:contentDescription="@string/a11y_create_room" android:src="@drawable/ic_fab_add_room" android:visibility="gone" app:maxImageSize="32dp" diff --git a/vector/src/main/res/layout/merge_composer_layout.xml b/vector/src/main/res/layout/merge_composer_layout.xml index c88495d8ad..641ce666ca 100644 --- a/vector/src/main/res/layout/merge_composer_layout.xml +++ b/vector/src/main/res/layout/merge_composer_layout.xml @@ -71,6 +71,7 @@ android:layout_width="22dp" android:layout_height="22dp" android:background="?android:attr/selectableItemBackground" + android:contentDescription="@string/action_close" android:src="@drawable/ic_close_round" android:tint="@color/riotx_notice" tools:ignore="MissingConstraints" /> @@ -88,6 +89,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:background="?android:attr/selectableItemBackground" + android:contentDescription="@string/send_attachment" android:src="@drawable/ic_attachment" android:tint="?attr/colorAccent" tools:ignore="MissingConstraints" /> @@ -107,6 +109,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:background="?android:attr/selectableItemBackground" + android:contentDescription="@string/send" android:src="@drawable/ic_send" android:tint="?attr/colorAccent" tools:ignore="MissingConstraints" /> diff --git a/vector/src/main/res/layout/motion_fab_menu_merge.xml b/vector/src/main/res/layout/motion_fab_menu_merge.xml index a7f82fe4b1..02ba4341c6 100644 --- a/vector/src/main/res/layout/motion_fab_menu_merge.xml +++ b/vector/src/main/res/layout/motion_fab_menu_merge.xml @@ -13,7 +13,10 @@ android:id="@+id/createRoomTouchGuard" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?riotx_touch_guard_bg" /> + android:background="?riotx_touch_guard_bg" + android:clickable="true" + android:contentDescription="@string/a11y_create_menu_close" + android:focusable="true" /> @@ -43,6 +49,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" + android:accessibilityTraversalBefore="@+id/createRoomItemGroup" + android:contentDescription="@string/a11y_create_direct_message" android:src="@drawable/ic_fab_add_chat" app:backgroundTint="#FFFFFF" app:fabCustomSize="48dp" @@ -57,6 +65,7 @@ android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:ellipsize="end" + android:importantForAccessibility="no" android:text="@string/fab_menu_create_chat" /> @@ -64,6 +73,8 @@ android:id="@+id/createRoomButton" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:accessibilityTraversalBefore="@+id/createRoomItemChat" + android:contentDescription="@string/a11y_create_menu_open" android:src="@drawable/ic_fab_add" app:maxImageSize="14dp" /> diff --git a/vector/src/main/res/layout/view_keys_backup_banner.xml b/vector/src/main/res/layout/view_keys_backup_banner.xml index d073826261..87c92cf8b4 100644 --- a/vector/src/main/res/layout/view_keys_backup_banner.xml +++ b/vector/src/main/res/layout/view_keys_backup_banner.xml @@ -106,6 +106,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" + android:contentDescription="@string/a11y_close_keys_backup_banner" android:src="@drawable/ic_small_close" app:layout_constraintEnd_toEndOf="@id/view_keys_backup_banner_close" app:layout_constraintStart_toStartOf="@id/view_keys_backup_banner_close" diff --git a/vector/src/main/res/menu/home_bottom_navigation.xml b/vector/src/main/res/menu/home_bottom_navigation.xml index 407e57d50a..f93a018436 100644 --- a/vector/src/main/res/menu/home_bottom_navigation.xml +++ b/vector/src/main/res/menu/home_bottom_navigation.xml @@ -3,23 +3,20 @@ + android:title="@string/bottom_action_home" /> + android:title="@string/bottom_action_people_x" /> + android:title="@string/bottom_action_rooms" /> diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index f2ac7817be..6b46d359be 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -13,4 +13,13 @@ Looks like the server is taking to long to respond, this can be caused by either poor connectivity or an error with our servers. Please try again in a while. + Send attachment + + Open the navigation drawer + Open the create room menu + Close the create room menu… + Create a new direct conversation + Create a new room + Close keys backup banner + \ No newline at end of file