From 9f3f5d8053fa90450d6166acb63bc07d6dd1704f Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 3 Nov 2020 16:53:30 +0100 Subject: [PATCH 01/21] Realm 10: upgrade lib and make it works on our current code. --- CHANGES.md | 2 +- matrix-sdk-android/build.gradle | 4 ++-- .../org/matrix/android/sdk/internal/crypto/CryptoModule.kt | 1 + .../matrix/android/sdk/internal/database/RealmKeysUtils.kt | 3 ++- .../sdk/internal/database/SessionRealmConfigurationFactory.kt | 1 + .../android/sdk/internal/session/identity/IdentityModule.kt | 1 + 6 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index fe88aed5ab..c44d299f27 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,7 +35,7 @@ Build 🧱: - Other changes: - - + - Upgrade Realm dependency to 10.0.0 Changes in Element 1.0.9 (2020-10-16) =================================================== diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index e4a8b8884a..29c709844a 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -9,7 +9,7 @@ buildscript { jcenter() } dependencies { - classpath "io.realm:realm-gradle-plugin:6.1.0" + classpath "io.realm:realm-gradle-plugin:10.0.0" } } @@ -149,7 +149,7 @@ dependencies { implementation 'androidx.exifinterface:exifinterface:1.3.0' // Database - implementation 'com.github.Zhuinden:realm-monarchy:0.5.1' + implementation 'com.github.Zhuinden:realm-monarchy:0.7.1' kapt 'dk.ilios:realmfieldnameshelper:1.1.1' // Work diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt index a8580bab8e..a786ebd4b2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt @@ -123,6 +123,7 @@ internal abstract class CryptoModule { } .name("crypto_store.realm") .modules(RealmCryptoStoreModule()) + .allowWritesOnUiThread(true) .schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION) .migration(realmCryptoStoreMigration) .build() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt index 6c430e8591..0e3a7a2c49 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database import android.content.Context import android.util.Base64 import androidx.core.content.edit +import io.realm.Realm import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.internal.session.securestorage.SecretStoringUtils import io.realm.RealmConfiguration @@ -46,7 +47,7 @@ internal class RealmKeysUtils @Inject constructor(context: Context, private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.keys", Context.MODE_PRIVATE) private fun generateKeyForRealm(): ByteArray { - val keyForRealm = ByteArray(RealmConfiguration.KEY_LENGTH) + val keyForRealm = ByteArray(Realm.ENCRYPTION_KEY_LENGTH) rng.nextBytes(keyForRealm) return keyForRealm } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt index 3324520d29..244fe3432a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt @@ -69,6 +69,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor( .apply { realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5)) } + .allowWritesOnUiThread(true) .modules(SessionRealmModule()) .schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION) .migration(migration) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt index 1bb57b47cd..e140cc19f3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt @@ -66,6 +66,7 @@ internal abstract class IdentityModule { .apply { realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5)) } + .allowWritesOnUiThread(true) .modules(IdentityRealmModule()) .build() } From 619ec4faa43df705239369f76663ce4793e94fe1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Nov 2020 15:57:56 +0100 Subject: [PATCH 02/21] Prepare release v1.0.10 --- CHANGES.md | 17 +---------------- .../android/en-US/changelogs/40100100.txt | 3 ++- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d91be2ef2b..8dceffbcf0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,6 @@ -Changes in Element 1.0.10 (2020-XX-XX) +Changes in Element 1.0.10 (2020-11-04) =================================================== -Features ✨: - - - Improvements 🙌: - Rework sending Event management (#154) - New room creation screen: set topic and avatar in the room creation form (#2078) @@ -28,18 +25,6 @@ Bugfix 🐛: - KeysBackup: Avoid using `!!` (#2262) - Two elements in the task switcher (#2299) -Translations 🗣: - - - -SDK API changes ⚠️: - - - -Build 🧱: - - - -Other changes: - - - Changes in Element 1.0.9 (2020-10-16) =================================================== diff --git a/fastlane/metadata/android/en-US/changelogs/40100100.txt b/fastlane/metadata/android/en-US/changelogs/40100100.txt index 0ffdd02fcb..c1821d2475 100644 --- a/fastlane/metadata/android/en-US/changelogs/40100100.txt +++ b/fastlane/metadata/android/en-US/changelogs/40100100.txt @@ -1 +1,2 @@ -// TODO \ No newline at end of file +This new version mainly contains bug fixes and improvements. Sending a message is now much faster. +Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.0.10 \ No newline at end of file From 17fed39b27c093922d0035924f4e616617a275eb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Nov 2020 16:00:16 +0100 Subject: [PATCH 03/21] Version++ --- CHANGES.md | 24 ++++++++++++++++++++++++ vector/build.gradle | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 8dceffbcf0..7fbf564393 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,27 @@ +Changes in Element 1.0.11 (2020-XX-XX) +=================================================== + +Features ✨: + - + +Improvements 🙌: + - + +Bugfix 🐛: + - + +Translations 🗣: + - + +SDK API changes ⚠️: + - + +Build 🧱: + - + +Other changes: + - + Changes in Element 1.0.10 (2020-11-04) =================================================== diff --git a/vector/build.gradle b/vector/build.gradle index 96b4994a7a..ca7cb12e31 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -17,7 +17,7 @@ androidExtensions { // Note: 2 digits max for each value ext.versionMajor = 1 ext.versionMinor = 0 -ext.versionPatch = 10 +ext.versionPatch = 11 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' From 45edf6025eebba0bc3a94d606adb903cc2c07b88 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Nov 2020 16:01:33 +0100 Subject: [PATCH 04/21] SAS Strings for Italian --- .../src/main/res/values-it/strings_sas.xml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 matrix-sdk-android/src/main/res/values-it/strings_sas.xml diff --git a/matrix-sdk-android/src/main/res/values-it/strings_sas.xml b/matrix-sdk-android/src/main/res/values-it/strings_sas.xml new file mode 100644 index 0000000000..b66c22bc6b --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-it/strings_sas.xml @@ -0,0 +1,68 @@ + + + + Cane + Gatto + Leone + Cavallo + Unicorno + Maiale + Elefante + Coniglio + Panda + Gallo + Pinguino + Tartaruga + Pesce + Polpo + Farfalla + Fiore + Albero + Cactus + Fungo + Globo + Luna + Nuvola + Fuoco + Banana + Mela + Fragola + Mais + Pizza + Torta + Cuore + Faccina sorridente + Robot + Cappello + Occhiali + Chiave inglese + Babbo Natale + Pollice alzato + Ombrello + Clessidra + Orologio + Regalo + Lampadina + Libro + Matita + Graffetta + Forbici + Lucchetto + Chiave + Martello + Telefono + Bandiera + Treno + Bicicletta + Aeroplano + Razzo + Trofeo + Palla + Chitarra + Trombetta + Campana + Ancora + Cuffie + Cartella + Puntina + From 6cb46455144f769fa4afd4c1291524f554c046cc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Nov 2020 15:28:13 +0100 Subject: [PATCH 05/21] Add a key to the category, to be able to hide it --- vector/src/main/res/xml/vector_settings_security_privacy.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/xml/vector_settings_security_privacy.xml b/vector/src/main/res/xml/vector_settings_security_privacy.xml index fa26107edb..5dfde2d1df 100644 --- a/vector/src/main/res/xml/vector_settings_security_privacy.xml +++ b/vector/src/main/res/xml/vector_settings_security_privacy.xml @@ -115,7 +115,9 @@ - + Date: Thu, 5 Nov 2020 15:33:28 +0100 Subject: [PATCH 06/21] Some fixes from Valere about verification --- .../crypto/quads/SharedSecureStorageViewModel.kt | 6 ++++++ .../crypto/recover/BootstrapCrossSigningTask.kt | 12 +++++++++++- .../IncomingVerificationRequestHandler.kt | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt index 951ff4ede6..862b2de85a 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt @@ -140,6 +140,12 @@ class SharedSecureStorageViewModel @AssistedInject constructor( } private fun handleDoResetAll() { + // as we are going to reset, we'd better cancel all outgoing requests + // if not they could be accepted in the middle of the reset process + // and cause strange use cases + session.cryptoService().verificationService().getExistingVerificationRequest(session.myUserId)?.forEach { + session.cryptoService().verificationService().cancelVerificationRequest(it) + } _viewEvents.post(SharedSecureStorageViewEvent.ShowResetBottomSheet) } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapCrossSigningTask.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapCrossSigningTask.kt index b7c689f41f..47e373ed0a 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapCrossSigningTask.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapCrossSigningTask.kt @@ -237,7 +237,7 @@ class BootstrapCrossSigningTask @Inject constructor( Timber.d("## BootstrapCrossSigningTask: Creating 4S - Checking megolm backup") // First ensure that in sync - val serverVersion = awaitCallback { + var serverVersion = awaitCallback { session.cryptoService().keysBackupService().getCurrentVersion(it) } @@ -247,6 +247,16 @@ class BootstrapCrossSigningTask @Inject constructor( || (params.setupMode == SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET && !isMegolmBackupSecretKnown) || (params.setupMode == SetupMode.HARD_RESET) if (shouldCreateKeyBackup) { + // clear all existing backups + while (serverVersion != null) { + awaitCallback { + session.cryptoService().keysBackupService().deleteBackup(serverVersion!!.version, it) + } + serverVersion = awaitCallback { + session.cryptoService().keysBackupService().getCurrentVersion(it) + } + } + Timber.d("## BootstrapCrossSigningTask: Creating 4S - Create megolm backup") val creationInfo = awaitCallback { session.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, it) diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt index e42eb6de6f..7d98b7c2a5 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt @@ -164,7 +164,7 @@ class IncomingVerificationRequestHandler @Inject constructor( override fun verificationRequestUpdated(pr: PendingVerificationRequest) { // If an incoming request is readied (by another device?) we should discard the alert - if (pr.isIncoming && (pr.isReady || pr.handledByOtherSession)) { + if (pr.isIncoming && (pr.isReady || pr.handledByOtherSession || pr.cancelConclusion != null)) { popupAlertManager.cancelAlert(uniqueIdForVerificationRequest(pr)) } } From b7a1f962942711805bab3b7fbafbe376e36ac62a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Nov 2020 15:40:12 +0100 Subject: [PATCH 07/21] Append to file but before the extension --- .../dialogs/GalleryOrCameraDialogHelper.kt | 3 ++- .../app/core/extensions/BasicExtensions.kt | 18 ++++++++++++++++++ .../preview/AttachmentsPreviewFragment.kt | 3 ++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt b/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt index 7198cdb4a2..5ecabd2aaa 100644 --- a/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt +++ b/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt @@ -23,6 +23,7 @@ import androidx.core.net.toUri import androidx.fragment.app.Fragment import com.yalantis.ucrop.UCrop import im.vector.app.R +import im.vector.app.core.extensions.insertBeforeLast import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO @@ -86,7 +87,7 @@ class GalleryOrCameraDialogHelper( } private fun startUCrop(image: MultiPickerImageType) { - val destinationFile = File(activity.cacheDir, "${image.displayName}_e_${System.currentTimeMillis()}") + val destinationFile = File(activity.cacheDir, image.displayName.insertBeforeLast("_e_${System.currentTimeMillis()}")) val uri = image.contentUri createUCropWithDefaultSettings(colorProvider, uri, destinationFile.toUri(), fragment.getString(R.string.rotate_and_crop_screen_title)) .withAspectRatio(1f, 1f) diff --git a/vector/src/main/java/im/vector/app/core/extensions/BasicExtensions.kt b/vector/src/main/java/im/vector/app/core/extensions/BasicExtensions.kt index c3e6520a46..07a684abef 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/BasicExtensions.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/BasicExtensions.kt @@ -48,3 +48,21 @@ fun CharSequence.isMsisdn(): Boolean { false } } + +/** + * Useful to append a String at the end of a filename but before the extension if any + * Ex: + * - "file.txt".insertBeforeLast("_foo") will return "file_foo.txt" + * - "file".insertBeforeLast("_foo") will return "file_foo" + * - "fi.le.txt".insertBeforeLast("_foo") will return "fi.le_foo.txt" + * - null.insertBeforeLast("_foo") will return "_foo" + */ +fun String?.insertBeforeLast(insert: String, delimiter: String = ".") : String { + if (this == null) return insert + val idx = lastIndexOf(delimiter) + return if (idx == -1) { + this + insert + } else { + replaceRange(idx, idx, insert) + } +} diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt index 9f3ba39bbe..ba0250724c 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt @@ -38,6 +38,7 @@ import com.airbnb.mvrx.withState import com.yalantis.ucrop.UCrop import im.vector.app.R import im.vector.app.core.extensions.cleanup +import im.vector.app.core.extensions.insertBeforeLast import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider @@ -170,7 +171,7 @@ class AttachmentsPreviewFragment @Inject constructor( private fun handleEditAction() = withState(viewModel) { val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState - val destinationFile = File(requireContext().cacheDir, "${currentAttachment.name}_edited_image_${System.currentTimeMillis()}") + val destinationFile = File(requireContext().cacheDir, currentAttachment.name.insertBeforeLast("_edited_image_${System.currentTimeMillis()}")) val uri = currentAttachment.queryUri createUCropWithDefaultSettings(colorProvider, uri, destinationFile.toUri(), currentAttachment.name) .getIntent(requireContext()) From 61ed436c4477a540bd77d4d7a47c79856a577976 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Nov 2020 15:41:52 +0100 Subject: [PATCH 08/21] Move some method to the companion --- .../im/vector/lib/multipicker/CameraPicker.kt | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/CameraPicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/CameraPicker.kt index 3f24a28c28..64df788e53 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/CameraPicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/CameraPicker.kt @@ -94,19 +94,21 @@ class CameraPicker { return Intent(MediaStore.ACTION_IMAGE_CAPTURE) } - private fun createPhotoUri(context: Context): Uri { - val file = createImageFile(context) - val authority = context.packageName + ".multipicker.fileprovider" - return FileProvider.getUriForFile(context, authority, file) - } + companion object { + fun createPhotoUri(context: Context): Uri { + val file = createImageFile(context) + val authority = context.packageName + ".multipicker.fileprovider" + return FileProvider.getUriForFile(context, authority, file) + } - private fun createImageFile(context: Context): File { - val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) - val storageDir: File = context.filesDir - return File.createTempFile( - "${timeStamp}_", /* prefix */ - ".jpg", /* suffix */ - storageDir /* directory */ - ) + private fun createImageFile(context: Context): File { + val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) + val storageDir: File = context.filesDir + return File.createTempFile( + "${timeStamp}_", /* prefix */ + ".jpg", /* suffix */ + storageDir /* directory */ + ) + } } } From c9e0aff839a8de268084e748b010fde2001355bf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Nov 2020 15:42:44 +0100 Subject: [PATCH 09/21] DRY --- .../im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt b/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt index 5ecabd2aaa..8cb122d5bb 100644 --- a/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt +++ b/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt @@ -117,7 +117,7 @@ class GalleryOrCameraDialogHelper( when (type) { Type.Camera -> if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, activity, takePhotoPermissionActivityResultLauncher)) { - avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(activity, takePhotoActivityResultLauncher) + doOpenCamera() } Type.Gallery -> MultiPicker.get(MultiPicker.IMAGE).single().startWith(pickImageActivityResultLauncher) From 5c7a5fab94b780d907b1b256639c777fcb212054 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Nov 2020 15:47:28 +0100 Subject: [PATCH 10/21] Improve API: rename the method and return empty list instead of null --- .../sdk/internal/crypto/verification/SASTest.kt | 6 +++--- .../crypto/verification/VerificationService.kt | 2 +- .../verification/DefaultVerificationService.kt | 13 ++++++------- .../crypto/quads/SharedSecureStorageViewModel.kt | 2 +- .../VerificationBottomSheetViewModel.kt | 4 ++-- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt index 75c7ad4d53..a81f503e77 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt @@ -555,7 +555,7 @@ class SASTest : InstrumentedTest { mTestHelper.waitWithLatch { mTestHelper.retryPeriodicallyWithLatch(it) { - val prAlicePOV = aliceVerificationService.getExistingVerificationRequest(bobSession.myUserId)?.firstOrNull() + val prAlicePOV = aliceVerificationService.getExistingVerificationRequests(bobSession.myUserId).firstOrNull() requestID = prAlicePOV?.transactionId Log.v("TEST", "== alicePOV is $prAlicePOV") prAlicePOV?.transactionId != null && prAlicePOV.localId == req.localId @@ -566,7 +566,7 @@ class SASTest : InstrumentedTest { mTestHelper.waitWithLatch { mTestHelper.retryPeriodicallyWithLatch(it) { - val prBobPOV = bobVerificationService.getExistingVerificationRequest(aliceSession.myUserId)?.firstOrNull() + val prBobPOV = bobVerificationService.getExistingVerificationRequests(aliceSession.myUserId).firstOrNull() Log.v("TEST", "== prBobPOV is $prBobPOV") prBobPOV?.transactionId == requestID } @@ -581,7 +581,7 @@ class SASTest : InstrumentedTest { // wait for alice to get the ready mTestHelper.waitWithLatch { mTestHelper.retryPeriodicallyWithLatch(it) { - val prAlicePOV = aliceVerificationService.getExistingVerificationRequest(bobSession.myUserId)?.firstOrNull() + val prAlicePOV = aliceVerificationService.getExistingVerificationRequests(bobSession.myUserId).firstOrNull() Log.v("TEST", "== prAlicePOV is $prAlicePOV") prAlicePOV?.transactionId == requestID && prAlicePOV?.isReady != null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt index 65c6a1f1f7..2413786ea9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt @@ -41,7 +41,7 @@ interface VerificationService { fun getExistingTransaction(otherUserId: String, tid: String): VerificationTransaction? - fun getExistingVerificationRequest(otherUserId: String): List? + fun getExistingVerificationRequests(otherUserId: String): List fun getExistingVerificationRequest(otherUserId: String, tid: String?): PendingVerificationRequest? diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt index 7f02750359..29ddd92213 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt @@ -537,11 +537,10 @@ internal class DefaultVerificationService @Inject constructor( // If there is a corresponding request, we can auto accept // as we are the one requesting in first place (or we accepted the request) // I need to check if the pending request was related to this device also - val autoAccept = getExistingVerificationRequest(otherUserId)?.any { + val autoAccept = getExistingVerificationRequests(otherUserId).any { it.transactionId == startReq.transactionId && (it.requestInfo?.fromDevice == this.deviceId || it.readyInfo?.fromDevice == this.deviceId) } - ?: false val tx = DefaultIncomingSASDefaultVerificationTransaction( // this, setDeviceVerificationAction, @@ -837,8 +836,8 @@ internal class DefaultVerificationService @Inject constructor( // SAS do not care for now? } - // Now transactions are udated, let's also update Requests - val existingRequest = getExistingVerificationRequest(senderId)?.find { it.transactionId == doneReq.transactionId } + // Now transactions are updated, let's also update Requests + val existingRequest = getExistingVerificationRequests(senderId).find { it.transactionId == doneReq.transactionId } if (existingRequest == null) { Timber.e("## SAS Received Done for unknown request txId:${doneReq.transactionId}") return @@ -892,7 +891,7 @@ internal class DefaultVerificationService @Inject constructor( private fun handleReadyReceived(senderId: String, readyReq: ValidVerificationInfoReady, transportCreator: (DefaultVerificationTransaction) -> VerificationTransport) { - val existingRequest = getExistingVerificationRequest(senderId)?.find { it.transactionId == readyReq.transactionId } + val existingRequest = getExistingVerificationRequests(senderId).find { it.transactionId == readyReq.transactionId } if (existingRequest == null) { Timber.e("## SAS Received Ready for unknown request txId:${readyReq.transactionId} fromDevice ${readyReq.fromDevice}") return @@ -1041,9 +1040,9 @@ internal class DefaultVerificationService @Inject constructor( } } - override fun getExistingVerificationRequest(otherUserId: String): List? { + override fun getExistingVerificationRequests(otherUserId: String): List { synchronized(lock = pendingRequests) { - return pendingRequests[otherUserId] + return pendingRequests[otherUserId].orEmpty() } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt index 862b2de85a..c7533cd3df 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt @@ -143,7 +143,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( // as we are going to reset, we'd better cancel all outgoing requests // if not they could be accepted in the middle of the reset process // and cause strange use cases - session.cryptoService().verificationService().getExistingVerificationRequest(session.myUserId)?.forEach { + session.cryptoService().verificationService().getExistingVerificationRequests(session.myUserId).forEach { session.cryptoService().verificationService().cancelVerificationRequest(it) } _viewEvents.post(SharedSecureStorageViewEvent.ShowResetBottomSheet) diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt index 2d09974687..aa20a9a992 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt @@ -99,8 +99,8 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( val pr = if (selfVerificationMode) { // See if active tx for this user and take it - session.cryptoService().verificationService().getExistingVerificationRequest(args.otherUserId) - ?.lastOrNull { !it.isFinished } + session.cryptoService().verificationService().getExistingVerificationRequests(args.otherUserId) + .lastOrNull { !it.isFinished } ?.also { verificationRequest -> if (verificationRequest.isIncoming && !verificationRequest.isReady) { // auto ready in this case, as we are waiting From de39a17247185a7e682bdd9a79b6086559936c43 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Nov 2020 16:09:04 +0100 Subject: [PATCH 11/21] Fix issue on setting avatar on a room. We deleted the just added avatar because `withState {}` is asynchronous --- CHANGES.md | 2 +- .../settings/RoomSettingsViewModel.kt | 28 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7fbf564393..c1e6bab185 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,7 +8,7 @@ Improvements 🙌: - Bugfix 🐛: - - + - Fix issue when updating the avatar of a room Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt index 32d8f043c3..6bf88e755e 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt @@ -153,20 +153,20 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: } private fun handleSetAvatarAction(action: RoomSettingsAction.SetAvatarAction) { - deletePendingAvatar() - setState { copy(avatarAction = action.avatarAction) } - } - - private fun deletePendingAvatar() { - // Maybe delete the pending avatar - withState { - (it.avatarAction as? RoomSettingsViewState.AvatarAction.UpdateAvatar) - ?.let { tryOrNull { it.newAvatarUri.toFile().delete() } } + setState { + deletePendingAvatar(this) + copy(avatarAction = action.avatarAction) } } + private fun deletePendingAvatar(state: RoomSettingsViewState) { + // Maybe delete the pending avatar + (state.avatarAction as? RoomSettingsViewState.AvatarAction.UpdateAvatar) + ?.let { tryOrNull { it.newAvatarUri.toFile().delete() } } + } + private fun cancel() { - deletePendingAvatar() + withState { deletePendingAvatar(it) } _viewEvents.post(RoomSettingsViewEvents.GoBack) } @@ -180,7 +180,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: when (val avatarAction = state.avatarAction) { RoomSettingsViewState.AvatarAction.None -> Unit - RoomSettingsViewState.AvatarAction.DeleteAvatar -> { + RoomSettingsViewState.AvatarAction.DeleteAvatar -> { operationList.add(room.rx().deleteAvatar()) } is RoomSettingsViewState.AvatarAction.UpdateAvatar -> { @@ -209,8 +209,10 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: .subscribe( { postLoading(false) - setState { copy(newHistoryVisibility = null) } - deletePendingAvatar() + setState { + deletePendingAvatar(this) + copy(newHistoryVisibility = null) + } _viewEvents.post(RoomSettingsViewEvents.Success) }, { From e7714da8e8f65b8764daf762f9e3b9d4cf2df04a Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 4 Nov 2020 16:32:25 +0300 Subject: [PATCH 12/21] Navigate to an existing DM instead of creating a new one. --- CHANGES.md | 1 + .../createdirect/CreateDirectRoomViewModel.kt | 26 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 79ea40de59..31dd8388e0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -39,6 +39,7 @@ Improvements 🙌: - Add graphic resources for F-Droid (#812, #2220) - Highlight text in the body of the displayed result (#2200) - Considerably faster QR-code bitmap generation (#2331) + - Open an existing DM instead of creating a new one (#2319) Bugfix 🐛: - Fixed ringtone handling (#2100 & #2246) diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt index c42e10686f..7d8b8c0c82 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt @@ -19,6 +19,7 @@ package im.vector.app.features.createdirect import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject @@ -56,10 +57,33 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted override fun handle(action: CreateDirectRoomAction) { when (action) { - is CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers -> createRoomAndInviteSelectedUsers(action.invitees) + is CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers -> onSubmitInvitees(action.invitees) } } + /** + * If users already have a DM room then navigate to it instead of creating a new room. + */ + private fun onSubmitInvitees(invitees: Set) { + invitees + .takeIf { it.size == 1 } + ?.first() + ?.let { invitee -> + when (invitee) { + is PendingInvitee.UserPendingInvitee -> session.getExistingDirectRoomWithUser(invitee.user.userId) + is PendingInvitee.ThreePidPendingInvitee -> null + }.exhaustive + } + ?.let { roomId -> + setState { + copy(createAndInviteState = Success(roomId)) + } + } + ?: run { + createRoomAndInviteSelectedUsers(invitees) + } + } + private fun createRoomAndInviteSelectedUsers(invitees: Set) { viewModelScope.launch(Dispatchers.IO) { val adminE2EByDefault = rawService.getElementWellknown(session.myUserId) From 458b4259fe0950c4c14734113292eebcfa627798 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 4 Nov 2020 17:51:31 +0300 Subject: [PATCH 13/21] Change menu action title for existing rooms. --- .../createdirect/CreateDirectRoomActivity.kt | 3 ++- .../userdirectory/KnownUsersFragment.kt | 3 +++ .../userdirectory/KnownUsersFragmentArgs.kt | 3 ++- .../userdirectory/UserDirectoryViewModel.kt | 27 +++++++++++++++++-- .../userdirectory/UserDirectoryViewState.kt | 3 ++- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index a1bb12a84b..3dfd93bea7 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -91,7 +91,8 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { KnownUsersFragment::class.java, KnownUsersFragmentArgs( title = getString(R.string.fab_menu_create_chat), - menuResId = R.menu.vector_create_direct_room + menuResId = R.menu.vector_create_direct_room, + isCreatingRoom = true ) ) } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt index c832fe4833..17e619d990 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt @@ -91,6 +91,9 @@ class KnownUsersFragment @Inject constructor( val showMenuItem = it.pendingInvitees.isNotEmpty() menu.forEach { menuItem -> menuItem.isVisible = showMenuItem + if (args.isCreatingRoom) { + menuItem.setTitle(if (it.isThereAnExistingRoom) R.string.action_open else R.string.create_room_action_create) + } } } super.onPrepareOptionsMenu(menu) diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt index 65fd6681bf..c20aedb803 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt @@ -23,5 +23,6 @@ import kotlinx.android.parcel.Parcelize data class KnownUsersFragmentArgs( val title: String, val menuResId: Int, - val excludedUserIds: Set? = null + val excludedUserIds: Set? = null, + val isCreatingRoom: Boolean = false ) : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt index b8c42a0f08..a924280da3 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt @@ -87,14 +87,37 @@ class UserDirectoryViewModel @AssistedInject constructor(@Assisted private fun handleRemoveSelectedUser(action: UserDirectoryAction.RemovePendingInvitee) = withState { state -> val selectedUsers = state.pendingInvitees.minus(action.pendingInvitee) - setState { copy(pendingInvitees = selectedUsers) } + setState { + copy( + pendingInvitees = selectedUsers, + isThereAnExistingRoom = isThereAnExistingRoom(selectedUsers) + ) + } } private fun handleSelectUser(action: UserDirectoryAction.SelectPendingInvitee) = withState { state -> // Reset the filter asap directoryUsersSearch.accept("") val selectedUsers = state.pendingInvitees.toggle(action.pendingInvitee) - setState { copy(pendingInvitees = selectedUsers) } + setState { + copy( + pendingInvitees = selectedUsers, + isThereAnExistingRoom = isThereAnExistingRoom(selectedUsers) + ) + } + } + + private fun isThereAnExistingRoom(selectedUsers: Set): Boolean { + return selectedUsers + .takeIf { it.size == 1 } + ?.firstOrNull() + ?.let { invitee -> + return when (invitee) { + is PendingInvitee.UserPendingInvitee -> session.getExistingDirectRoomWithUser(invitee.user.userId) != null + is PendingInvitee.ThreePidPendingInvitee -> false + }.exhaustive + } + ?: false } private fun observeDirectoryUsers() = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt index 8bb555e0fa..3d2cd0c1b4 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt @@ -30,7 +30,8 @@ data class UserDirectoryViewState( val pendingInvitees: Set = emptySet(), val createAndInviteState: Async = Uninitialized, val directorySearchTerm: String = "", - val filterKnownUsersValue: Option = Option.empty() + val filterKnownUsersValue: Option = Option.empty(), + val isThereAnExistingRoom: Boolean = false ) : MvRxState { constructor(args: KnownUsersFragmentArgs) : this(excludedUserIds = args.excludedUserIds) From 12d8bd17433bd2248408f12db989592eb650019b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Nov 2020 17:34:10 +0100 Subject: [PATCH 14/21] Cleanup after rebase - avoid computing twice the existing roomId --- CHANGES.md | 3 +- .../createdirect/CreateDirectRoomAction.kt | 5 ++- .../createdirect/CreateDirectRoomActivity.kt | 5 ++- .../createdirect/CreateDirectRoomViewModel.kt | 32 +++++++------------ .../userdirectory/KnownUsersFragment.kt | 8 +++-- .../UserDirectorySharedAction.kt | 4 ++- .../userdirectory/UserDirectoryViewModel.kt | 15 +++------ .../userdirectory/UserDirectoryViewState.kt | 2 +- 8 files changed, 36 insertions(+), 38 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 31dd8388e0..fa30acabd5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features ✨: - Improvements 🙌: - - + - Open an existing DM instead of creating a new one (#2319) Bugfix 🐛: - Fix issue when updating the avatar of a room @@ -39,7 +39,6 @@ Improvements 🙌: - Add graphic resources for F-Droid (#812, #2220) - Highlight text in the body of the displayed result (#2200) - Considerably faster QR-code bitmap generation (#2331) - - Open an existing DM instead of creating a new one (#2319) Bugfix 🐛: - Fixed ringtone handling (#2100 & #2246) diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomAction.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomAction.kt index f6fc3fed5b..ce91761fdd 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomAction.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomAction.kt @@ -20,5 +20,8 @@ import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.features.userdirectory.PendingInvitee sealed class CreateDirectRoomAction : VectorViewModelAction { - data class CreateRoomAndInviteSelectedUsers(val invitees: Set) : CreateDirectRoomAction() + data class CreateRoomAndInviteSelectedUsers( + val invitees: Set, + val existingDmRoomId: String? + ) : CreateDirectRoomAction() } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 3dfd93bea7..10ab1673e4 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -122,7 +122,10 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { private fun onMenuItemSelected(action: UserDirectorySharedAction.OnMenuItemSelected) { if (action.itemId == R.id.action_create_direct_room) { - viewModel.handle(CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers(action.invitees)) + viewModel.handle(CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers( + action.invitees, + action.existingDmRoomId + )) } } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt index 7d8b8c0c82..be9449b77a 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt @@ -57,31 +57,23 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted override fun handle(action: CreateDirectRoomAction) { when (action) { - is CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers -> onSubmitInvitees(action.invitees) - } + is CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers -> onSubmitInvitees(action) + }.exhaustive } /** * If users already have a DM room then navigate to it instead of creating a new room. */ - private fun onSubmitInvitees(invitees: Set) { - invitees - .takeIf { it.size == 1 } - ?.first() - ?.let { invitee -> - when (invitee) { - is PendingInvitee.UserPendingInvitee -> session.getExistingDirectRoomWithUser(invitee.user.userId) - is PendingInvitee.ThreePidPendingInvitee -> null - }.exhaustive - } - ?.let { roomId -> - setState { - copy(createAndInviteState = Success(roomId)) - } - } - ?: run { - createRoomAndInviteSelectedUsers(invitees) - } + private fun onSubmitInvitees(action: CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers) { + if (action.existingDmRoomId != null) { + // Do not create a new DM, just tell that the creation is successful by passing the existing roomId + setState { + copy(createAndInviteState = Success(action.existingDmRoomId)) + } + } else { + // Create the DM + createRoomAndInviteSelectedUsers(action.invitees) + } } private fun createRoomAndInviteSelectedUsers(invitees: Set) { diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt index 17e619d990..0ca46cd154 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt @@ -92,7 +92,7 @@ class KnownUsersFragment @Inject constructor( menu.forEach { menuItem -> menuItem.isVisible = showMenuItem if (args.isCreatingRoom) { - menuItem.setTitle(if (it.isThereAnExistingRoom) R.string.action_open else R.string.create_room_action_create) + menuItem.setTitle(if (it.existingDmRoomId != null) R.string.action_open else R.string.create_room_action_create) } } } @@ -100,7 +100,11 @@ class KnownUsersFragment @Inject constructor( } override fun onOptionsItemSelected(item: MenuItem): Boolean = withState(viewModel) { - sharedActionViewModel.post(UserDirectorySharedAction.OnMenuItemSelected(item.itemId, it.pendingInvitees)) + sharedActionViewModel.post(UserDirectorySharedAction.OnMenuItemSelected( + item.itemId, + it.pendingInvitees, + it.existingDmRoomId + )) return@withState true } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt index a4ae0d1be2..14daa67f25 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt @@ -23,5 +23,7 @@ sealed class UserDirectorySharedAction : VectorSharedAction { object OpenPhoneBook : UserDirectorySharedAction() object Close : UserDirectorySharedAction() object GoBack : UserDirectorySharedAction() - data class OnMenuItemSelected(val itemId: Int, val invitees: Set) : UserDirectorySharedAction() + data class OnMenuItemSelected(val itemId: Int, + val invitees: Set, + val existingDmRoomId: String?) : UserDirectorySharedAction() } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt index a924280da3..0a24b85ce2 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt @@ -90,7 +90,7 @@ class UserDirectoryViewModel @AssistedInject constructor(@Assisted setState { copy( pendingInvitees = selectedUsers, - isThereAnExistingRoom = isThereAnExistingRoom(selectedUsers) + existingDmRoomId = getExistingDmRoomId(selectedUsers) ) } } @@ -102,22 +102,17 @@ class UserDirectoryViewModel @AssistedInject constructor(@Assisted setState { copy( pendingInvitees = selectedUsers, - isThereAnExistingRoom = isThereAnExistingRoom(selectedUsers) + existingDmRoomId = getExistingDmRoomId(selectedUsers) ) } } - private fun isThereAnExistingRoom(selectedUsers: Set): Boolean { + private fun getExistingDmRoomId(selectedUsers: Set): String? { return selectedUsers .takeIf { it.size == 1 } + ?.filterIsInstance(PendingInvitee.UserPendingInvitee::class.java) ?.firstOrNull() - ?.let { invitee -> - return when (invitee) { - is PendingInvitee.UserPendingInvitee -> session.getExistingDirectRoomWithUser(invitee.user.userId) != null - is PendingInvitee.ThreePidPendingInvitee -> false - }.exhaustive - } - ?: false + ?.let { invitee -> session.getExistingDirectRoomWithUser(invitee.user.userId) } } private fun observeDirectoryUsers() = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt index 3d2cd0c1b4..fe79a8ab37 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt @@ -31,7 +31,7 @@ data class UserDirectoryViewState( val createAndInviteState: Async = Uninitialized, val directorySearchTerm: String = "", val filterKnownUsersValue: Option = Option.empty(), - val isThereAnExistingRoom: Boolean = false + val existingDmRoomId: String? = null ) : MvRxState { constructor(args: KnownUsersFragmentArgs) : this(excludedUserIds = args.excludedUserIds) From 35768ff7e8171efbe2d8ad03bea2337ff33b663c Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Fri, 6 Nov 2020 16:49:51 +0000 Subject: [PATCH 15/21] Convert `AccountService` to suspend functions Signed-off-by: Dominic Fischer --- .../android/sdk/account/ChangePasswordTest.kt | 6 ++-- .../sdk/account/DeactivateAccountTest.kt | 4 +-- .../android/sdk/common/CommonTestHelper.kt | 10 +++++++ .../sdk/api/session/account/AccountService.kt | 6 ++-- .../session/account/DefaultAccountService.kt | 23 ++++----------- .../settings/VectorSettingsGeneralFragment.kt | 28 +++++++++---------- .../DeactivateAccountViewModel.kt | 23 +++++++++------ 7 files changed, 51 insertions(+), 49 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt index ec5477f976..6ae72aeb3a 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.account +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.common.CommonTestHelper @@ -43,8 +45,8 @@ class ChangePasswordTest : InstrumentedTest { val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false)) // Change password - commonTestHelper.doSync { - session.changePassword(TestConstants.PASSWORD, NEW_PASSWORD, it) + commonTestHelper.runBlockingTest { + session.changePassword(TestConstants.PASSWORD, NEW_PASSWORD) } // Try to login with the previous password, it will fail diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt index a6fbfd9b7a..9996eef0a8 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt @@ -43,8 +43,8 @@ class DeactivateAccountTest : InstrumentedTest { val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false)) // Deactivate the account - commonTestHelper.doSync { - session.deactivateAccount(TestConstants.PASSWORD, false, it) + commonTestHelper.runBlockingTest { + session.deactivateAccount(TestConstants.PASSWORD, false) } // Try to login on the previous account, it will fail (M_USER_DEACTIVATED) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index cbe4cca8a3..660a3cc5e3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -40,6 +40,7 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue @@ -343,6 +344,15 @@ class CommonTestHelper(context: Context) { await(latch, timeout) } + // Transform a method with a MatrixCallback to a synchronous method + fun runBlockingTest(timeout: Long = TestConstants.timeOutMillis, block: suspend () -> T): T { + return runBlocking { + withTimeout(timeout) { + block() + } + } + } + // Transform a method with a MatrixCallback to a synchronous method inline fun doSync(timeout: Long? = TestConstants.timeOutMillis, block: (MatrixCallback) -> Unit): T { val lock = CountDownLatch(1) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt index b05f0036b2..1913da7c78 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt @@ -16,8 +16,6 @@ package org.matrix.android.sdk.api.session.account -import org.matrix.android.sdk.api.MatrixCallback -import org.matrix.android.sdk.api.util.Cancelable /** * This interface defines methods to manage the account. It's implemented at the session level. @@ -28,7 +26,7 @@ interface AccountService { * @param password Current password. * @param newPassword New password */ - fun changePassword(password: String, newPassword: String, callback: MatrixCallback): Cancelable + suspend fun changePassword(password: String, newPassword: String) /** * Deactivate the account. @@ -46,5 +44,5 @@ interface AccountService { * @param eraseAllData set to true to forget all messages that have been sent. Warning: this will cause future users to see * an incomplete view of conversations */ - fun deactivateAccount(password: String, eraseAllData: Boolean, callback: MatrixCallback): Cancelable + suspend fun deactivateAccount(password: String, eraseAllData: Boolean) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt index 31a39d45e5..1165d2116b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt @@ -16,30 +16,17 @@ package org.matrix.android.sdk.internal.session.account -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.account.AccountService -import org.matrix.android.sdk.api.util.Cancelable -import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.task.configureWith import javax.inject.Inject internal class DefaultAccountService @Inject constructor(private val changePasswordTask: ChangePasswordTask, - private val deactivateAccountTask: DeactivateAccountTask, - private val taskExecutor: TaskExecutor) : AccountService { + private val deactivateAccountTask: DeactivateAccountTask) : AccountService { - override fun changePassword(password: String, newPassword: String, callback: MatrixCallback): Cancelable { - return changePasswordTask - .configureWith(ChangePasswordTask.Params(password, newPassword)) { - this.callback = callback - } - .executeBy(taskExecutor) + override suspend fun changePassword(password: String, newPassword: String) { + changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword)) } - override fun deactivateAccount(password: String, eraseAllData: Boolean, callback: MatrixCallback): Cancelable { - return deactivateAccountTask - .configureWith(DeactivateAccountTask.Params(password, eraseAllData)) { - this.callback = callback - } - .executeBy(taskExecutor) + override suspend fun deactivateAccount(password: String, eraseAllData: Boolean) { + deactivateAccountTask.execute(DeactivateAccountTask.Params(password, eraseAllData)) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index d8171bd30d..b1ccabfb76 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -27,6 +27,7 @@ import android.widget.ImageView import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible +import androidx.lifecycle.lifecycleScope import androidx.preference.EditTextPreference import androidx.preference.Preference import androidx.preference.PreferenceCategory @@ -451,28 +452,25 @@ class VectorSettingsGeneralFragment @Inject constructor( val newPwd = newPasswordText.text.toString() showPasswordLoadingView(true) - session.changePassword(oldPwd, newPwd, object : MatrixCallback { - override fun onSuccess(data: Unit) { - if (!isAdded) { - return - } - showPasswordLoadingView(false) + lifecycleScope.launch { + val result = runCatching { + session.changePassword(oldPwd, newPwd) + } + if (!isAdded) { + return@launch + } + showPasswordLoadingView(false) + result.fold({ dialog.dismiss() activity.toast(R.string.settings_password_updated) - } - - override fun onFailure(failure: Throwable) { - if (!isAdded) { - return - } - showPasswordLoadingView(false) + }, { failure -> if (failure.isInvalidPassword()) { oldPasswordTil.error = getString(R.string.settings_fail_to_update_password_invalid_current_password) } else { oldPasswordTil.error = getString(R.string.settings_fail_to_update_password) } - } - }) + }) + } } } dialog.show() diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt index e08147d54f..f264f430ad 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt @@ -15,6 +15,7 @@ */ package im.vector.app.features.settings.account.deactivation +import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory @@ -24,9 +25,12 @@ import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModelAction +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.session.Session +import java.lang.Exception data class DeactivateAccountViewState( val passwordShown: Boolean = false @@ -67,19 +71,22 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v _viewEvents.post(DeactivateAccountViewEvents.Loading()) - session.deactivateAccount(action.password, action.eraseAllData, object : MatrixCallback { - override fun onSuccess(data: Unit) { - _viewEvents.post(DeactivateAccountViewEvents.Done) - } + viewModelScope.launch { + val event = try { + session.deactivateAccount(action.password, action.eraseAllData) + DeactivateAccountViewEvents.Done + } catch (failure: Exception) { + if (failure is CancellationException) throw failure - override fun onFailure(failure: Throwable) { if (failure.isInvalidPassword()) { - _viewEvents.post(DeactivateAccountViewEvents.InvalidPassword) + DeactivateAccountViewEvents.InvalidPassword } else { - _viewEvents.post(DeactivateAccountViewEvents.OtherFailure(failure)) + DeactivateAccountViewEvents.OtherFailure(failure) } } - }) + + _viewEvents.post(event) + } } companion object : MvRxViewModelFactory { From 983e02888caf53415a2635221c9a8d67ca1047bd Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Fri, 6 Nov 2020 19:17:45 +0000 Subject: [PATCH 16/21] Remove incorrect comment Signed-off-by: Dominic Fischer --- .../java/org/matrix/android/sdk/common/CommonTestHelper.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index 660a3cc5e3..0e7088a6a5 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -344,7 +344,6 @@ class CommonTestHelper(context: Context) { await(latch, timeout) } - // Transform a method with a MatrixCallback to a synchronous method fun runBlockingTest(timeout: Long = TestConstants.timeOutMillis, block: suspend () -> T): T { return runBlocking { withTimeout(timeout) { From 0da4ff7b029b895d6b0c04c5e99970ae0eee8da1 Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Fri, 6 Nov 2020 19:20:23 +0000 Subject: [PATCH 17/21] Run ktlint --- .../java/org/matrix/android/sdk/account/ChangePasswordTest.kt | 2 -- .../matrix/android/sdk/api/session/account/AccountService.kt | 1 - .../settings/account/deactivation/DeactivateAccountViewModel.kt | 1 - 3 files changed, 4 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt index 6ae72aeb3a..103b638c39 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt @@ -16,8 +16,6 @@ package org.matrix.android.sdk.account -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeout import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.common.CommonTestHelper diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt index 1913da7c78..8915202f35 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt @@ -16,7 +16,6 @@ package org.matrix.android.sdk.api.session.account - /** * This interface defines methods to manage the account. It's implemented at the session level. */ diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt index f264f430ad..672caca556 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt @@ -27,7 +27,6 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModelAction import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.session.Session import java.lang.Exception From 6207aab19dcd0a73d84c2850e77423eb0221523e Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Mon, 9 Nov 2020 17:20:23 +0000 Subject: [PATCH 18/21] Remove cancellation handling Signed-off-by: Dominic Fischer --- .../account/deactivation/DeactivateAccountViewModel.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt index 672caca556..211559c657 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt @@ -25,7 +25,6 @@ import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModelAction -import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.session.Session @@ -75,8 +74,6 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v session.deactivateAccount(action.password, action.eraseAllData) DeactivateAccountViewEvents.Done } catch (failure: Exception) { - if (failure is CancellationException) throw failure - if (failure.isInvalidPassword()) { DeactivateAccountViewEvents.InvalidPassword } else { From cedeea13e63e9f8e8891054c6704098219c39b50 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 9 Nov 2020 23:00:19 +0100 Subject: [PATCH 19/21] Fix discard change dialog displayed by mistake when avatar has been updated --- CHANGES.md | 3 ++- .../features/roomprofile/settings/RoomSettingsViewModel.kt | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index fa30acabd5..71a677beb8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,7 +8,8 @@ Improvements 🙌: - Open an existing DM instead of creating a new one (#2319) Bugfix 🐛: - - Fix issue when updating the avatar of a room + - Fix issue when updating the avatar of a room (new avatar vanishing) + - Discard change dialog displayed by mistake when avatar has been updated Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt index 6bf88e755e..4e540f867e 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt @@ -211,7 +211,10 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: postLoading(false) setState { deletePendingAvatar(this) - copy(newHistoryVisibility = null) + copy( + avatarAction = RoomSettingsViewState.AvatarAction.None, + newHistoryVisibility = null + ) } _viewEvents.post(RoomSettingsViewEvents.Success) }, From 13ddc28d059fd9a5e7d4562281f6c84cc8ab5342 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 9 Nov 2020 23:07:53 +0100 Subject: [PATCH 20/21] Fix issue with callback.onSuccess() called multiple times --- .../session/room/state/DefaultStateService.kt | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt index 65d375e176..3463b26c8a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt @@ -35,6 +35,7 @@ import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.launchToCallback import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers +import org.matrix.android.sdk.internal.util.awaitCallback internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String, private val stateEventDataSource: StateEventDataSource, @@ -132,23 +133,23 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private override fun updateAvatar(avatarUri: Uri, fileName: String, callback: MatrixCallback): Cancelable { return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) { val response = fileUploader.uploadFromUri(avatarUri, fileName, "image/jpeg") - sendStateEvent( - eventType = EventType.STATE_ROOM_AVATAR, - body = mapOf("url" to response.contentUri), - callback = callback, - stateKey = null - ) + awaitCallback { + sendStateEvent( + eventType = EventType.STATE_ROOM_AVATAR, + body = mapOf("url" to response.contentUri), + callback = it, + stateKey = null + ) + } } } override fun deleteAvatar(callback: MatrixCallback): Cancelable { - return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) { - sendStateEvent( - eventType = EventType.STATE_ROOM_AVATAR, - body = emptyMap(), - callback = callback, - stateKey = null - ) - } + return sendStateEvent( + eventType = EventType.STATE_ROOM_AVATAR, + body = emptyMap(), + callback = callback, + stateKey = null + ) } } From dc17e5c3fa215f7350498a134a694a4232ed1e60 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 10 Nov 2020 10:39:34 +0100 Subject: [PATCH 21/21] Update CHANGES.md after merge of #2354 --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 71a677beb8..26418c75f1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,7 +15,7 @@ Translations 🗣: - SDK API changes ⚠️: - - + - AccountService now exposes suspendable function instead of using MatrixCallback (#2354). Note: We will incrementally migrate all the SDK API in a near future. Build 🧱: -