diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml
index cf1cd5b9ff..de434d0122 100644
--- a/.buildkite/pipeline.yml
+++ b/.buildkite/pipeline.yml
@@ -3,14 +3,36 @@
# https://github.com/buildkite-plugins/docker-buildkite-plugin/releases
# We propagate the environment to the container (sse https://github.com/buildkite-plugins/docker-buildkite-plugin#propagate-environment-optional-boolean)
-# Build debug version of the RiotX application, from the develop branch and the features branches
-
steps:
- - label: "Assemble GPlay Debug version"
+ - label: "Compile and run Unit tests"
agents:
# We use a medium sized instance instead of the normal small ones because
- # gradle build is long
+ # gradle build can be memory hungry
queue: "medium"
+ commands:
+ - "./gradlew clean test --stacktrace"
+ plugins:
+ - docker#v3.1.0:
+ image: "runmymind/docker-android-sdk"
+ propagate-environment: true
+
+ - label: "Compile Android tests"
+ agents:
+ # We use a medium sized instance instead of the normal small ones because
+ # gradle build can be memory hungry
+ queue: "medium"
+ commands:
+ - "./gradlew clean assembleAndroidTest --stacktrace"
+ plugins:
+ - docker#v3.1.0:
+ image: "runmymind/docker-android-sdk"
+ propagate-environment: true
+
+ - label: "Assemble GPlay Debug version"
+ agents:
+ # We use a xlarge sized instance instead of the normal small ones because
+ # gradle build can be memory hungry
+ queue: "xlarge"
commands:
- "./gradlew clean lintGplayRelease assembleGplayDebug --stacktrace"
artifact_paths:
@@ -23,9 +45,9 @@ steps:
- label: "Assemble FDroid Debug version"
agents:
- # We use a medium sized instance instead of the normal small ones because
- # gradle build is long
- queue: "medium"
+ # We use a xlarge sized instance instead of the normal small ones because
+ # gradle build can be memory hungry
+ queue: "xlarge"
commands:
- "./gradlew clean lintFdroidRelease assembleFdroidDebug --stacktrace"
artifact_paths:
@@ -38,9 +60,9 @@ steps:
- label: "Build Google Play unsigned APK"
agents:
- # We use a medium sized instance instead of the normal small ones because
- # gradle build is long
- queue: "medium"
+ # We use a xlarge sized instance instead of the normal small ones because
+ # gradle build can be memory hungry
+ queue: "xlarge"
commands:
- "./gradlew clean assembleGplayRelease --stacktrace"
artifact_paths:
diff --git a/CHANGES.md b/CHANGES.md
index 48d0be34cd..33ba41e778 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,26 @@
+Changes in RiotX 0.8.0 (2019-11-19)
+===================================================
+
+Features ✨:
+ - Handle long click on room in the room list (#395)
+ - Ignore/UnIgnore users, and display list of ignored users (#542, #617)
+
+Improvements 🙌:
+ - Search reaction by name or keyword in emoji picker
+ - Handle code tags (#567)
+ - Support spoiler messages
+ - Support m.sticker and m.room.join_rules events in timeline
+
+Other changes:
+ - Markdown set to off by default (#412)
+ - Accessibility improvements to the attachment file type chooser
+
+Bugfix 🐛:
+ - Fix issues with some member events rendering (#498)
+ - Passphrase does not match (Export room keys) (#644)
+ - Ask for permission to write external storage when uri comes from the keyboard (#658)
+ - Fix issue with english US/GB translation (#671)
+
Changes in RiotX 0.7.0 (2019-10-24)
===================================================
@@ -12,6 +35,7 @@ Improvements:
- Attachments: start using system pickers (#52)
- Mark all messages as read (#396)
+
Other changes:
- Accessibility improvements to read receipts in the room timeline and reactions emoji chooser
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d64dd7110e..45834afa21 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -86,6 +86,10 @@ Also, if possible, please test your change on a real device. Testing on Android
When adding new string resources, please only add new entries in file `value/strings.xml`. Translations will be added later by the community of translators with a specific tool named [Weblate](https://translate.riot.im/projects/riot-android/).
Do not hesitate to use plurals when appropriate.
+### Accessibility
+
+Please consider accessibility as an important point. As a minimum requirement, in layout XML files please use attributes such as `android:contentDescription` and `android:importantForAccessibility`, and test with a screen reader if it's working well. You can add new string resources, dedicated to accessibility, in this case, please prefix theirs id with `a11y_`.
+
### Layout
When adding or editing layouts, make sure the layout will render correctly if device uses a RTL (Right To Left) language.
diff --git a/matrix-sdk-android-rx/build.gradle b/matrix-sdk-android-rx/build.gradle
index 31f928c241..1d8e81e44f 100644
--- a/matrix-sdk-android-rx/build.gradle
+++ b/matrix-sdk-android-rx/build.gradle
@@ -11,6 +11,8 @@ android {
versionCode 1
versionName "1.0"
+ // Multidex is useful for tests
+ multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/matrix-sdk-android-rx/src/androidTest/java/im/vector/matrix/rx/ExampleInstrumentedTest.java b/matrix-sdk-android-rx/src/androidTest/java/im/vector/matrix/rx/ExampleInstrumentedTest.java
deleted file mode 100644
index 986d40d1a9..0000000000
--- a/matrix-sdk-android-rx/src/androidTest/java/im/vector/matrix/rx/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.matrix.rx;
-
-import android.content.Context;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("im.vector.matrix.rx.test", appContext.getPackageName());
- }
-}
diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt
index e058b2716c..6793d6249d 100644
--- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt
+++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt
@@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
import im.vector.matrix.android.api.session.room.model.ReadReceipt
import im.vector.matrix.android.api.session.room.model.RoomSummary
+import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
import im.vector.matrix.android.api.session.room.send.UserDraft
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.util.Optional
@@ -67,6 +68,10 @@ class RxRoom(private val room: Room) {
fun liveDrafts(): Observable> {
return room.getDraftsLive().asObservable()
}
+
+ fun liveNotificationState(): Observable {
+ return room.getLiveRoomNotificationState().asObservable()
+ }
}
fun Room.rx(): RxRoom {
diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt
index f19777b6f5..1572851d3a 100644
--- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt
+++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt
@@ -54,6 +54,10 @@ class RxSession(private val session: Session) {
return session.liveUsers().asObservable()
}
+ fun liveIgnoredUsers(): Observable> {
+ return session.liveIgnoredUsers().asObservable()
+ }
+
fun livePagedUsers(filter: String? = null): Observable> {
return session.livePagedUsers(filter).asObservable()
}
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index 3e6d3ea88b..ab5f122dbc 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -155,7 +155,8 @@ dependencies {
testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:4.3'
//testImplementation 'org.robolectric:shadows-support-v4:3.0'
- testImplementation 'io.mockk:mockk:1.9.3.kotlin12'
+ // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
+ testImplementation 'io.mockk:mockk:1.9.2.kotlin12'
testImplementation 'org.amshove.kluent:kluent-android:1.44'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
@@ -165,7 +166,8 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
androidTestImplementation 'org.amshove.kluent:kluent-android:1.44'
- androidTestImplementation 'io.mockk:mockk-android:1.9.3.kotlin12'
+ // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
+ androidTestImplementation 'io.mockk:mockk-android:1.9.2.kotlin12'
androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt
index 3cd47d4998..99fe7d29b4 100644
--- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt
@@ -17,12 +17,12 @@
package im.vector.matrix.android
import android.content.Context
-import androidx.test.InstrumentationRegistry
+import androidx.test.core.app.ApplicationProvider
import java.io.File
interface InstrumentedTest {
fun context(): Context {
- return InstrumentationRegistry.getTargetContext()
+ return ApplicationProvider.getApplicationContext()
}
fun cacheDir(): File {
diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt
index 7d33fae4d8..5c86f5ad22 100644
--- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt
@@ -17,8 +17,8 @@
package im.vector.matrix.android.auth
import androidx.test.annotation.UiThreadTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule
-import androidx.test.runner.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.OkReplayRuleChainNoActivity
import im.vector.matrix.android.api.auth.Authenticator
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt
index 77a3cde249..c1dfa465fb 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt
@@ -67,5 +67,5 @@ interface Authenticator {
/**
* Create a session after a SSO successful login
*/
- fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session
+ fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback): Cancelable
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/crypto/Emojis.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/crypto/Emojis.kt
new file mode 100644
index 0000000000..943b2c1b10
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/crypto/Emojis.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.api.crypto
+
+import im.vector.matrix.android.api.session.crypto.sas.EmojiRepresentation
+import im.vector.matrix.android.internal.crypto.verification.getEmojiForCode
+
+/**
+ * Provide all the emojis used for SAS verification (for debug purpose)
+ */
+fun getAllVerificationEmojis(): List {
+ return (0..63).map { getEmojiForCode(it) }
+}
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 d135504055..a81af2cf21 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
@@ -21,7 +21,7 @@ import timber.log.Timber
sealed class Action {
object Notify : Action()
object DoNotNotify : Action()
- data class Sound(val sound: String) : Action()
+ data class Sound(val sound: String = ACTION_OBJECT_VALUE_VALUE_DEFAULT) : Action()
data class Highlight(val highlight: Boolean) : Action()
}
@@ -63,6 +63,29 @@ private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default"
*
*
*/
+
+@Suppress("IMPLICIT_CAST_TO_ANY")
+fun List.toJson(): List {
+ return map { action ->
+ when (action) {
+ is Action.Notify -> ACTION_NOTIFY
+ is Action.DoNotNotify -> ACTION_DONT_NOTIFY
+ is Action.Sound -> {
+ mapOf(
+ ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_SOUND,
+ ACTION_OBJECT_VALUE_KEY to action.sound
+ )
+ }
+ is Action.Highlight -> {
+ mapOf(
+ ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT,
+ ACTION_OBJECT_VALUE_KEY to action.highlight
+ )
+ }
+ }
+ }
+}
+
fun PushRule.getActions(): List {
val result = ArrayList()
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 aa277ea8bd..0ef70eb99b 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
@@ -34,6 +34,10 @@ interface PushRuleService {
fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable
+ fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback): Cancelable
+
+ fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback): Cancelable
+
fun addPushRuleListener(listener: PushRuleListener)
fun removePushRuleListener(listener: PushRuleListener)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt
index f1e4ca6c7b..a84e5af48c 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt
@@ -19,7 +19,7 @@ package im.vector.matrix.android.api.session.cache
import im.vector.matrix.android.api.MatrixCallback
/**
- * This interface defines a method to sign out. It's implemented at the session level.
+ * This interface defines a method to clear the cache. It's implemented at the session level.
*/
interface CacheService {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/LocalEcho.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/LocalEcho.kt
index ca75871cda..1dbee475e0 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/LocalEcho.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/LocalEcho.kt
@@ -16,7 +16,7 @@
package im.vector.matrix.android.api.session.events.model
-import java.util.*
+import java.util.UUID
object LocalEcho {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt
index 70c9c6e36c..90790a6ab0 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt
@@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.room.crypto.RoomCryptoService
import im.vector.matrix.android.api.session.room.members.MembershipService
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.relation.RelationService
+import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService
import im.vector.matrix.android.api.session.room.reporting.ReportingService
import im.vector.matrix.android.api.session.room.read.ReadService
import im.vector.matrix.android.api.session.room.send.DraftService
@@ -41,7 +42,8 @@ interface Room :
StateService,
ReportingService,
RelationService,
- RoomCryptoService {
+ RoomCryptoService,
+ RoomPushRuleService {
/**
* The roomId of this room
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomJoinRules.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomJoinRules.kt
new file mode 100644
index 0000000000..d7cf8678c3
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomJoinRules.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package im.vector.matrix.android.api.session.room.model
+
+import com.squareup.moshi.Json
+
+/**
+ * Enum for [RoomJoinRulesContent] : https://matrix.org/docs/spec/client_server/r0.4.0#m-room-join-rules
+ */
+enum class RoomJoinRules(val value: String) {
+
+ @Json(name = "public")
+ PUBLIC("public"),
+
+ @Json(name = "invite")
+ INVITE("invite"),
+
+ @Json(name = "knock")
+ KNOCK("knock"),
+
+ @Json(name = "private")
+ PRIVATE("private")
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomJoinRulesContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomJoinRulesContent.kt
new file mode 100644
index 0000000000..cf6b182e2d
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomJoinRulesContent.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package im.vector.matrix.android.api.session.room.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ * Class representing the EventType.STATE_ROOM_JOIN_RULES state event content
+ */
+@JsonClass(generateAdapter = true)
+data class RoomJoinRulesContent(
+ @Json(name = "join_rule") val joinRules: RoomJoinRules? = null
+)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageContent.kt
index 107a8b276d..fbac261802 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageContent.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageContent.kt
@@ -38,7 +38,7 @@ data class MessageImageContent(
/**
* Metadata about the image referred to in url.
*/
- @Json(name = "info") val info: ImageInfo? = null,
+ @Json(name = "info") override val info: ImageInfo? = null,
/**
* Required. Required if the file is unencrypted. The URL (typically MXC URI) to the image.
@@ -52,4 +52,4 @@ data class MessageImageContent(
* Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.
*/
@Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null
-) : MessageEncryptedContent
+) : MessageImageInfoContent
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageInfoContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageInfoContent.kt
new file mode 100644
index 0000000000..9087a45b4c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageImageInfoContent.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package im.vector.matrix.android.api.session.room.model.message
+
+/**
+ * A content with image information
+ */
+interface MessageImageInfoContent : MessageEncryptedContent {
+ val info: ImageInfo?
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageStickerContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageStickerContent.kt
new file mode 100644
index 0000000000..d1b4a5c3cb
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageStickerContent.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package im.vector.matrix.android.api.session.room.model.message
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import im.vector.matrix.android.api.session.events.model.Content
+import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultContent
+import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo
+
+@JsonClass(generateAdapter = true)
+data class MessageStickerContent(
+ /**
+ * Set in local, not from server
+ */
+ override val type: String = MessageType.MSGTYPE_STICKER_LOCAL,
+
+ /**
+ * Required. A textual representation of the image. This could be the alt text of the image, the filename of the image,
+ * or some kind of content description for accessibility e.g. 'image attachment'.
+ */
+ @Json(name = "body") override val body: String,
+
+ /**
+ * Metadata about the image referred to in url.
+ */
+ @Json(name = "info") override val info: ImageInfo? = null,
+
+ /**
+ * Required. Required if the file is unencrypted. The URL (typically MXC URI) to the image.
+ */
+ @Json(name = "url") override val url: String? = null,
+
+ @Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
+ @Json(name = "m.new_content") override val newContent: Content? = null,
+
+ /**
+ * Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption.
+ */
+ @Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null
+) : MessageImageInfoContent
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/notification/RoomNotificationState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/notification/RoomNotificationState.kt
new file mode 100644
index 0000000000..a638b2710c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/notification/RoomNotificationState.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.api.session.room.notification
+
+/**
+ * Defines the room notification state
+ */
+enum class RoomNotificationState {
+ /**
+ * All the messages will trigger a noisy notification
+ */
+ ALL_MESSAGES_NOISY,
+
+ /**
+ * All the messages will trigger a notification
+ */
+ ALL_MESSAGES,
+
+ /**
+ * Only the messages with user display name / user name will trigger notifications
+ */
+ MENTIONS_ONLY,
+
+ /**
+ * No notifications
+ */
+ MUTE
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/notification/RoomPushRuleService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/notification/RoomPushRuleService.kt
new file mode 100644
index 0000000000..41cd484ef9
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/notification/RoomPushRuleService.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.api.session.room.notification
+
+import androidx.lifecycle.LiveData
+import im.vector.matrix.android.api.MatrixCallback
+import im.vector.matrix.android.api.util.Cancelable
+
+interface RoomPushRuleService {
+
+ fun getLiveRoomNotificationState(): LiveData
+
+ fun setRoomNotificationState(roomNotificationState: RoomNotificationState, matrixCallback: MatrixCallback): Cancelable
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt
index 43c1544ffd..ad747efee9 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt
@@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
import im.vector.matrix.android.api.session.room.model.ReadReceipt
import im.vector.matrix.android.api.session.room.model.message.MessageContent
+import im.vector.matrix.android.api.session.room.model.message.MessageStickerContent
import im.vector.matrix.android.api.session.room.model.message.isReply
import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
@@ -62,15 +63,11 @@ data class TimelineEvent(
}
fun getDisambiguatedDisplayName(): String {
- return if (isUniqueDisplayName) {
- senderName
- } else {
- senderName?.let { name ->
- "$name (${root.senderId})"
- }
+ return when {
+ senderName.isNullOrBlank() -> root.senderId ?: ""
+ isUniqueDisplayName -> senderName
+ else -> "$senderName (${root.senderId})"
}
- ?: root.senderId
- ?: ""
}
/**
@@ -103,8 +100,14 @@ fun TimelineEvent.getEditedEventId(): String? {
/**
* Get last MessageContent, after a possible edition
*/
-fun TimelineEvent.getLastMessageContent(): MessageContent? = annotations?.editSummary?.aggregatedContent?.toModel()
- ?: root.getClearContent().toModel()
+fun TimelineEvent.getLastMessageContent(): MessageContent? {
+ return if (root.getClearType() == EventType.STICKER) {
+ root.getClearContent().toModel()
+ } else {
+ annotations?.editSummary?.aggregatedContent?.toModel()
+ ?: root.getClearContent().toModel()
+ }
+}
/**
* Get last Message body, after a possible edition
@@ -113,7 +116,8 @@ fun TimelineEvent.getLastMessageBody(): String? {
val lastMessageContent = getLastMessageContent()
if (lastMessageContent != null) {
- return lastMessageContent.newContent?.toModel()?.body ?: lastMessageContent.body
+ return lastMessageContent.newContent?.toModel()?.body
+ ?: lastMessageContent.body
}
return null
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt
index d3de777e34..2a93a876f6 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt
@@ -64,4 +64,19 @@ interface UserService {
* @return a Livedata of users
*/
fun livePagedUsers(filter: String? = null): LiveData>
+
+ /**
+ * Get list of ignored users
+ */
+ fun liveIgnoredUsers(): LiveData>
+
+ /**
+ * Ignore users
+ */
+ fun ignoreUserIds(userIds: List, callback: MatrixCallback): Cancelable
+
+ /**
+ * Un-ignore some users
+ */
+ fun unIgnoreUserIds(userIds: List, callback: MatrixCallback): Cancelable
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt
index bfb9a59956..f83166512e 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt
@@ -21,4 +21,6 @@ import java.lang.reflect.ParameterizedType
typealias JsonDict = Map
+val emptyJsonDict = emptyMap()
+
internal val JSON_DICT_PARAMETERIZED_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt
index e379090677..ff49d4308b 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt
@@ -17,6 +17,7 @@
package im.vector.matrix.android.internal.auth
import android.util.Patterns
+import dagger.Lazy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.api.auth.data.Credentials
@@ -39,10 +40,9 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import javax.inject.Inject
-import javax.inject.Provider
internal class DefaultAuthenticator @Inject constructor(@Unauthenticated
- private val okHttpClient: Provider,
+ private val okHttpClient: Lazy,
private val retrofitFactory: RetrofitFactory,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val sessionParamsStore: SessionParamsStore,
@@ -112,14 +112,27 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated
sessionManager.getOrCreateSession(sessionParams)
}
- override fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session {
+ override fun createSessionFromSso(credentials: Credentials,
+ homeServerConnectionConfig: HomeServerConnectionConfig,
+ callback: MatrixCallback): Cancelable {
+ val job = GlobalScope.launch(coroutineDispatchers.main) {
+ val sessionOrFailure = runCatching {
+ createSessionFromSso(credentials, homeServerConnectionConfig)
+ }
+ sessionOrFailure.foldToCallback(callback)
+ }
+ return CancelableCoroutine(job)
+ }
+
+ private suspend fun createSessionFromSso(credentials: Credentials,
+ homeServerConnectionConfig: HomeServerConnectionConfig): Session = withContext(coroutineDispatchers.computation) {
val sessionParams = SessionParams(credentials, homeServerConnectionConfig)
sessionParamsStore.save(sessionParams)
- return sessionManager.getOrCreateSession(sessionParams)
+ sessionManager.getOrCreateSession(sessionParams)
}
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
- val retrofit = retrofitFactory.create(okHttpClient.get(), homeServerConnectionConfig.homeServerUri.toString())
+ val retrofit = retrofitFactory.create(okHttpClient, homeServerConnectionConfig.homeServerUri.toString())
return retrofit.create(AuthAPI::class.java)
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt
index e1fef7e2eb..17bcb9dc81 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt
@@ -16,7 +16,6 @@
package im.vector.matrix.android.internal.auth
-import arrow.core.Try
import im.vector.matrix.android.api.auth.data.SessionParams
internal interface SessionParamsStore {
@@ -27,9 +26,9 @@ internal interface SessionParamsStore {
fun getAll(): List
- fun save(sessionParams: SessionParams): Try
+ suspend fun save(sessionParams: SessionParams)
- fun delete(userId: String): Try
+ suspend fun delete(userId: String)
- fun deleteAll(): Try
+ suspend fun deleteAll()
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt
index 7ec5d24559..00fde2682e 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt
@@ -16,9 +16,9 @@
package im.vector.matrix.android.internal.auth.db
-import arrow.core.Try
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.internal.auth.SessionParamsStore
+import im.vector.matrix.android.internal.database.awaitTransaction
import im.vector.matrix.android.internal.di.AuthDatabase
import io.realm.Realm
import io.realm.RealmConfiguration
@@ -62,41 +62,29 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
return sessionParams
}
- override fun save(sessionParams: SessionParams): Try {
- return Try {
+ override suspend fun save(sessionParams: SessionParams) {
+ awaitTransaction(realmConfiguration) {
val entity = mapper.map(sessionParams)
if (entity != null) {
- val realm = Realm.getInstance(realmConfiguration)
- realm.executeTransaction {
- it.insert(entity)
- }
- realm.close()
+ it.insert(entity)
}
}
}
- override fun delete(userId: String): Try {
- return Try {
- val realm = Realm.getInstance(realmConfiguration)
- realm.executeTransaction {
- it.where(SessionParamsEntity::class.java)
- .equalTo(SessionParamsEntityFields.USER_ID, userId)
- .findAll()
- .deleteAllFromRealm()
- }
- realm.close()
+ override suspend fun delete(userId: String) {
+ awaitTransaction(realmConfiguration) {
+ it.where(SessionParamsEntity::class.java)
+ .equalTo(SessionParamsEntityFields.USER_ID, userId)
+ .findAll()
+ .deleteAllFromRealm()
}
}
- override fun deleteAll(): Try {
- return Try {
- val realm = Realm.getInstance(realmConfiguration)
- realm.executeTransaction {
- it.where(SessionParamsEntity::class.java)
- .findAll()
- .deleteAllFromRealm()
- }
- realm.close()
+ override suspend fun deleteAll() {
+ awaitTransaction(realmConfiguration) {
+ it.where(SessionParamsEntity::class.java)
+ .findAll()
+ .deleteAllFromRealm()
}
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt
index 7f2a23e4c2..b2002f0916 100755
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt
@@ -66,7 +66,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
if (':' in userId) {
try {
synchronized(notReadyToRetryHS) {
- res = !notReadyToRetryHS.contains(userId.substring(userId.lastIndexOf(":") + 1))
+ res = !notReadyToRetryHS.contains(userId.substringAfterLast(':'))
}
} catch (e: Exception) {
Timber.e(e, "## canRetryKeysDownload() failed")
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequestManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequestManager.kt
index 89a27c9463..86e8a1825c 100755
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequestManager.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/OutgoingRoomKeyRequestManager.kt
@@ -216,7 +216,7 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
sendMessageToDevices(requestMessage, request.recipients, request.requestId, object : MatrixCallback {
private fun onDone(state: OutgoingRoomKeyRequest.RequestState) {
if (request.state !== OutgoingRoomKeyRequest.RequestState.UNSENT) {
- Timber.v("## sendOutgoingRoomKeyRequest() : Cannot update room key request from UNSENT as it was already updated to " + request.state)
+ Timber.v("## sendOutgoingRoomKeyRequest() : Cannot update room key request from UNSENT as it was already updated to ${request.state}")
} else {
request.state = state
cryptoStore.updateOutgoingRoomKeyRequest(request)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt
index 5ef2b9b1a2..81988fe209 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt
@@ -41,8 +41,7 @@ fun doWithRealm(realmConfiguration: RealmConfiguration, action: (Realm) -> T
*/
fun doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? {
return Realm.getInstance(realmConfiguration).use { realm ->
- val result = action.invoke(realm)
- result?.let { realm.copyFromRealm(it) }
+ action.invoke(realm)?.let { realm.copyFromRealm(it) }
}
}
@@ -51,8 +50,7 @@ fun doRealmQueryAndCopy(realmConfiguration: RealmConfiguration
*/
fun doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable): Iterable {
return Realm.getInstance(realmConfiguration).use { realm ->
- val result = action.invoke(realm)
- realm.copyFromRealm(result)
+ action.invoke(realm).let { realm.copyFromRealm(it) }
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt
index d88a84de9e..8a3b66dfe5 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt
@@ -91,7 +91,7 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
realmLocker = Realm.getInstance(realmConfiguration)
// Ensure CryptoMetadataEntity is inserted in DB
- doWithRealm(realmConfiguration) { realm ->
+ doRealmTransaction(realmConfiguration) { realm ->
var currentMetadata = realm.where().findFirst()
var deleteAll = false
@@ -109,15 +109,13 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
}
if (currentMetadata == null) {
- realm.executeTransaction {
- if (deleteAll) {
- it.deleteAll()
- }
+ if (deleteAll) {
+ realm.deleteAll()
+ }
- // Metadata not found, or database cleaned, create it
- it.createObject(CryptoMetadataEntity::class.java, credentials.userId).apply {
- deviceId = credentials.deviceId
- }
+ // Metadata not found, or database cleaned, create it
+ realm.createObject(CryptoMetadataEntity::class.java, credentials.userId).apply {
+ deviceId = credentials.deviceId
}
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
index ca1157e583..e0cd47e0e0 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
@@ -43,6 +43,7 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
+import java.lang.Exception
import java.util.UUID
import javax.inject.Inject
import kotlin.collections.HashMap
@@ -166,72 +167,59 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
return
}
// Download device keys prior to everything
- checkKeysAreDownloaded(
- otherUserId!!,
- startReq,
- success = {
- Timber.v("## SAS onStartRequestReceived ${startReq.transactionID!!}")
- val tid = startReq.transactionID!!
- val existing = getExistingTransaction(otherUserId, tid)
- val existingTxs = getExistingTransactionsForUser(otherUserId)
- if (existing != null) {
- // should cancel both!
- Timber.v("## SAS onStartRequestReceived - Request exist with same if ${startReq.transactionID!!}")
- existing.cancel(CancelCode.UnexpectedMessage)
- cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
- } else if (existingTxs?.isEmpty() == false) {
- Timber.v("## SAS onStartRequestReceived - There is already a transaction with this user ${startReq.transactionID!!}")
- // Multiple keyshares between two devices: any two devices may only have at most one key verification in flight at a time.
- existingTxs.forEach {
- it.cancel(CancelCode.UnexpectedMessage)
- }
- cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
- } else {
- // Ok we can create
- if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) {
- Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}")
- val tx = IncomingSASVerificationTransaction(
- this,
- setDeviceVerificationAction,
- credentials,
- cryptoStore,
- sendToDeviceTask,
- taskExecutor,
- myDeviceInfoHolder.get().myDevice.fingerprint()!!,
- startReq.transactionID!!,
- otherUserId)
- addTransaction(tx)
- tx.acceptToDeviceEvent(otherUserId, startReq)
- } else {
- Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}")
- cancelTransaction(tid, otherUserId, startReq.fromDevice
- ?: event.getSenderKey()!!, CancelCode.UnknownMethod)
- }
- }
- },
- error = {
- cancelTransaction(startReq.transactionID!!, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
- })
+ if (checkKeysAreDownloaded(otherUserId!!, startReq) != null) {
+ Timber.v("## SAS onStartRequestReceived ${startReq.transactionID!!}")
+ val tid = startReq.transactionID!!
+ val existing = getExistingTransaction(otherUserId, tid)
+ val existingTxs = getExistingTransactionsForUser(otherUserId)
+ if (existing != null) {
+ // should cancel both!
+ Timber.v("## SAS onStartRequestReceived - Request exist with same if ${startReq.transactionID!!}")
+ existing.cancel(CancelCode.UnexpectedMessage)
+ cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
+ } else if (existingTxs?.isEmpty() == false) {
+ Timber.v("## SAS onStartRequestReceived - There is already a transaction with this user ${startReq.transactionID!!}")
+ // Multiple keyshares between two devices: any two devices may only have at most one key verification in flight at a time.
+ existingTxs.forEach {
+ it.cancel(CancelCode.UnexpectedMessage)
+ }
+ cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
+ } else {
+ // Ok we can create
+ if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) {
+ Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}")
+ val tx = IncomingSASVerificationTransaction(
+ this,
+ setDeviceVerificationAction,
+ credentials,
+ cryptoStore,
+ sendToDeviceTask,
+ taskExecutor,
+ myDeviceInfoHolder.get().myDevice.fingerprint()!!,
+ startReq.transactionID!!,
+ otherUserId)
+ addTransaction(tx)
+ tx.acceptToDeviceEvent(otherUserId, startReq)
+ } else {
+ Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}")
+ cancelTransaction(tid, otherUserId, startReq.fromDevice
+ ?: event.getSenderKey()!!, CancelCode.UnknownMethod)
+ }
+ }
+ } else {
+ cancelTransaction(startReq.transactionID!!, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
+ }
}
private suspend fun checkKeysAreDownloaded(otherUserId: String,
- startReq: KeyVerificationStart,
- success: (MXUsersDevicesMap) -> Unit,
- error: () -> Unit) {
- runCatching {
- deviceListManager.downloadKeys(listOf(otherUserId), true)
- }.fold(
- {
- if (it.getUserDeviceIds(otherUserId)?.contains(startReq.fromDevice) == true) {
- success(it)
- } else {
- error()
- }
- },
- {
- error()
- }
- )
+ startReq: KeyVerificationStart): MXUsersDevicesMap? {
+ return try {
+ val keys = deviceListManager.downloadKeys(listOf(otherUserId), true)
+ val deviceIds = keys.getUserDeviceIds(otherUserId) ?: return null
+ keys.takeIf { deviceIds.contains(startReq.fromDevice) }
+ } catch (e: Exception) {
+ null
+ }
}
private suspend fun onCancelReceived(event: Event) {
@@ -342,10 +330,8 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
private fun addTransaction(tx: VerificationTransaction) {
tx.otherUserId.let { otherUserId ->
synchronized(txMap) {
- if (txMap[otherUserId] == null) {
- txMap[otherUserId] = HashMap()
- }
- txMap[otherUserId]?.set(tx.transactionId, tx)
+ val txInnerMap = txMap.getOrPut(otherUserId) { HashMap() }
+ txInnerMap[tx.transactionId] = tx
dispatchTxAdded(tx)
tx.addListener(this)
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/AsyncTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/AsyncTransaction.kt
index 36e68e5cf3..0f8445d20f 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/AsyncTransaction.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/AsyncTransaction.kt
@@ -20,14 +20,19 @@ import io.realm.RealmConfiguration
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
+import timber.log.Timber
-suspend fun awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> Unit) = withContext(Dispatchers.IO) {
+suspend fun awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> Unit) = withContext(Dispatchers.Default) {
Realm.getInstance(config).use { bgRealm ->
bgRealm.beginTransaction()
try {
+ val start = System.currentTimeMillis()
transaction(bgRealm)
if (isActive) {
bgRealm.commitTransaction()
+ val end = System.currentTimeMillis()
+ val time = end - start
+ Timber.v("Execute transaction in $time millis")
}
} finally {
if (bgRealm.isInTransaction) {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt
index 24765c120d..36ed2f7edf 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt
@@ -39,14 +39,17 @@ internal fun TimelineEventEntity.updateSenderData() {
val isUnlinked = chunkEntity.isUnlinked()
var senderMembershipEvent: EventEntity?
var senderRoomMemberContent: String?
+ var senderRoomMemberPrevContent: String?
when {
stateIndex <= 0 -> {
senderMembershipEvent = chunkEntity.timelineEvents.buildQuery(senderId, isUnlinked).next(from = stateIndex)?.root
senderRoomMemberContent = senderMembershipEvent?.prevContent
+ senderRoomMemberPrevContent = senderMembershipEvent?.content
}
else -> {
senderMembershipEvent = chunkEntity.timelineEvents.buildQuery(senderId, isUnlinked).prev(since = stateIndex)?.root
senderRoomMemberContent = senderMembershipEvent?.content
+ senderRoomMemberPrevContent = senderMembershipEvent?.prevContent
}
}
@@ -58,11 +61,27 @@ internal fun TimelineEventEntity.updateSenderData() {
.equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_MEMBER)
.prev(since = stateIndex)
senderRoomMemberContent = senderMembershipEvent?.content
+ senderRoomMemberPrevContent = senderMembershipEvent?.prevContent
+ }
+
+ ContentMapper.map(senderRoomMemberContent).toModel()?.also {
+ this.senderAvatar = it.avatarUrl
+ this.senderName = it.displayName
+ this.isUniqueDisplayName = RoomMembers(realm, roomId).isUniqueDisplayName(it.displayName)
+ }
+
+ // We try to fallback on prev content if we got a room member state events with null fields
+ if (root?.type == EventType.STATE_ROOM_MEMBER) {
+ ContentMapper.map(senderRoomMemberPrevContent).toModel()?.also {
+ if (this.senderAvatar == null && it.avatarUrl != null) {
+ this.senderAvatar = it.avatarUrl
+ }
+ if (this.senderName == null && it.displayName != null) {
+ this.senderName = it.displayName
+ this.isUniqueDisplayName = RoomMembers(realm, roomId).isUniqueDisplayName(it.displayName)
+ }
+ }
}
- val senderRoomMember: RoomMember? = ContentMapper.map(senderRoomMemberContent).toModel()
- this.senderAvatar = senderRoomMember?.avatarUrl
- this.senderName = senderRoomMember?.displayName
- this.isUniqueDisplayName = RoomMembers(realm, roomId).isUniqueDisplayName(senderRoomMember?.displayName)
this.senderMembershipEvent = senderMembershipEvent
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt
index 5db062b000..2577bec581 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt
@@ -22,7 +22,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
-import java.util.*
+import java.util.UUID
import javax.inject.Inject
internal class RoomSummaryMapper @Inject constructor(
@@ -36,7 +36,7 @@ internal class RoomSummaryMapper @Inject constructor(
}
val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let {
- timelineEventMapper.map(it)
+ timelineEventMapper.map(it, buildReadReceipts = false)
}
if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) {
// TODO use a global event decryptor? attache to session and that listen to new sessionId?
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/IgnoredUserEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/IgnoredUserEntity.kt
new file mode 100644
index 0000000000..bd31046f82
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/IgnoredUserEntity.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.database.model
+
+import io.realm.RealmObject
+
+internal open class IgnoredUserEntity(var userId: String = "") : RealmObject() {
+
+ companion object
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRuleEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRuleEntity.kt
index 4744c8d053..1ef65d9dea 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRuleEntity.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/PushRuleEntity.kt
@@ -17,6 +17,8 @@ package im.vector.matrix.android.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
+import io.realm.RealmResults
+import io.realm.annotations.LinkingObjects
internal open class PushRuleEntity(
// Required. The actions to perform when this rule is matched.
@@ -33,5 +35,8 @@ internal open class PushRuleEntity(
var pattern: String? = null
) : RealmObject() {
+ @LinkingObjects("pushRules")
+ val parent: RealmResults? = null
+
companion object
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt
index 21b2fdce5a..76b355b064 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt
@@ -35,6 +35,7 @@ import io.realm.annotations.RealmModule
RoomTagEntity::class,
SyncEntity::class,
UserEntity::class,
+ IgnoredUserEntity::class,
EventAnnotationsSummaryEntity::class,
ReactionAggregatedSummaryEntity::class,
EditAggregatedSummaryEntity::class,
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/FilterEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/FilterEntityQueries.kt
index 8fbbb1311e..4f64f2896f 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/FilterEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/FilterEntityQueries.kt
@@ -16,27 +16,26 @@
package im.vector.matrix.android.internal.database.query
+import im.vector.matrix.android.internal.database.awaitTransaction
import im.vector.matrix.android.internal.database.model.FilterEntity
import im.vector.matrix.android.internal.session.filter.FilterFactory
import io.realm.Realm
-import io.realm.kotlin.createObject
import io.realm.kotlin.where
/**
* Get the current filter, create one if it does not exist
*/
-internal fun FilterEntity.Companion.getFilter(realm: Realm): FilterEntity {
+internal suspend fun FilterEntity.Companion.getFilter(realm: Realm): FilterEntity {
var filter = realm.where().findFirst()
if (filter == null) {
- realm.executeTransaction {
- realm.createObject().apply {
- filterBodyJson = FilterFactory.createDefaultFilterBody().toJSONString()
- roomEventFilterJson = FilterFactory.createDefaultRoomFilter().toJSONString()
- filterId = ""
- }
+ filter = FilterEntity().apply {
+ filterBodyJson = FilterFactory.createDefaultFilterBody().toJSONString()
+ roomEventFilterJson = FilterFactory.createDefaultRoomFilter().toJSONString()
+ filterId = ""
+ }
+ awaitTransaction(realm.configuration) {
+ it.insert(filter)
}
- filter = realm.where().findFirst()!!
}
-
return filter
}
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 4ecb40a7e1..42e7770114 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
@@ -16,10 +16,10 @@
package im.vector.matrix.android.internal.database.query
import im.vector.matrix.android.api.pushrules.RuleKind
+import im.vector.matrix.android.internal.database.model.*
+import im.vector.matrix.android.internal.database.model.PushRuleEntity
import im.vector.matrix.android.internal.database.model.PushRulesEntity
-import im.vector.matrix.android.internal.database.model.PushRulesEntityFields
import im.vector.matrix.android.internal.database.model.PusherEntity
-import im.vector.matrix.android.internal.database.model.PusherEntityFields
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.kotlin.where
@@ -41,3 +41,11 @@ internal fun PushRulesEntity.Companion.where(realm: Realm,
.equalTo(PushRulesEntityFields.SCOPE, scope)
.equalTo(PushRulesEntityFields.KIND_STR, kind.name)
}
+
+internal fun PushRuleEntity.Companion.where(realm: Realm,
+ scope: String,
+ ruleId: String): RealmQuery {
+ return realm.where()
+ .equalTo("${PushRuleEntityFields.PARENT}.${PushRulesEntityFields.SCOPE}", scope)
+ .equalTo(PushRuleEntityFields.RULE_ID, ruleId)
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt
index e0a507f939..6b996d1285 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt
@@ -24,8 +24,7 @@ import io.realm.kotlin.where
internal fun ReadReceiptEntity.Companion.where(realm: Realm, roomId: String, userId: String): RealmQuery {
return realm.where()
- .equalTo(ReadReceiptEntityFields.ROOM_ID, roomId)
- .equalTo(ReadReceiptEntityFields.USER_ID, userId)
+ .equalTo(ReadReceiptEntityFields.PRIMARY_KEY, buildPrimaryKey(roomId, userId))
}
internal fun ReadReceiptEntity.Companion.whereUserId(realm: Realm, userId: String): RealmQuery {
@@ -45,8 +44,10 @@ internal fun ReadReceiptEntity.Companion.createUnmanaged(roomId: String, eventId
internal fun ReadReceiptEntity.Companion.getOrCreate(realm: Realm, roomId: String, userId: String): ReadReceiptEntity {
return ReadReceiptEntity.where(realm, roomId, userId).findFirst()
- ?: realm.createObject(ReadReceiptEntity::class.java, "${roomId}_$userId").apply {
+ ?: realm.createObject(ReadReceiptEntity::class.java, buildPrimaryKey(roomId, userId)).apply {
this.roomId = roomId
this.userId = userId
}
}
+
+private fun buildPrimaryKey(roomId: String, userId: String) = "${roomId}_$userId"
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt
index 49474e8e6b..3bd035c0b1 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt
@@ -111,7 +111,7 @@ internal fun RealmQuery.prev(since: Int? = null, strict: Bo
internal fun RealmList.find(eventId: String): TimelineEventEntity? {
return this.where()
- .equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, eventId)
+ .equalTo(TimelineEventEntityFields.EVENT_ID, eventId)
.findFirst()
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt
index 811950ac15..c17864b82b 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt
@@ -36,7 +36,7 @@ internal object MatrixModule {
@MatrixScope
fun providesMatrixCoroutineDispatchers(): MatrixCoroutineDispatchers {
return MatrixCoroutineDispatchers(io = Dispatchers.IO,
- computation = Dispatchers.IO,
+ computation = Dispatchers.Default,
main = Dispatchers.Main,
crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(),
sync = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
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 d8db462f7c..96cdf29226 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
@@ -20,10 +20,11 @@ import com.squareup.moshi.Moshi
import im.vector.matrix.android.api.session.room.model.message.*
import im.vector.matrix.android.internal.network.parsing.RuntimeJsonAdapterFactory
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
+import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
+import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataDirectMessages
+import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataFallback
+import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataIgnoredUsers
+import im.vector.matrix.android.internal.session.sync.model.accountdata.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(UserAccountDataIgnoredUsers::class.java, UserAccountData.TYPE_IGNORED_USER_LIST)
.registerSubtype(UserAccountDataPushRules::class.java, UserAccountData.TYPE_PUSH_RULES)
)
.add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
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 bfc37d733d..3d850c223a 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
@@ -22,7 +22,7 @@ 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 java.util.Collections
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt
index 15e6f76381..44ccd7c941 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt
@@ -17,17 +17,24 @@
package im.vector.matrix.android.internal.network
import com.squareup.moshi.Moshi
+import dagger.Lazy
+import okhttp3.Call
import okhttp3.OkHttpClient
+import okhttp3.Request
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Inject
class RetrofitFactory @Inject constructor(private val moshi: Moshi) {
- fun create(okHttpClient: OkHttpClient, baseUrl: String): Retrofit {
+ fun create(okHttpClient: Lazy, baseUrl: String): Retrofit {
return Retrofit.Builder()
.baseUrl(baseUrl)
- .client(okHttpClient)
+ .callFactory(object : Call.Factory {
+ override fun newCall(request: Request): Call {
+ return okHttpClient.get().newCall(request)
+ }
+ })
.addConverterFactory(UnitConverterFactory)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
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 d038630a74..0e88894969 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
@@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session
import android.content.Context
import com.zhuinden.monarchy.Monarchy
import dagger.Binds
+import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntoSet
@@ -132,7 +133,7 @@ internal abstract class SessionModule {
@JvmStatic
@Provides
@SessionScope
- fun providesRetrofit(@Authenticated okHttpClient: OkHttpClient,
+ fun providesRetrofit(@Authenticated okHttpClient: Lazy,
sessionParams: SessionParams,
retrofitFactory: RetrofitFactory): Retrofit {
return retrofitFactory
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterRepository.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterRepository.kt
index 02e6db189a..53967784a1 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterRepository.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterRepository.kt
@@ -16,54 +16,44 @@
package im.vector.matrix.android.internal.session.filter
+import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.FilterEntity
import im.vector.matrix.android.internal.database.model.FilterEntityFields
import im.vector.matrix.android.internal.database.query.getFilter
-import im.vector.matrix.android.internal.di.SessionDatabase
+import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
-import io.realm.RealmConfiguration
import io.realm.kotlin.where
import javax.inject.Inject
-internal class DefaultFilterRepository @Inject constructor(
- @SessionDatabase private val realmConfiguration: RealmConfiguration
-) : FilterRepository {
+internal class DefaultFilterRepository @Inject constructor(private val monarchy: Monarchy) : FilterRepository {
- override fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean {
- val result: Boolean
+ override suspend fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean {
+ return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
+ val filter = FilterEntity.getFilter(realm)
+ val result = if (filter.filterBodyJson != filterBody.toJSONString()) {
+ // Filter has changed, store it and reset the filter Id
+ monarchy.awaitTransaction {
+ // We manage only one filter for now
+ val filterBodyJson = filterBody.toJSONString()
+ val roomEventFilterJson = roomEventFilter.toJSONString()
- val realm = Realm.getInstance(realmConfiguration)
+ val filterEntity = FilterEntity.getFilter(it)
- val filter = FilterEntity.getFilter(realm)
-
- if (filter.filterBodyJson != filterBody.toJSONString()) {
- // Filter has changed, store it and reset the filter Id
- realm.executeTransaction {
- // We manage only one filter for now
- val filterBodyJson = filterBody.toJSONString()
- val roomEventFilterJson = roomEventFilter.toJSONString()
-
- val filterEntity = FilterEntity.getFilter(it)
-
- filterEntity.filterBodyJson = filterBodyJson
- filterEntity.roomEventFilterJson = roomEventFilterJson
- // Reset filterId
- filterEntity.filterId = ""
+ filterEntity.filterBodyJson = filterBodyJson
+ filterEntity.roomEventFilterJson = roomEventFilterJson
+ // Reset filterId
+ filterEntity.filterId = ""
+ }
+ true
+ } else {
+ filter.filterId.isBlank()
}
- result = true
- } else {
- result = filter.filterId.isBlank()
+ result
}
-
- realm.close()
-
- return result
}
- override fun storeFilterId(filterBody: FilterBody, filterId: String) {
- val realm = Realm.getInstance(realmConfiguration)
-
- realm.executeTransaction {
+ override suspend fun storeFilterId(filterBody: FilterBody, filterId: String) {
+ monarchy.awaitTransaction {
// We manage only one filter for now
val filterBodyJson = filterBody.toJSONString()
@@ -73,39 +63,24 @@ internal class DefaultFilterRepository @Inject constructor(
?.findFirst()
?.filterId = filterId
}
-
- realm.close()
}
- override fun getFilter(): String {
- val result: String
-
- val realm = Realm.getInstance(realmConfiguration)
-
- val filter = FilterEntity.getFilter(realm)
-
- result = if (filter.filterId.isBlank()) {
- // Use the Json format
- filter.filterBodyJson
- } else {
- // Use FilterId
- filter.filterId
+ override suspend fun getFilter(): String {
+ return Realm.getInstance(monarchy.realmConfiguration).use {
+ val filter = FilterEntity.getFilter(it)
+ if (filter.filterId.isBlank()) {
+ // Use the Json format
+ filter.filterBodyJson
+ } else {
+ // Use FilterId
+ filter.filterId
+ }
}
-
- realm.close()
-
- return result
}
- override fun getRoomFilter(): String {
- val realm = Realm.getInstance(realmConfiguration)
-
- val filter = FilterEntity.getFilter(realm)
-
- val result = filter.roomEventFilterJson
-
- realm.close()
-
- return result
+ override suspend fun getRoomFilter(): String {
+ return Realm.getInstance(monarchy.realmConfiguration).use {
+ FilterEntity.getFilter(it).roomEventFilterJson
+ }
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterService.kt
index 84e820ebca..c85d949d0a 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/DefaultFilterService.kt
@@ -21,36 +21,13 @@ import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import javax.inject.Inject
-internal class DefaultFilterService @Inject constructor(private val filterRepository: FilterRepository,
- private val saveFilterTask: SaveFilterTask,
+internal class DefaultFilterService @Inject constructor(private val saveFilterTask: SaveFilterTask,
private val taskExecutor: TaskExecutor) : FilterService {
// TODO Pass a list of support events instead
override fun setFilter(filterPreset: FilterService.FilterPreset) {
- val filterBody = when (filterPreset) {
- FilterService.FilterPreset.RiotFilter -> {
- FilterFactory.createRiotFilterBody()
- }
- FilterService.FilterPreset.NoFilter -> {
- FilterFactory.createDefaultFilterBody()
- }
- }
-
- val roomFilter = when (filterPreset) {
- FilterService.FilterPreset.RiotFilter -> {
- FilterFactory.createRiotRoomFilter()
- }
- FilterService.FilterPreset.NoFilter -> {
- FilterFactory.createDefaultRoomFilter()
- }
- }
-
- val updated = filterRepository.storeFilter(filterBody, roomFilter)
-
- if (updated) {
- saveFilterTask
- .configureWith(SaveFilterTask.Params(filterBody))
- .executeBy(taskExecutor)
- }
+ saveFilterTask
+ .configureWith(SaveFilterTask.Params(filterPreset))
+ .executeBy(taskExecutor)
}
}
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 b98049675e..08985bf17d 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,18 +16,19 @@
package im.vector.matrix.android.internal.session.filter
+import im.vector.matrix.android.api.session.sync.FilterService
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
/**
- * Save a filter to the server
+ * Save a filter, in db and if any changes, upload to the server
*/
internal interface SaveFilterTask : Task {
data class Params(
- val filter: FilterBody
+ val filterPreset: FilterService.FilterPreset
)
}
@@ -37,10 +38,29 @@ internal class DefaultSaveFilterTask @Inject constructor(@UserId private val use
) : SaveFilterTask {
override suspend fun execute(params: SaveFilterTask.Params) {
- val filterResponse = executeRequest {
- // TODO auto retry
- apiCall = filterAPI.uploadFilter(userId, params.filter)
+ val filterBody = when (params.filterPreset) {
+ FilterService.FilterPreset.RiotFilter -> {
+ FilterFactory.createRiotFilterBody()
+ }
+ FilterService.FilterPreset.NoFilter -> {
+ FilterFactory.createDefaultFilterBody()
+ }
+ }
+ val roomFilter = when (params.filterPreset) {
+ FilterService.FilterPreset.RiotFilter -> {
+ FilterFactory.createRiotRoomFilter()
+ }
+ FilterService.FilterPreset.NoFilter -> {
+ FilterFactory.createDefaultRoomFilter()
+ }
+ }
+ val updated = filterRepository.storeFilter(filterBody, roomFilter)
+ if (updated) {
+ val filterResponse = executeRequest {
+ // TODO auto retry
+ apiCall = filterAPI.uploadFilter(userId, filterBody)
+ }
+ filterRepository.storeFilterId(filterBody, filterResponse.filterId)
}
- filterRepository.storeFilterId(params.filter, filterResponse.filterId)
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterRepository.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterRepository.kt
index 092d9ff766..d205ea8a87 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterRepository.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/filter/FilterRepository.kt
@@ -21,20 +21,20 @@ internal interface FilterRepository {
/**
* Return true if the filterBody has changed, or need to be sent to the server
*/
- fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean
+ suspend fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean
/**
* Set the filterId of this filter
*/
- fun storeFilterId(filterBody: FilterBody, filterId: String)
+ suspend fun storeFilterId(filterBody: FilterBody, filterId: String)
/**
* Return filter json or filter id
*/
- fun getFilter(): String
+ suspend fun getFilter(): String
/**
* Return the room filter
*/
- fun getRoomFilter(): String
+ suspend fun getRoomFilter(): String
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt
index 98ab0b5389..45571286b9 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/homeserver/DefaultGetHomeServerCapabilitiesTask.kt
@@ -23,7 +23,7 @@ import im.vector.matrix.android.internal.database.query.getOrCreate
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 java.util.*
+import java.util.Date
import javax.inject.Inject
internal interface GetHomeServerCapabilitiesTask : Task
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 82b928fc54..9121202649 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
@@ -28,7 +28,9 @@ import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
import im.vector.matrix.android.internal.database.model.PushRulesEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.SessionScope
+import im.vector.matrix.android.internal.session.pushers.AddPushRuleTask
import im.vector.matrix.android.internal.session.pushers.GetPushRulesTask
+import im.vector.matrix.android.internal.session.pushers.RemovePushRuleTask
import im.vector.matrix.android.internal.session.pushers.UpdatePushRuleEnableStatusTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
@@ -38,6 +40,8 @@ import javax.inject.Inject
@SessionScope
internal class DefaultPushRuleService @Inject constructor(private val getPushRulesTask: GetPushRulesTask,
private val updatePushRuleEnableStatusTask: UpdatePushRuleEnableStatusTask,
+ private val addPushRuleTask: AddPushRuleTask,
+ private val removePushRuleTask: RemovePushRuleTask,
private val taskExecutor: TaskExecutor,
private val monarchy: Monarchy
) : PushRuleService {
@@ -98,6 +102,22 @@ internal class DefaultPushRuleService @Inject constructor(private val getPushRul
.executeBy(taskExecutor)
}
+ override fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback): Cancelable {
+ return addPushRuleTask
+ .configureWith(AddPushRuleTask.Params(kind, pushRule)) {
+ this.callback = callback
+ }
+ .executeBy(taskExecutor)
+ }
+
+ override fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback): Cancelable {
+ return removePushRuleTask
+ .configureWith(RemovePushRuleTask.Params(kind, pushRule)) {
+ this.callback = callback
+ }
+ .executeBy(taskExecutor)
+ }
+
override fun removePushRuleListener(listener: PushRuleService.PushRuleListener) {
synchronized(listeners) {
listeners.remove(listener)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddPushRuleTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddPushRuleTask.kt
new file mode 100644
index 0000000000..99992ef4dc
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/AddPushRuleTask.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.matrix.android.internal.session.pushers
+
+import im.vector.matrix.android.api.pushrules.RuleKind
+import im.vector.matrix.android.api.pushrules.rest.PushRule
+import im.vector.matrix.android.internal.network.executeRequest
+import im.vector.matrix.android.internal.task.Task
+import javax.inject.Inject
+
+internal interface AddPushRuleTask : Task {
+ data class Params(
+ val kind: RuleKind,
+ val pushRule: PushRule
+ )
+}
+
+internal class DefaultAddPushRuleTask @Inject constructor(private val pushRulesApi: PushRulesApi)
+ : AddPushRuleTask {
+
+ override suspend fun execute(params: AddPushRuleTask.Params) {
+ return executeRequest {
+ apiCall = pushRulesApi.addRule(params.kind.value, params.pushRule.ruleId, params.pushRule)
+ }
+ }
+}
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 243e4d4b03..8c7e9fb263 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
@@ -32,7 +32,7 @@ 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.*
+import java.util.UUID
import java.util.concurrent.TimeUnit
import javax.inject.Inject
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 7aa06c0275..1564363e1b 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
@@ -25,6 +25,8 @@ import im.vector.matrix.android.api.session.pushers.PushersService
import im.vector.matrix.android.internal.session.notification.DefaultProcessEventForPushTask
import im.vector.matrix.android.internal.session.notification.DefaultPushRuleService
import im.vector.matrix.android.internal.session.notification.ProcessEventForPushTask
+import im.vector.matrix.android.internal.session.room.notification.DefaultSetRoomNotificationStateTask
+import im.vector.matrix.android.internal.session.room.notification.SetRoomNotificationStateTask
import retrofit2.Retrofit
@Module
@@ -67,6 +69,15 @@ internal abstract class PushersModule {
@Binds
abstract fun bindUpdatePushRuleEnableStatusTask(updatePushRuleEnableStatusTask: DefaultUpdatePushRuleEnableStatusTask): UpdatePushRuleEnableStatusTask
+ @Binds
+ abstract fun bindAddPushRuleTask(addPushRuleTask: DefaultAddPushRuleTask): AddPushRuleTask
+
+ @Binds
+ abstract fun bindRemovePushRuleTask(removePushRuleTask: DefaultRemovePushRuleTask): RemovePushRuleTask
+
+ @Binds
+ abstract fun bindSetRoomNotificationStateTask(setRoomNotificationStateTask: DefaultSetRoomNotificationStateTask): SetRoomNotificationStateTask
+
@Binds
abstract fun bindPushRuleService(pushRuleService: DefaultPushRuleService): PushRuleService
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePushRuleTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePushRuleTask.kt
new file mode 100644
index 0000000000..c4938fa0cc
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/RemovePushRuleTask.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.matrix.android.internal.session.pushers
+
+import im.vector.matrix.android.api.pushrules.RuleKind
+import im.vector.matrix.android.api.pushrules.rest.PushRule
+import im.vector.matrix.android.internal.network.executeRequest
+import im.vector.matrix.android.internal.task.Task
+import javax.inject.Inject
+
+internal interface RemovePushRuleTask : Task {
+ data class Params(
+ val kind: RuleKind,
+ val pushRule: PushRule
+ )
+}
+
+internal class DefaultRemovePushRuleTask @Inject constructor(private val pushRulesApi: PushRulesApi)
+ : RemovePushRuleTask {
+
+ override suspend fun execute(params: RemovePushRuleTask.Params) {
+ return executeRequest {
+ apiCall = pushRulesApi.deleteRule(params.kind.value, params.pushRule.ruleId)
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt
index fea827fd25..cca20fc5fc 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt
@@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.members.MembershipService
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.relation.RelationService
+import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService
import im.vector.matrix.android.api.session.room.reporting.ReportingService
import im.vector.matrix.android.api.session.room.read.ReadService
import im.vector.matrix.android.api.session.room.send.DraftService
@@ -49,7 +50,8 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
private val readService: ReadService,
private val cryptoService: CryptoService,
private val relationService: RelationService,
- private val roomMembersService: MembershipService) :
+ private val roomMembersService: MembershipService,
+ private val roomPushRuleService: RoomPushRuleService) :
Room,
TimelineService by timelineService,
SendService by sendService,
@@ -58,7 +60,8 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
ReportingService by reportingService,
ReadService by readService,
RelationService by relationService,
- MembershipService by roomMembersService {
+ MembershipService by roomMembersService,
+ RoomPushRuleService by roomPushRuleService {
override fun getRoomSummaryLive(): LiveData> {
val liveData = monarchy.findAllMappedWithChanges(
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 0b18279aa8..c9d5aeb6bb 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
@@ -21,7 +21,7 @@ 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
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.mapper.ContentMapper
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
@@ -41,8 +41,8 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona
fun resolve(roomId: String): String? {
var res: String? = null
monarchy.doWithRealm { realm ->
- val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_AVATAR).prev()?.asDomain()
- res = roomName?.content.toModel()?.avatarUrl
+ val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_AVATAR).prev()
+ res = ContentMapper.map(roomName?.content).toModel()?.avatarUrl
if (!res.isNullOrEmpty()) {
return@doWithRealm
}
@@ -60,6 +60,6 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona
}
private fun EventEntity?.toRoomMember(): RoomMember? {
- return this?.asDomain()?.content?.toModel()
+ return ContentMapper.map(this?.content).toModel()
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt
index e2199782f4..30a2948f68 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt
@@ -22,6 +22,7 @@ import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
import im.vector.matrix.android.internal.session.room.draft.DefaultDraftService
import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService
+import im.vector.matrix.android.internal.session.room.notification.DefaultRoomPushRuleService
import im.vector.matrix.android.internal.session.room.read.DefaultReadService
import im.vector.matrix.android.internal.session.room.relation.DefaultRelationService
import im.vector.matrix.android.internal.session.room.reporting.DefaultReportingService
@@ -44,7 +45,8 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
private val reportingServiceFactory: DefaultReportingService.Factory,
private val readServiceFactory: DefaultReadService.Factory,
private val relationServiceFactory: DefaultRelationService.Factory,
- private val membershipServiceFactory: DefaultMembershipService.Factory) :
+ private val membershipServiceFactory: DefaultMembershipService.Factory,
+ private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory) :
RoomFactory {
override fun create(roomId: String): Room {
@@ -60,7 +62,8 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
readServiceFactory.create(roomId),
cryptoService,
relationServiceFactory.create(roomId),
- membershipServiceFactory.create(roomId)
+ membershipServiceFactory.create(roomId),
+ roomPushRuleServiceFactory.create(roomId)
)
}
}
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 0d28720ec6..1158c08984 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
@@ -21,7 +21,7 @@ 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
import im.vector.matrix.android.api.session.room.model.RoomTopicContent
-import im.vector.matrix.android.internal.database.mapper.asDomain
+import im.vector.matrix.android.internal.database.mapper.ContentMapper
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.model.RoomSummaryEntity
@@ -65,8 +65,10 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
roomId: String,
membership: Membership? = null,
roomSummary: RoomSyncSummary? = null,
- unreadNotifications: RoomSyncUnreadNotifications? = null) {
- val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
+ unreadNotifications: RoomSyncUnreadNotifications? = null,
+ updateMembers: Boolean = false) {
+ val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
+ ?: realm.createObject(roomId)
if (roomSummary != null) {
if (roomSummary.heroes.isNotEmpty()) {
@@ -88,24 +90,27 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
}
val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, filterTypes = PREVIEWABLE_TYPES)
- val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
+ val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()
roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0
- // avoid this call if we are sure there are unread events
- || !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId)
-
- val otherRoomMembers = RoomMembers(realm, roomId)
- .queryRoomMembersEvent()
- .notEqualTo(EventEntityFields.STATE_KEY, userId)
- .findAll()
- .asSequence()
- .map { it.stateKey }
+ // avoid this call if we are sure there are unread events
+ || !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId)
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
- roomSummaryEntity.topic = lastTopicEvent?.content.toModel()?.topic
+ roomSummaryEntity.topic = ContentMapper.map(lastTopicEvent?.content).toModel()?.topic
roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent
- roomSummaryEntity.otherMemberIds.clear()
- roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
+
+ if (updateMembers) {
+ val otherRoomMembers = RoomMembers(realm, roomId)
+ .queryRoomMembersEvent()
+ .notEqualTo(EventEntityFields.STATE_KEY, userId)
+ .findAll()
+ .asSequence()
+ .map { it.stateKey }
+
+ roomSummaryEntity.otherMemberIds.clear()
+ roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
+ }
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt
index d952915d2c..7d9332ee84 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt
@@ -74,7 +74,7 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP
it.updateSenderData()
}
roomEntity.areAllMembersLoaded = true
- roomSummaryUpdater.update(realm, roomId)
+ roomSummaryUpdater.update(realm, roomId, updateMembers = true)
}
}
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 965bd21cf4..2271631932 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
@@ -22,7 +22,7 @@ import im.vector.matrix.android.R
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.*
-import im.vector.matrix.android.internal.database.mapper.asDomain
+import im.vector.matrix.android.internal.database.mapper.ContentMapper
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.model.RoomEntity
@@ -56,20 +56,20 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
var name: CharSequence? = null
monarchy.doWithRealm { realm ->
val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst()
- val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_NAME).prev()?.asDomain()
- name = roomName?.content.toModel()?.name
+ val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_NAME).prev()
+ name = ContentMapper.map(roomName?.content).toModel()?.name
if (!name.isNullOrEmpty()) {
return@doWithRealm
}
- val canonicalAlias = EventEntity.where(realm, roomId, EventType.STATE_CANONICAL_ALIAS).prev()?.asDomain()
- name = canonicalAlias?.content.toModel()?.canonicalAlias
+ val canonicalAlias = EventEntity.where(realm, roomId, EventType.STATE_CANONICAL_ALIAS).prev()
+ name = ContentMapper.map(canonicalAlias?.content).toModel()?.canonicalAlias
if (!name.isNullOrEmpty()) {
return@doWithRealm
}
- val aliases = EventEntity.where(realm, roomId, EventType.STATE_ROOM_ALIASES).prev()?.asDomain()
- name = aliases?.content.toModel()?.aliases?.firstOrNull()
+ val aliases = EventEntity.where(realm, roomId, EventType.STATE_ROOM_ALIASES).prev()
+ name = ContentMapper.map(aliases?.content).toModel()?.aliases?.firstOrNull()
if (!name.isNullOrEmpty()) {
return@doWithRealm
}
@@ -132,6 +132,6 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
}
private fun EventEntity?.toRoomMember(): RoomMember? {
- return this?.asDomain()?.content?.toModel()
+ return ContentMapper.map(this?.content).toModel()
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt
index b50424b343..9fba1d8f02 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt
@@ -73,6 +73,7 @@ internal class RoomMembers(private val realm: Realm,
return EventEntity
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
.sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING)
+ .isNotNull(EventEntityFields.STATE_KEY)
.distinct(EventEntityFields.STATE_KEY)
.isNotNull(EventEntityFields.CONTENT)
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/DefaultRoomPushRuleService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/DefaultRoomPushRuleService.kt
new file mode 100644
index 0000000000..7cb7452244
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/DefaultRoomPushRuleService.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.session.room.notification
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.Transformations
+import com.squareup.inject.assisted.Assisted
+import com.squareup.inject.assisted.AssistedInject
+import com.zhuinden.monarchy.Monarchy
+import im.vector.matrix.android.api.MatrixCallback
+import im.vector.matrix.android.api.pushrules.RuleScope
+import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
+import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService
+import im.vector.matrix.android.api.util.Cancelable
+import im.vector.matrix.android.internal.database.model.PushRuleEntity
+import im.vector.matrix.android.internal.database.query.where
+import im.vector.matrix.android.internal.task.TaskExecutor
+import im.vector.matrix.android.internal.task.configureWith
+
+internal class DefaultRoomPushRuleService @AssistedInject constructor(@Assisted private val roomId: String,
+ private val setRoomNotificationStateTask: SetRoomNotificationStateTask,
+ private val monarchy: Monarchy,
+ private val taskExecutor: TaskExecutor)
+ : RoomPushRuleService {
+
+ @AssistedInject.Factory
+ interface Factory {
+ fun create(roomId: String): RoomPushRuleService
+ }
+
+ override fun getLiveRoomNotificationState(): LiveData {
+ return Transformations.map(getPushRuleForRoom()) {
+ it?.toRoomNotificationState() ?: RoomNotificationState.ALL_MESSAGES
+ }
+ }
+
+ override fun setRoomNotificationState(roomNotificationState: RoomNotificationState, matrixCallback: MatrixCallback): Cancelable {
+ return setRoomNotificationStateTask
+ .configureWith(SetRoomNotificationStateTask.Params(roomId, roomNotificationState)) {
+ this.callback = callback
+ }
+ .executeBy(taskExecutor)
+ }
+
+ private fun getPushRuleForRoom(): LiveData {
+ val liveData = monarchy.findAllMappedWithChanges(
+ { realm ->
+ PushRuleEntity.where(realm, scope = RuleScope.GLOBAL, ruleId = roomId)
+ },
+ { result ->
+ result.toRoomPushRule()
+ }
+ )
+ return Transformations.map(liveData) { results ->
+ results.firstOrNull()
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRule.kt
new file mode 100644
index 0000000000..b07f94f0f3
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRule.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.session.room.notification
+
+import im.vector.matrix.android.api.pushrules.RuleKind
+import im.vector.matrix.android.api.pushrules.rest.PushRule
+
+internal data class RoomPushRule(
+ val kind: RuleKind,
+ val rule: PushRule
+)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRuleMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRuleMapper.kt
new file mode 100644
index 0000000000..d08d346a1f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/RoomPushRuleMapper.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.session.room.notification
+
+import im.vector.matrix.android.api.pushrules.*
+import im.vector.matrix.android.api.pushrules.rest.PushCondition
+import im.vector.matrix.android.api.pushrules.rest.PushRule
+import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
+import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
+import im.vector.matrix.android.internal.database.model.PushRuleEntity
+
+internal fun PushRuleEntity.toRoomPushRule(): RoomPushRule? {
+ val kind = parent?.firstOrNull()?.kind
+ val pushRule = when (kind) {
+ RuleSetKey.OVERRIDE -> {
+ PushRulesMapper.map(this)
+ }
+ RuleSetKey.ROOM -> {
+ PushRulesMapper.mapRoomRule(this)
+ }
+ else -> null
+ }
+ return if (pushRule == null || kind == null) {
+ null
+ } else {
+ RoomPushRule(kind, pushRule)
+ }
+}
+
+internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? {
+ return when {
+ this == RoomNotificationState.ALL_MESSAGES -> null
+ this == RoomNotificationState.ALL_MESSAGES_NOISY -> {
+ val rule = PushRule(
+ actions = listOf(Action.Notify, Action.Sound()).toJson(),
+ enabled = true,
+ ruleId = roomId
+ )
+ return RoomPushRule(RuleSetKey.ROOM, rule)
+ }
+ else -> {
+ val condition = PushCondition(
+ kind = Condition.Kind.event_match.value,
+ key = "room_id",
+ pattern = roomId
+ )
+ val rule = PushRule(
+ actions = listOf(Action.DoNotNotify).toJson(),
+ enabled = true,
+ ruleId = roomId,
+ conditions = listOf(condition)
+ )
+ val kind = if (this == RoomNotificationState.MUTE) {
+ RuleSetKey.OVERRIDE
+ } else {
+ RuleSetKey.ROOM
+ }
+ return RoomPushRule(kind, rule)
+ }
+ }
+}
+
+internal fun RoomPushRule.toRoomNotificationState(): RoomNotificationState {
+ return if (rule.enabled) {
+ val actions = rule.getActions()
+ if (actions.contains(Action.DoNotNotify)) {
+ if (kind == RuleSetKey.OVERRIDE) {
+ RoomNotificationState.MUTE
+ } else {
+ RoomNotificationState.MENTIONS_ONLY
+ }
+ } else if (actions.contains(Action.Notify)) {
+ val hasSoundAction = actions.find {
+ it is Action.Sound
+ } != null
+ if (hasSoundAction) {
+ RoomNotificationState.ALL_MESSAGES_NOISY
+ } else {
+ RoomNotificationState.ALL_MESSAGES
+ }
+ } else {
+ RoomNotificationState.ALL_MESSAGES
+ }
+ } else {
+ RoomNotificationState.ALL_MESSAGES
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/SetRoomNotificationStateTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/SetRoomNotificationStateTask.kt
new file mode 100644
index 0000000000..0362a6607f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/notification/SetRoomNotificationStateTask.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.session.room.notification
+
+import com.zhuinden.monarchy.Monarchy
+import im.vector.matrix.android.api.pushrules.RuleScope
+import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
+import im.vector.matrix.android.internal.database.model.PushRuleEntity
+import im.vector.matrix.android.internal.database.query.where
+import im.vector.matrix.android.internal.session.pushers.AddPushRuleTask
+import im.vector.matrix.android.internal.session.pushers.RemovePushRuleTask
+import im.vector.matrix.android.internal.task.Task
+import io.realm.Realm
+import javax.inject.Inject
+
+internal interface SetRoomNotificationStateTask : Task {
+ data class Params(
+ val roomId: String,
+ val roomNotificationState: RoomNotificationState
+ )
+}
+
+internal class DefaultSetRoomNotificationStateTask @Inject constructor(private val monarchy: Monarchy,
+ private val removePushRuleTask: RemovePushRuleTask,
+ private val addPushRuleTask: AddPushRuleTask)
+ : SetRoomNotificationStateTask {
+
+ override suspend fun execute(params: SetRoomNotificationStateTask.Params) {
+ val currentRoomPushRule = Realm.getInstance(monarchy.realmConfiguration).use {
+ PushRuleEntity.where(it, scope = RuleScope.GLOBAL, ruleId = params.roomId).findFirst()?.toRoomPushRule()
+ }
+ if (currentRoomPushRule != null) {
+ removePushRuleTask.execute(RemovePushRuleTask.Params(currentRoomPushRule.kind, currentRoomPushRule.rule))
+ }
+ val newRoomPushRule = params.roomNotificationState.toRoomPushRule(params.roomId)
+ if (newRoomPushRule != null) {
+ addPushRuleTask.execute(AddPushRuleTask.Params(newRoomPushRule.kind, newRoomPushRule.rule))
+ }
+ }
+}
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 49c813ece6..3fa0dcdca1 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
@@ -39,7 +39,6 @@ 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.*
import javax.inject.Inject
/**
@@ -119,7 +118,7 @@ internal class LocalEchoEventFactory @Inject constructor(@UserId private val use
permalink,
stringProvider.getString(R.string.message_reply_to_prefix),
userLink,
- originalEvent.senderName ?: originalEvent.root.senderId,
+ originalEvent.getDisambiguatedDisplayName(),
body.takeFormatted(),
createTextContent(newBodyText, newBodyAutoMarkdown).takeFormatted()
)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt
index 606c20e8cb..4127e43540 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt
@@ -52,7 +52,8 @@ import io.realm.RealmQuery
import io.realm.RealmResults
import io.realm.Sort
import timber.log.Timber
-import java.util.*
+import java.util.Collections
+import java.util.UUID
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
import kotlin.collections.ArrayList
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/securestorage/SecretStoringUtils.kt
index 260f98d97f..592191975e 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/securestorage/SecretStoringUtils.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/securestorage/SecretStoringUtils.kt
@@ -31,7 +31,7 @@ import java.security.KeyPairGenerator
import java.security.KeyStore
import java.security.KeyStoreException
import java.security.SecureRandom
-import java.util.*
+import java.util.Calendar
import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.IvParameterSpec
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 5fb25834c0..4a003eb7d9 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
@@ -67,6 +67,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
}
suspend fun handle(roomsSyncResponse: RoomsSyncResponse, isInitialSync: Boolean, reporter: DefaultInitialSyncProgressService? = null) {
+ Timber.v("Execute transaction from $this")
monarchy.awaitTransaction { realm ->
handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), isInitialSync, reporter)
handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), isInitialSync, reporter)
@@ -133,6 +134,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
roomEntity.membership = Membership.JOIN
// State event
+
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
val minStateIndex = roomEntity.untimelinedStateEvents.where().min(EventEntityFields.STATE_INDEX)?.toInt()
?: Int.MIN_VALUE
@@ -146,7 +148,6 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
}
}
}
-
if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
val chunkEntity = handleTimelineEvents(
realm,
@@ -157,14 +158,19 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
)
roomEntity.addOrUpdate(chunkEntity)
}
- roomSummaryUpdater.update(realm, roomId, Membership.JOIN, roomSync.summary, roomSync.unreadNotifications)
+ val hasRoomMember = roomSync.state?.events?.firstOrNull {
+ it.type == EventType.STATE_ROOM_MEMBER
+ } != null || roomSync.timeline?.events?.firstOrNull {
+ it.type == EventType.STATE_ROOM_MEMBER
+ } != null
+
+ roomSummaryUpdater.update(realm, roomId, Membership.JOIN, roomSync.summary, roomSync.unreadNotifications, updateMembers = hasRoomMember)
return roomEntity
}
private fun handleInvitedRoom(realm: Realm,
roomId: String,
- roomSync:
- InvitedRoomSync): RoomEntity {
+ roomSync: InvitedRoomSync): RoomEntity {
Timber.v("Handle invited sync for room $roomId")
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
roomEntity.membership = Membership.INVITE
@@ -172,7 +178,10 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
val chunkEntity = handleTimelineEvents(realm, roomEntity, roomSync.inviteState.events)
roomEntity.addOrUpdate(chunkEntity)
}
- roomSummaryUpdater.update(realm, roomId, Membership.INVITE)
+ val hasRoomMember = roomSync.inviteState?.events?.firstOrNull {
+ it.type == EventType.STATE_ROOM_MEMBER
+ } != null
+ roomSummaryUpdater.update(realm, roomId, Membership.INVITE, updateMembers = hasRoomMember)
return roomEntity
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTokenStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTokenStore.kt
index f56ee3352f..350f2a1d83 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTokenStore.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTokenStore.kt
@@ -16,27 +16,24 @@
package im.vector.matrix.android.internal.session.sync
+import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.SyncEntity
-import im.vector.matrix.android.internal.di.SessionDatabase
+import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
-import io.realm.RealmConfiguration
import javax.inject.Inject
-internal class SyncTokenStore @Inject constructor(@SessionDatabase private val realmConfiguration: RealmConfiguration) {
+internal class SyncTokenStore @Inject constructor(private val monarchy: Monarchy) {
fun getLastToken(): String? {
- val realm = Realm.getInstance(realmConfiguration)
- val token = realm.where(SyncEntity::class.java).findFirst()?.nextBatch
- realm.close()
- return token
+ return Realm.getInstance(monarchy.realmConfiguration).use {
+ it.where(SyncEntity::class.java).findFirst()?.nextBatch
+ }
}
- fun saveToken(token: String?) {
- val realm = Realm.getInstance(realmConfiguration)
- realm.executeTransaction {
+ suspend fun saveToken(token: String?) {
+ monarchy.awaitTransaction {
val sync = SyncEntity(token)
it.insertOrUpdate(sync)
}
- realm.close()
}
}
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 56b96b428d..56bc005805 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
@@ -27,10 +27,9 @@ 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.sync.model.accountdata.*
import im.vector.matrix.android.internal.session.user.accountdata.DirectChatsHelper
+import im.vector.matrix.android.internal.session.user.accountdata.SaveIgnoredUsersTask
import im.vector.matrix.android.internal.session.user.accountdata.UpdateUserAccountDataTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
@@ -44,6 +43,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
private val directChatsHelper: DirectChatsHelper,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val savePushRulesTask: SavePushRulesTask,
+ private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
private val taskExecutor: TaskExecutor) {
suspend fun handle(accountData: UserAccountDataSync?, invites: Map?) {
@@ -51,9 +51,18 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
when (it) {
is UserAccountDataDirectMessages -> handleDirectChatRooms(it)
is UserAccountDataPushRules -> handlePushRules(it)
- else -> return@forEach
+ is UserAccountDataIgnoredUsers -> handleIgnoredUsers(it)
+ is UserAccountDataFallback -> Timber.d("Receive account data of unhandled type ${it.type}")
+ else -> error("Missing code here!")
}
}
+
+ // TODO Store all account data, app can be interested of it
+ // accountData?.list?.forEach {
+ // it.toString()
+ // MoshiProvider.providesMoshi()
+ // }
+
monarchy.doWithRealm { realm ->
synchronizeWithServerIfNeeded(realm, invites)
}
@@ -114,4 +123,11 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
updateUserAccountDataTask.configureWith(updateUserAccountParams).executeBy(taskExecutor)
}
}
+
+ private fun handleIgnoredUsers(userAccountDataIgnoredUsers: UserAccountDataIgnoredUsers) {
+ saveIgnoredUsersTask
+ .configureWith(SaveIgnoredUsersTask.Params(userAccountDataIgnoredUsers.content.ignoredUsers.keys.toList()))
+ .executeBy(taskExecutor)
+ // TODO If not initial sync, we should execute a init sync
+ }
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt
index d084dcdadd..9e5cc2cfa4 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt
@@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
+import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataSync
// SyncResponse represents the request response for server sync v2.
@JsonClass(generateAdapter = true)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt
new file mode 100644
index 0000000000..ea591d79b0
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.session.sync.model.accountdata
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import im.vector.matrix.android.api.util.JsonDict
+import im.vector.matrix.android.api.util.emptyJsonDict
+
+@JsonClass(generateAdapter = true)
+internal data class IgnoredUsersContent(
+ /**
+ * Required. The map of users to ignore. UserId -> empty object for future enhancement
+ */
+ @Json(name = "ignored_users") val ignoredUsers: Map
+) {
+
+ companion object {
+ fun createWithUserIds(userIds: List): IgnoredUsersContent {
+ return IgnoredUsersContent(
+ ignoredUsers = userIds.associateWith { emptyJsonDict }
+ )
+ }
+ }
+}
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/accountdata/UserAccountData.kt
similarity index 81%
rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt
rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountData.kt
index 2173d2f4df..55dbad6099 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/accountdata/UserAccountData.kt
@@ -14,9 +14,13 @@
* limitations under the License.
*/
-package im.vector.matrix.android.internal.session.sync.model
+package im.vector.matrix.android.internal.session.sync.model.accountdata
-internal interface UserAccountData {
+import com.squareup.moshi.Json
+
+internal abstract class UserAccountData {
+
+ @Json(name = "type") abstract val type: String
companion object {
const val TYPE_IGNORED_USER_LIST = "m.ignored_user_list"
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataDirectMessages.kt
similarity index 82%
rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt
rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataDirectMessages.kt
index 825a16cb1e..e5c6135bd1 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataDirectMessages.kt
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package im.vector.matrix.android.internal.session.sync.model
+package im.vector.matrix.android.internal.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class UserAccountDataDirectMessages(
+ @Json(name = "type") override val type: String = TYPE_DIRECT_MESSAGES,
@Json(name = "content") val content: Map>
-) : UserAccountData
+) : UserAccountData()
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataFallback.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataFallback.kt
similarity index 84%
rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataFallback.kt
rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataFallback.kt
index 70d28c084f..a8b8235d37 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataFallback.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataFallback.kt
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package im.vector.matrix.android.internal.session.sync.model
+package im.vector.matrix.android.internal.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class UserAccountDataFallback(
+ @Json(name = "type") override val type: String,
@Json(name = "content") val content: Map
-) : UserAccountData
+) : UserAccountData()
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt
new file mode 100644
index 0000000000..63a7604305
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.session.sync.model.accountdata
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+internal data class UserAccountDataIgnoredUsers(
+ @Json(name = "type") override val type: String = TYPE_IGNORED_USER_LIST,
+ @Json(name = "content") val content: IgnoredUsersContent
+) : UserAccountData()
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/accountdata/UserAccountDataPushRules.kt
similarity index 83%
rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt
rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataPushRules.kt
index 7f357c876b..0d549d1667 100644
--- 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/accountdata/UserAccountDataPushRules.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package im.vector.matrix.android.internal.session.sync.model
+package im.vector.matrix.android.internal.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@@ -22,5 +22,6 @@ import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
@JsonClass(generateAdapter = true)
internal data class UserAccountDataPushRules(
+ @Json(name = "type") override val type: String = TYPE_PUSH_RULES,
@Json(name = "content") val content: GetPushRulesResponse
-) : UserAccountData
+) : UserAccountData()
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataSync.kt
similarity index 91%
rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt
rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataSync.kt
index 4b9e9d652d..c7f8bfa4c2 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataSync.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package im.vector.matrix.android.internal.session.sync.model
+package im.vector.matrix.android.internal.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt
index be330bfc36..d314c8d108 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt
@@ -29,9 +29,12 @@ import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.database.mapper.asDomain
+import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
+import im.vector.matrix.android.internal.database.model.IgnoredUserEntityFields
import im.vector.matrix.android.internal.database.model.UserEntity
import im.vector.matrix.android.internal.database.model.UserEntityFields
import im.vector.matrix.android.internal.database.query.where
+import im.vector.matrix.android.internal.session.user.accountdata.UpdateIgnoredUserIdsTask
import im.vector.matrix.android.internal.session.user.model.SearchUserTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
@@ -40,8 +43,8 @@ import javax.inject.Inject
internal class DefaultUserService @Inject constructor(private val monarchy: Monarchy,
private val searchUserTask: SearchUserTask,
+ private val updateIgnoredUserIdsTask: UpdateIgnoredUserIdsTask,
private val taskExecutor: TaskExecutor) : UserService {
-
private val realmDataSourceFactory: Monarchy.RealmDataSourceFactory by lazy {
monarchy.createDataSourceFactory { realm ->
realm.where(UserEntity::class.java)
@@ -62,7 +65,7 @@ internal class DefaultUserService @Inject constructor(private val monarchy: Mona
override fun getUser(userId: String): User? {
val userEntity = monarchy.fetchCopied { UserEntity.where(it, userId).findFirst() }
- ?: return null
+ ?: return null
return userEntity.asDomain()
}
@@ -117,4 +120,33 @@ internal class DefaultUserService @Inject constructor(private val monarchy: Mona
}
.executeBy(taskExecutor)
}
+
+ override fun liveIgnoredUsers(): LiveData> {
+ return monarchy.findAllMappedWithChanges(
+ { realm ->
+ realm.where(IgnoredUserEntity::class.java)
+ .isNotEmpty(IgnoredUserEntityFields.USER_ID)
+ .sort(IgnoredUserEntityFields.USER_ID)
+ },
+ { getUser(it.userId) ?: User(userId = it.userId) }
+ )
+ }
+
+ override fun ignoreUserIds(userIds: List, callback: MatrixCallback): Cancelable {
+ val params = UpdateIgnoredUserIdsTask.Params(userIdsToIgnore = userIds.toList())
+ return updateIgnoredUserIdsTask
+ .configureWith(params) {
+ this.callback = callback
+ }
+ .executeBy(taskExecutor)
+ }
+
+ override fun unIgnoreUserIds(userIds: List, callback: MatrixCallback): Cancelable {
+ val params = UpdateIgnoredUserIdsTask.Params(userIdsToUnIgnore = userIds.toList())
+ return updateIgnoredUserIdsTask
+ .configureWith(params) {
+ this.callback = callback
+ }
+ .executeBy(taskExecutor)
+ }
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt
index a997c616f3..51c296ba6e 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt
@@ -21,6 +21,10 @@ import dagger.Module
import dagger.Provides
import im.vector.matrix.android.api.session.user.UserService
import im.vector.matrix.android.internal.session.SessionScope
+import im.vector.matrix.android.internal.session.user.accountdata.DefaultSaveIgnoredUsersTask
+import im.vector.matrix.android.internal.session.user.accountdata.DefaultUpdateIgnoredUserIdsTask
+import im.vector.matrix.android.internal.session.user.accountdata.SaveIgnoredUsersTask
+import im.vector.matrix.android.internal.session.user.accountdata.UpdateIgnoredUserIdsTask
import im.vector.matrix.android.internal.session.user.model.DefaultSearchUserTask
import im.vector.matrix.android.internal.session.user.model.SearchUserTask
import retrofit2.Retrofit
@@ -43,4 +47,10 @@ internal abstract class UserModule {
@Binds
abstract fun bindSearchUserTask(searchUserTask: DefaultSearchUserTask): SearchUserTask
+
+ @Binds
+ abstract fun bindSaveIgnoredUsersTask(task: DefaultSaveIgnoredUsersTask): SaveIgnoredUsersTask
+
+ @Binds
+ abstract fun bindUpdateIgnoredUserIdsTask(task: DefaultUpdateIgnoredUserIdsTask): UpdateIgnoredUserIdsTask
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt
new file mode 100644
index 0000000000..c9a3eef440
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.user.accountdata
+
+import com.zhuinden.monarchy.Monarchy
+import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
+import im.vector.matrix.android.internal.task.Task
+import im.vector.matrix.android.internal.util.awaitTransaction
+import javax.inject.Inject
+
+/**
+ * Save the ignored users list in DB
+ */
+internal interface SaveIgnoredUsersTask : Task {
+ data class Params(
+ val userIds: List
+ )
+}
+
+internal class DefaultSaveIgnoredUsersTask @Inject constructor(private val monarchy: Monarchy) : SaveIgnoredUsersTask {
+
+ override suspend fun execute(params: SaveIgnoredUsersTask.Params) {
+ monarchy.awaitTransaction { realm ->
+ // clear current ignored users
+ realm.where(IgnoredUserEntity::class.java)
+ .findAll()
+ .deleteAllFromRealm()
+
+ // And save the new received list
+ params.userIds.forEach { realm.createObject(IgnoredUserEntity::class.java).apply { userId = it } }
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt
new file mode 100644
index 0000000000..075eeb23d1
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.session.user.accountdata
+
+import com.zhuinden.monarchy.Monarchy
+import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
+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.accountdata.IgnoredUsersContent
+import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
+import im.vector.matrix.android.internal.task.Task
+import javax.inject.Inject
+
+internal interface UpdateIgnoredUserIdsTask : Task {
+
+ data class Params(
+ val userIdsToIgnore: List = emptyList(),
+ val userIdsToUnIgnore: List = emptyList()
+ )
+}
+
+internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(private val accountDataApi: AccountDataAPI,
+ private val monarchy: Monarchy,
+ private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
+ @UserId private val userId: String) : UpdateIgnoredUserIdsTask {
+
+ override suspend fun execute(params: UpdateIgnoredUserIdsTask.Params) {
+ // Get current list
+ val ignoredUserIds = monarchy.fetchAllMappedSync(
+ { realm -> realm.where(IgnoredUserEntity::class.java) },
+ { it.userId }
+ ).toMutableSet()
+
+ val original = ignoredUserIds.toList()
+
+ ignoredUserIds.removeAll { it in params.userIdsToUnIgnore }
+ ignoredUserIds.addAll(params.userIdsToIgnore)
+
+ if (original == ignoredUserIds) {
+ // No change
+ return
+ }
+
+ val list = ignoredUserIds.toList()
+ val body = IgnoredUsersContent.createWithUserIds(list)
+
+ executeRequest {
+ apiCall = accountDataApi.setAccountData(userId, UserAccountData.TYPE_IGNORED_USER_LIST, body)
+ }
+
+ // Update the DB right now (do not wait for the sync to come back with updated data, for a faster UI update)
+ saveIgnoredUsersTask.execute(SaveIgnoredUsersTask.Params(list))
+ }
+}
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 5c0dac1125..9fa71005ff 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
@@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.session.user.accountdata
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.session.sync.model.accountdata.UserAccountData
import im.vector.matrix.android.internal.task.Task
import javax.inject.Inject
@@ -29,6 +29,7 @@ internal interface UpdateUserAccountDataTask : Task>
) : Params {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CompatUtil.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CompatUtil.kt
index 058a862bc8..2df2bd2bf2 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CompatUtil.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CompatUtil.kt
@@ -36,7 +36,7 @@ import java.security.*
import java.security.cert.CertificateException
import java.security.spec.AlgorithmParameterSpec
import java.security.spec.RSAKeyGenParameterSpec
-import java.util.*
+import java.util.Calendar
import java.util.zip.GZIPOutputStream
import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringUtils.kt
index 4a46a43f03..31da372bbe 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringUtils.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/StringUtils.kt
@@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.util
import im.vector.matrix.android.api.MatrixPatterns
import timber.log.Timber
-import java.util.*
+import java.util.Locale
/**
* Convert a string to an UTF8 String
diff --git a/matrix-sdk-android/src/main/res/values-bg/strings.xml b/matrix-sdk-android/src/main/res/values-bg/strings.xml
index 85643c7ade..2566ee780c 100644
--- a/matrix-sdk-android/src/main/res/values-bg/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-bg/strings.xml
@@ -172,4 +172,5 @@
Изпращане на съобщение…
Изчисти опашката за изпращане
+ %1$s оттегли поканата за присъединяване на %2$s към стаята
diff --git a/matrix-sdk-android/src/main/res/values-en-rGB/strings.xml b/matrix-sdk-android/src/main/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000000..f457e30ed0
--- /dev/null
+++ b/matrix-sdk-android/src/main/res/values-en-rGB/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Spanner
+ Aeroplane
+
diff --git a/matrix-sdk-android/src/main/res/values-en-rUS/strings.xml b/matrix-sdk-android/src/main/res/values-en-rUS/strings.xml
deleted file mode 100644
index 09e9dfc111..0000000000
--- a/matrix-sdk-android/src/main/res/values-en-rUS/strings.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- Wrench
- Airplane
-
-
-
-
diff --git a/matrix-sdk-android/src/main/res/values-ko/strings.xml b/matrix-sdk-android/src/main/res/values-ko/strings.xml
index 959ff8a96e..9dfbb6609b 100644
--- a/matrix-sdk-android/src/main/res/values-ko/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-ko/strings.xml
@@ -12,8 +12,8 @@
%1$s님이 떠났습니다
%1$s님이 초대를 거부했습니다
%1$s님이 %2$s님을 추방했습니다
- %1$s님이 %2$s님의 차단을 풀었습니다
- %1$s님이 %2$s님을 차단했습니다
+ %1$s님이 %2$s님의 출입 금지를 풀었습니다
+ %1$s님이 %2$s님을 출입 금지했습니다
%1$s님이 %2$s님의 초대를 취소했습니다
%1$s님이 아바타를 변경했습니다
%1$s님이 표시 이름을 %2$s(으)로 설정했습니다
diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml
index 604bb13a41..ce26c22137 100644
--- a/matrix-sdk-android/src/main/res/values/strings.xml
+++ b/matrix-sdk-android/src/main/res/values/strings.xml
@@ -170,7 +170,7 @@
Glasses
- Spanner
+ Wrench
Santa
@@ -208,7 +208,7 @@
Bicycle
- Aeroplane
+ Airplane
Rocket
diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushRuleActionsTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushRuleActionsTest.kt
index f98af53333..17543e9d25 100644
--- a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushRuleActionsTest.kt
+++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushRuleActionsTest.kt
@@ -18,7 +18,7 @@ package im.vector.matrix.android.api.pushrules
import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.internal.di.MoshiProvider
-import org.junit.Assert
+import org.junit.Assert.*
import org.junit.Test
class PushRuleActionsTest {
@@ -63,22 +63,17 @@ class PushRuleActionsTest {
val pushRule = MoshiProvider.providesMoshi().adapter(PushRule::class.java).fromJson(rawPushRule)
- Assert.assertNotNull("Should have parsed the rule", pushRule)
- Assert.assertNotNull("Failed to parse actions", Action.mapFrom(pushRule!!))
+ assertNotNull("Should have parsed the rule", pushRule)
- val actions = Action.mapFrom(pushRule)
- Assert.assertEquals(3, actions!!.size)
+ val actions = pushRule!!.getActions()
+ assertEquals(3, actions.size)
- Assert.assertEquals("First action should be notify", Action.Type.NOTIFY, actions[0].type)
+ assertTrue("First action should be notify", actions[0] is Action.Notify)
- Assert.assertEquals("Second action should be tweak", Action.Type.SET_TWEAK, actions[1].type)
- Assert.assertEquals("Second action tweak key should be sound", "sound", actions[1].tweak_action)
- Assert.assertEquals("Second action should have default as stringValue", "default", actions[1].stringValue)
- Assert.assertNull("Second action boolValue should be null", actions[1].boolValue)
+ assertTrue("Second action should be sound", actions[1] is Action.Sound)
+ assertEquals("Second action should have default sound", "default", (actions[1] as Action.Sound).sound)
- Assert.assertEquals("Third action should be tweak", Action.Type.SET_TWEAK, actions[2].type)
- Assert.assertEquals("Third action tweak key should be highlight", "highlight", actions[2].tweak_action)
- Assert.assertEquals("Third action tweak param should be false", false, actions[2].boolValue)
- Assert.assertNull("Third action stringValue should be null", actions[2].stringValue)
+ assertTrue("Third action should be highlight", actions[2] is Action.Highlight)
+ assertEquals("Third action tweak param should be false", false, (actions[2] as Action.Highlight).highlight)
}
}
diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt
index 42e7e850b3..a29f5d5542 100644
--- a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt
+++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt
@@ -16,23 +16,15 @@
package im.vector.matrix.android.api.pushrules
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import im.vector.matrix.android.api.MatrixCallback
-import im.vector.matrix.android.api.session.content.ContentAttachmentData
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.RoomService
-import im.vector.matrix.android.api.session.room.model.*
-import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
+import im.vector.matrix.android.api.session.room.model.Membership
+import im.vector.matrix.android.api.session.room.model.RoomMember
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
-import im.vector.matrix.android.api.session.room.send.UserDraft
-import im.vector.matrix.android.api.session.room.timeline.Timeline
-import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
-import im.vector.matrix.android.api.session.room.timeline.TimelineSettings
-import im.vector.matrix.android.api.util.Cancelable
-import im.vector.matrix.android.api.util.Optional
+import io.mockk.every
+import io.mockk.mockk
import org.junit.Assert
import org.junit.Test
@@ -133,17 +125,20 @@ class PushrulesConditionTest {
val conditionEqual3Bis = RoomMemberCountCondition("==3")
val conditionLessThan3 = RoomMemberCountCondition("<3")
- val session = MockRoomService()
+ val room2JoinedId = "2joined"
+ val room3JoinedId = "3joined"
- Event(
- type = "m.room.message",
- eventId = "mx0",
- content = MessageTextContent("m.text", "A").toContent(),
- originServerTs = 0,
- roomId = "2joined").also {
- Assert.assertFalse("This room does not have 3 members", conditionEqual3.isSatisfied(it, session))
- Assert.assertFalse("This room does not have 3 members", conditionEqual3Bis.isSatisfied(it, session))
- Assert.assertTrue("This room has less than 3 members", conditionLessThan3.isSatisfied(it, session))
+ val roomStub2Joined = mockk {
+ every { getNumberOfJoinedMembers() } returns 2
+ }
+
+ val roomStub3Joined = mockk {
+ every { getNumberOfJoinedMembers() } returns 3
+ }
+
+ val sessionStub = mockk {
+ every { getRoom(room2JoinedId) } returns roomStub2Joined
+ every { getRoom(room3JoinedId) } returns roomStub3Joined
}
Event(
@@ -151,10 +146,21 @@ class PushrulesConditionTest {
eventId = "mx0",
content = MessageTextContent("m.text", "A").toContent(),
originServerTs = 0,
- roomId = "3joined").also {
- Assert.assertTrue("This room has 3 members", conditionEqual3.isSatisfied(it, session))
- Assert.assertTrue("This room has 3 members", conditionEqual3Bis.isSatisfied(it, session))
- Assert.assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, session))
+ roomId = room2JoinedId).also {
+ Assert.assertFalse("This room does not have 3 members", conditionEqual3.isSatisfied(it, sessionStub))
+ Assert.assertFalse("This room does not have 3 members", conditionEqual3Bis.isSatisfied(it, sessionStub))
+ Assert.assertTrue("This room has less than 3 members", conditionLessThan3.isSatisfied(it, sessionStub))
+ }
+
+ Event(
+ type = "m.room.message",
+ eventId = "mx0",
+ content = MessageTextContent("m.text", "A").toContent(),
+ originServerTs = 0,
+ roomId = room3JoinedId).also {
+ Assert.assertTrue("This room has 3 members", conditionEqual3.isSatisfied(it, sessionStub))
+ Assert.assertTrue("This room has 3 members", conditionEqual3Bis.isSatisfied(it, sessionStub))
+ Assert.assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, sessionStub))
}
}
@@ -171,208 +177,4 @@ class PushrulesConditionTest {
Assert.assertTrue("Notice", conditionEqual.isSatisfied(it))
}
}
-
- class MockRoomService() : RoomService {
- 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? {
- return when (roomId) {
- "2joined" -> MockRoom(roomId, 2)
- "3joined" -> MockRoom(roomId, 3)
- else -> null
- }
- }
-
- override fun liveRoomSummaries(): LiveData> {
- return MutableLiveData()
- }
-
- override fun markAllAsRead(roomIds: List, callback: MatrixCallback): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
- }
-
- class MockRoom(override val roomId: String, val _numberOfJoinedMembers: Int) : Room {
- override fun getReadMarkerLive(): LiveData> {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun getMyReadReceiptLive(): LiveData> {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun resendTextMessage(localEcho: TimelineEvent): Cancelable? {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun deleteFailedEcho(localEcho: TimelineEvent) {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun clearSendingQueue() {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun resendAllFailedMessages() {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun saveDraft(draft: UserDraft) {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun deleteDraft() {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun getDraftsLive(): LiveData> {
- 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 getTimeLineEventLive(eventId: String): LiveData> {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun getNumberOfJoinedMembers(): Int {
- return _numberOfJoinedMembers
- }
-
- override fun getRoomSummaryLive(): LiveData> {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun roomSummary(): RoomSummary? {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun getTimeLineEvent(eventId: String): TimelineEvent? {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun sendTextMessage(text: String, msgType: String, autoMarkdown: Boolean): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun sendFormattedTextMessage(text: String, formattedText: String): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun sendMedia(attachment: ContentAttachmentData): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun sendMedias(attachments: List): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun redactEvent(event: Event, reason: String?): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun markAllAsRead(callback: MatrixCallback) {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun setReadReceipt(eventId: String, callback: MatrixCallback) {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun setReadMarker(fullyReadEventId: String, callback: MatrixCallback) {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun isEventRead(eventId: String): Boolean {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun getRoomMember(userId: String): RoomMember? {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun getRoomMemberIdsLive(): LiveData> {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- 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(viaServers: List, callback: MatrixCallback): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun leave(callback: MatrixCallback): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun updateTopic(topic: String, callback: MatrixCallback) {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun sendReaction(targetEventId: String, reaction: String): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun undoReaction(targetEventId: String, reaction: String): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun editTextMessage(targetEventId: String, msgType: String, newBodyText: String,
- newBodyAutoMarkdown: Boolean, compatibilityBodyText: String): Cancelable {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun replyToMessage(eventReplied: TimelineEvent, replyText: String, autoMarkdown: Boolean): Cancelable? {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun getEventSummaryLive(eventId: String): LiveData> {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun isEncrypted(): Boolean {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun encryptionAlgorithm(): String? {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
-
- override fun shouldEncryptForInvitedMembers(): Boolean {
- TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
- }
- }
}
diff --git a/tools/import_from_riot.sh b/tools/import_from_riot.sh
index 2e4b332a3c..271a872a48 100755
--- a/tools/import_from_riot.sh
+++ b/tools/import_from_riot.sh
@@ -32,7 +32,7 @@ cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-da/strings.xml ./mat
cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-de/strings.xml ./matrix-sdk-android/src/main/res/values-de/strings.xml
cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-el/strings.xml ./matrix-sdk-android/src/main/res/values-el/strings.xml
cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-eo/strings.xml ./matrix-sdk-android/src/main/res/values-eo/strings.xml
-cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-en-rUS/strings.xml ./matrix-sdk-android/src/main/res/values-en-rUS/strings.xml
+cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-en-rGB/strings.xml ./matrix-sdk-android/src/main/res/values-en-rGB/strings.xml
cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-es/strings.xml ./matrix-sdk-android/src/main/res/values-es/strings.xml
cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-es-rMX/strings.xml ./matrix-sdk-android/src/main/res/values-es-rMX/strings.xml
cp ../matrix-android-sdk/matrix-sdk/src/main/res/values-eu/strings.xml ./matrix-sdk-android/src/main/res/values-eu/strings.xml
@@ -102,6 +102,7 @@ cp ../riot-android/vector/src/main/res/values-ro/strings.xml ./vector/src
cp ../riot-android/vector/src/main/res/values-ru/strings.xml ./vector/src/main/res/values-ru/strings.xml
cp ../riot-android/vector/src/main/res/values-sk/strings.xml ./vector/src/main/res/values-sk/strings.xml
cp ../riot-android/vector/src/main/res/values-sq/strings.xml ./vector/src/main/res/values-sq/strings.xml
+cp ../riot-android/vector/src/main/res/values-sr/strings.xml ./vector/src/main/res/values-sr/strings.xml
cp ../riot-android/vector/src/main/res/values-te/strings.xml ./vector/src/main/res/values-te/strings.xml
cp ../riot-android/vector/src/main/res/values-th/strings.xml ./vector/src/main/res/values-th/strings.xml
cp ../riot-android/vector/src/main/res/values-tlh/strings.xml ./vector/src/main/res/values-tlh/strings.xml
diff --git a/vector/build.gradle b/vector/build.gradle
index 3ef125d331..e425d53a62 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -15,7 +15,7 @@ androidExtensions {
}
ext.versionMajor = 0
-ext.versionMinor = 7
+ext.versionMinor = 8
ext.versionPatch = 0
static def getGitTimestamp() {
@@ -217,9 +217,10 @@ android {
dependencies {
def epoxy_version = '3.8.0'
+ def fragment_version = '1.2.0-rc01'
def arrow_version = "0.8.2"
def coroutines_version = "1.3.2"
- def markwon_version = '3.1.0'
+ def markwon_version = '4.1.2'
def big_image_viewer_version = '1.5.6'
def glide_version = '4.10.0'
def moshi_version = '1.8.0'
@@ -234,6 +235,8 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation "androidx.fragment:fragment:$fragment_version"
+ implementation "androidx.fragment:fragment-ktx:$fragment_version"
//Do not use beta2 at the moment, as it breaks things
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
implementation 'androidx.core:core-ktx:1.1.0'
@@ -265,7 +268,7 @@ dependencies {
implementation("com.airbnb.android:epoxy:$epoxy_version")
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
implementation "com.airbnb.android:epoxy-paging:$epoxy_version"
- implementation 'com.airbnb.android:mvrx:1.1.0'
+ implementation 'com.airbnb.android:mvrx:1.3.0'
// Work
implementation "androidx.work:work-runtime-ktx:2.3.0-alpha01"
@@ -283,8 +286,8 @@ dependencies {
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation 'com.google.android.material:material:1.1.0-beta01'
implementation 'me.gujun.android:span:1.7'
- implementation "ru.noties.markwon:core:$markwon_version"
- implementation "ru.noties.markwon:html:$markwon_version"
+ implementation "io.noties.markwon:core:$markwon_version"
+ implementation "io.noties.markwon:html:$markwon_version"
implementation 'me.saket:better-link-movement-method:2.2.0'
implementation 'com.google.android:flexbox:1.1.1'
diff --git a/vector/src/androidTest/java/im/vector/riotx/ExampleInstrumentedTest.kt b/vector/src/androidTest/java/im/vector/riotx/ExampleInstrumentedTest.kt
deleted file mode 100644
index afed0c783a..0000000000
--- a/vector/src/androidTest/java/im/vector/riotx/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.riotx
-
-import androidx.test.InstrumentationRegistry
-import androidx.test.runner.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getTargetContext()
- assertEquals("im.vector.riotx", appContext.packageName)
- }
-}
diff --git a/vector/src/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml
index 0d071e3465..8bb571902a 100644
--- a/vector/src/debug/AndroidManifest.xml
+++ b/vector/src/debug/AndroidManifest.xml
@@ -4,6 +4,7 @@
+
diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt
index bfb9f0654e..6624a05985 100644
--- a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt
+++ b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt
@@ -26,6 +26,7 @@ import androidx.core.app.Person
import butterknife.OnClick
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorBaseActivity
+import im.vector.riotx.features.debug.sas.DebugSasEmojiActivity
class DebugMenuActivity : VectorBaseActivity() {
@@ -36,6 +37,11 @@ class DebugMenuActivity : VectorBaseActivity() {
startActivity(Intent(this, TestLinkifyActivity::class.java))
}
+ @OnClick(R.id.debug_show_sas_emoji)
+ fun showSasEmoji() {
+ startActivity(Intent(this, DebugSasEmojiActivity::class.java))
+ }
+
@OnClick(R.id.debug_test_notification)
fun testNotification() {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/sas/DebugSasEmojiActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/sas/DebugSasEmojiActivity.kt
new file mode 100644
index 0000000000..ba1c47c08c
--- /dev/null
+++ b/vector/src/debug/java/im/vector/riotx/features/debug/sas/DebugSasEmojiActivity.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.debug.sas
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import im.vector.matrix.android.api.crypto.getAllVerificationEmojis
+import im.vector.riotx.R
+import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*
+
+class DebugSasEmojiActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.fragment_generic_recycler_epoxy)
+
+ val controller = SasEmojiController()
+ epoxyRecyclerView.setController(controller)
+ controller.setData(SasState(getAllVerificationEmojis()))
+ }
+}
diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/sas/ItemSasEmoji.kt b/vector/src/debug/java/im/vector/riotx/features/debug/sas/ItemSasEmoji.kt
new file mode 100644
index 0000000000..92d9bc0b11
--- /dev/null
+++ b/vector/src/debug/java/im/vector/riotx/features/debug/sas/ItemSasEmoji.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.debug.sas
+
+import android.annotation.SuppressLint
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.matrix.android.api.session.crypto.sas.EmojiRepresentation
+import im.vector.riotx.core.epoxy.VectorEpoxyHolder
+import im.vector.riotx.core.epoxy.VectorEpoxyModel
+
+@EpoxyModelClass(layout = im.vector.riotx.R.layout.item_sas_emoji)
+abstract class ItemSasEmoji : VectorEpoxyModel() {
+
+ @EpoxyAttribute
+ var index: Int = 0
+ @EpoxyAttribute
+ lateinit var emojiRepresentation: EmojiRepresentation
+
+ @SuppressLint("SetTextI18n")
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+ holder.indexView.text = "$index:"
+ holder.emojiView.text = emojiRepresentation.emoji
+ holder.textView.setText(emojiRepresentation.nameResId)
+ holder.idView.text = holder.idView.resources.getResourceEntryName(emojiRepresentation.nameResId)
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val indexView by bind(im.vector.riotx.R.id.sas_emoji_index)
+ val emojiView by bind(im.vector.riotx.R.id.sas_emoji)
+ val textView by bind(im.vector.riotx.R.id.sas_emoji_text)
+ val idView by bind(im.vector.riotx.R.id.sas_emoji_text_id)
+ }
+}
diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/sas/SasEmojiController.kt b/vector/src/debug/java/im/vector/riotx/features/debug/sas/SasEmojiController.kt
new file mode 100644
index 0000000000..daf432fb45
--- /dev/null
+++ b/vector/src/debug/java/im/vector/riotx/features/debug/sas/SasEmojiController.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.riotx.features.debug.sas
+
+import com.airbnb.epoxy.TypedEpoxyController
+import im.vector.matrix.android.api.session.crypto.sas.EmojiRepresentation
+
+data class SasState(
+ val emojiList: List
+)
+
+class SasEmojiController : TypedEpoxyController() {
+
+ override fun buildModels(data: SasState?) {
+ if (data == null) return
+
+ data.emojiList.forEachIndexed { idx, emojiRepresentation ->
+ itemSasEmoji {
+ id(idx)
+ index(idx)
+ emojiRepresentation(emojiRepresentation)
+ }
+ }
+ }
+}
diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml
index a0acfe9937..01ab061f6a 100644
--- a/vector/src/debug/res/layout/activity_debug_menu.xml
+++ b/vector/src/debug/res/layout/activity_debug_menu.xml
@@ -47,6 +47,13 @@
android:layout_height="wrap_content"
android:text="Test Material theme Dark" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/java/im/vector/riotx/ActiveSessionObservableStore.kt b/vector/src/main/java/im/vector/riotx/ActiveSessionDataSource.kt
similarity index 84%
rename from vector/src/main/java/im/vector/riotx/ActiveSessionObservableStore.kt
rename to vector/src/main/java/im/vector/riotx/ActiveSessionDataSource.kt
index fd6a92e820..4cafdb8d11 100644
--- a/vector/src/main/java/im/vector/riotx/ActiveSessionObservableStore.kt
+++ b/vector/src/main/java/im/vector/riotx/ActiveSessionDataSource.kt
@@ -19,9 +19,9 @@ package im.vector.riotx
import arrow.core.Option
import im.vector.matrix.android.api.session.Session
-import im.vector.riotx.core.utils.RxStore
+import im.vector.riotx.core.utils.BehaviorDataSource
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class ActiveSessionObservableStore @Inject constructor() : RxStore