From f4314ebdaef94e2b3dac5f91f8a7f46bcfc1f313 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Wed, 1 Jul 2020 21:58:58 +0200 Subject: [PATCH 01/28] Version++ --- CHANGES.md | 24 ++++++++++++++++++++++++ vector/build.gradle | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index ad3f82af9a..4a7d0d70af 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,27 @@ +Changes in Riot.imX 0.91.4 (2020-XX-XX) +=================================================== + +Features ✨: + - + +Improvements 🙌: + - + +Bugfix 🐛: + - + +Translations 🗣: + - + +SDK API changes ⚠️: + - + +Build 🧱: + - + +Other changes: + - + Changes in Riot.imX 0.91.3 (2020-07-01) =================================================== diff --git a/vector/build.gradle b/vector/build.gradle index 3c74ccda97..e497b156ae 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -17,7 +17,7 @@ androidExtensions { // Note: 2 digits max for each value ext.versionMajor = 0 ext.versionMinor = 91 -ext.versionPatch = 3 +ext.versionPatch = 4 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' From 93fb40f3235422c244e0c3575893763ab0f97f7e Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Thu, 2 Jul 2020 11:29:00 +0200 Subject: [PATCH 02/28] (re-)Enable abortOnError for lint And fix a first issue (on unused code) --- vector/build.gradle | 3 +-- .../vector/riotx/features/form/FormEditTextWithButtonItem.kt | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/build.gradle b/vector/build.gradle index e497b156ae..92e7239dbf 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -232,8 +232,7 @@ android { lintOptions { lintConfig file("lint.xml") - // TODO Restore true once pb with WorkManager is fixed - abortOnError false + abortOnError true } compileOptions { diff --git a/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt b/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt index 0650c0f55c..799f6abe00 100644 --- a/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt @@ -56,6 +56,7 @@ abstract class FormEditTextWithButtonItem : VectorEpoxyModel<FormEditTextWithBut } override fun bind(holder: Holder) { + super.bind(holder) holder.textInputLayout.isEnabled = enabled holder.textInputLayout.hint = hint From 5713fa4f595b80281e85c65047aba1f668914707 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Thu, 2 Jul 2020 12:17:09 +0200 Subject: [PATCH 03/28] Clean code --- .../java/im/vector/riotx/VectorApplication.kt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/VectorApplication.kt b/vector/src/main/java/im/vector/riotx/VectorApplication.kt index d0a3174227..ab7c3e1bf7 100644 --- a/vector/src/main/java/im/vector/riotx/VectorApplication.kt +++ b/vector/src/main/java/im/vector/riotx/VectorApplication.kt @@ -63,7 +63,13 @@ import java.util.Locale import java.util.concurrent.Executors import javax.inject.Inject -class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.Provider, androidx.work.Configuration.Provider { +import androidx.work.Configuration as WorkConfiguration + +class VectorApplication : + Application(), + HasVectorInjector, + MatrixConfiguration.Provider, + WorkConfiguration.Provider { lateinit var appContext: Context @Inject lateinit var legacySessionImporter: LegacySessionImporter @@ -85,6 +91,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration. @Inject lateinit var webRtcPeerConnectionManager: WebRtcPeerConnectionManager lateinit var vectorComponent: VectorComponent + // font thread handler private var fontThreadHandler: Handler? = null @@ -157,7 +164,11 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration. override fun providesMatrixConfiguration() = MatrixConfiguration(BuildConfig.FLAVOR_DESCRIPTION) - override fun getWorkManagerConfiguration() = androidx.work.Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build() + override fun getWorkManagerConfiguration(): WorkConfiguration { + return WorkConfiguration.Builder() + .setExecutor(Executors.newCachedThreadPool()) + .build() + } override fun injector(): VectorComponent { return vectorComponent From 1de819b0a3ab6dd3d4e878ed831c3416ce45de59 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Thu, 2 Jul 2020 12:21:23 +0200 Subject: [PATCH 04/28] Fix lint false-positive about WorkManger (#1012) --- CHANGES.md | 2 +- matrix-sdk-android/src/main/AndroidManifest.xml | 6 ------ vector/src/main/AndroidManifest.xml | 6 ++++++ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4a7d0d70af..378ea2279a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,7 +17,7 @@ SDK API changes ⚠️: - Build 🧱: - - + - Fix lint false-positive about WorkManger (#1012) Other changes: - diff --git a/matrix-sdk-android/src/main/AndroidManifest.xml b/matrix-sdk-android/src/main/AndroidManifest.xml index 94b2db2bf1..c02f34f1c9 100644 --- a/matrix-sdk-android/src/main/AndroidManifest.xml +++ b/matrix-sdk-android/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" package="im.vector.matrix.android"> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> @@ -8,11 +7,6 @@ <application android:networkSecurityConfig="@xml/network_security_config"> - <provider - android:name="androidx.work.impl.WorkManagerInitializer" - android:authorities="${applicationId}.workmanager-init" - android:exported="false" - tools:node="remove" /> <!-- The SDK offers a secured File provider to access downloaded files. Access to these file will be given via the FileService, with a temporary diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 3ed0d95b71..f9b78db17c 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -247,6 +247,12 @@ <!-- Providers --> + <!-- Remove WorkManagerInitializer Provider because we are using on-demand initialization of WorkManager--> + <provider + android:name="androidx.work.impl.WorkManagerInitializer" + android:authorities="${applicationId}.workmanager-init" + tools:node="remove" /> + <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileProvider" From 542d11d7f1fd095fddb7d0b8dd7aaca78ec3ab7d Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Thu, 2 Jul 2020 12:44:07 +0200 Subject: [PATCH 05/28] Upgrade build-tools from 3.5.3 to 3.6.6 and gradle from 5.4.1 to 5.6.4 --- CHANGES.md | 2 ++ build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 378ea2279a..3555894bf4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,8 @@ SDK API changes ⚠️: Build 🧱: - Fix lint false-positive about WorkManger (#1012) + - Upgrade build-tools from 3.5.3 to 3.6.6 + - Upgrade gradle from 5.4.1 to 5.6.4 Other changes: - diff --git a/build.gradle b/build.gradle index 74a62f0d17..5f1fa78620 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:3.6.3' classpath 'com.google.gms:google-services:4.3.2' classpath "com.airbnb.okreplay:gradle-plugin:1.5.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 51b92600a0..4da2435f42 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Sep 27 10:10:35 CEST 2019 +#Thu Jul 02 12:33:07 CEST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip From 69eaf2695e8c48eb78fec1c1defe54e6d41dfa24 Mon Sep 17 00:00:00 2001 From: Valere <valeref@matrix.org> Date: Thu, 2 Jul 2020 14:08:09 +0200 Subject: [PATCH 06/28] FIx / inbound session bad migration --- .../internal/crypto/store/db/RealmCryptoStoreMigration.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt index eb2fc9ebad..47af558b90 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -182,7 +182,8 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi try { val oldSerializedData = obj.getString("olmInboundGroupSessionData") deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 -> - val newOlmInboundGroupSessionWrapper2 = OlmInboundGroupSessionWrapper2() + val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier() + val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false) .apply { olmInboundGroupSession = mxOlmInboundGroupSession2.mSession roomId = mxOlmInboundGroupSession2.mRoomId @@ -191,7 +192,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain } - obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper2)) + obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper)) } } catch (e: Exception) { Timber.e(e, "Error") From 2ef82f1b827eeca512c7f05badbc2f13ef3cf3ae Mon Sep 17 00:00:00 2001 From: ganfra <francoisg@matrix.org> Date: Thu, 2 Jul 2020 16:05:05 +0200 Subject: [PATCH 07/28] Use HomeActivity.newIntent to make sure we have args --- .../features/notifications/NotificationUtils.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt index d7dabd0778..36874d5782 100755 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt @@ -205,7 +205,7 @@ class NotificationUtils @Inject constructor(private val context: Context, @SuppressLint("NewApi") fun buildForegroundServiceNotification(@StringRes subTitleResId: Int, withProgress: Boolean = true): Notification { // build the pending intent go to the home screen if this is clicked. - val i = Intent(context, HomeActivity::class.java) + val i = HomeActivity.newIntent(context) i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP val pi = PendingIntent.getActivity(context, 0, i, 0) @@ -307,7 +307,7 @@ class NotificationUtils @Inject constructor(private val context: Context, val contentPendingIntent = PendingIntent.getActivity(context, System.currentTimeMillis().toInt(), contentIntent, 0) val answerCallPendingIntent = TaskStackBuilder.create(context) - .addNextIntentWithParentStack(Intent(context, HomeActivity::class.java)) + .addNextIntentWithParentStack(HomeActivity.newIntent(context)) .addNextIntent(VectorCallActivity.newIntent( context = context, callId = callId, @@ -459,7 +459,7 @@ class NotificationUtils @Inject constructor(private val context: Context, ) val contentPendingIntent = TaskStackBuilder.create(context) - .addNextIntentWithParentStack(Intent(context, HomeActivity::class.java)) + .addNextIntentWithParentStack(HomeActivity.newIntent(context)) // TODO other userId .addNextIntent(VectorCallActivity.newIntent(context, callId, roomId, "otherUserId", true, isVideo, null)) .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT) @@ -651,7 +651,7 @@ class NotificationUtils @Inject constructor(private val context: Context, stringProvider.getString(R.string.join), joinIntentPendingIntent) - val contentIntent = Intent(context, HomeActivity::class.java) + val contentIntent = HomeActivity.newIntent(context) contentIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that contentIntent.data = Uri.parse("foobar://" + inviteNotifiableEvent.eventId) @@ -689,7 +689,7 @@ class NotificationUtils @Inject constructor(private val context: Context, .setColor(accentColor) .setAutoCancel(true) .apply { - val contentIntent = Intent(context, HomeActivity::class.java) + val contentIntent = HomeActivity.newIntent(context) contentIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that contentIntent.data = Uri.parse("foobar://" + simpleNotifiableEvent.eventId) @@ -718,7 +718,7 @@ class NotificationUtils @Inject constructor(private val context: Context, // Recreate the back stack return TaskStackBuilder.create(context) - .addNextIntentWithParentStack(Intent(context, HomeActivity::class.java)) + .addNextIntentWithParentStack(HomeActivity.newIntent(context)) .addNextIntent(roomIntentTap) .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT) } From 5008bfd6a9c7daf42196ec15749fd4b01e99954d Mon Sep 17 00:00:00 2001 From: ganfra <francoisg@matrix.org> Date: Thu, 2 Jul 2020 16:17:00 +0200 Subject: [PATCH 08/28] Update CHANGES --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 4a7d0d70af..519a42db4e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,7 +8,7 @@ Improvements 🙌: - Bugfix 🐛: - - + - Fix crash when coming from a notification (#1601) Translations 🗣: - From 596fcf94bac88f461cb6ef487f893fe710a6d613 Mon Sep 17 00:00:00 2001 From: Valere <valeref@matrix.org> Date: Thu, 2 Jul 2020 19:26:05 +0200 Subject: [PATCH 09/28] Fix / Serialization issues Fixes keybackup import failing and UTD of incoming messages --- matrix-sdk-android/proguard-rules.pro | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/matrix-sdk-android/proguard-rules.pro b/matrix-sdk-android/proguard-rules.pro index 08a20cbf0a..fa860d8049 100644 --- a/matrix-sdk-android/proguard-rules.pro +++ b/matrix-sdk-android/proguard-rules.pro @@ -64,3 +64,19 @@ ### Webrtc -keep class org.webrtc.** { *; } + +### Serializable persisted classes +# https://www.guardsquare.com/en/products/proguard/manual/examples#serializable +-keepnames class * implements java.io.Serializable + +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient <fields>; + !private <fields>; + !private <methods>; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} \ No newline at end of file From e098b87d0a9908f9cccbb0afab83819433083f2d Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Thu, 2 Jul 2020 21:30:49 +0200 Subject: [PATCH 10/28] Update comment --- .../internal/crypto/store/db/RealmCryptoStoreMigration.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt index 47af558b90..7bf8e2478f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -176,7 +176,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi } } - // Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper2 + // Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper realm.schema.get("OlmInboundGroupSessionEntity") ?.transform { obj -> try { From 15223ecfe4ccda4b97b27c8511d668e9b0b5e49c Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Thu, 2 Jul 2020 21:31:39 +0200 Subject: [PATCH 11/28] Update changelog with the recent change --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 4a7d0d70af..61e27a1476 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,7 +8,7 @@ Improvements 🙌: - Bugfix 🐛: - - + - Fix Exception when importing keys (#1576) Translations 🗣: - From bfb8b6203cca75448e97efc0f7bafc2ff62a7121 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Thu, 2 Jul 2020 22:02:42 +0200 Subject: [PATCH 12/28] Add proguard command (commented) --- vector/proguard-rules.pro | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vector/proguard-rules.pro b/vector/proguard-rules.pro index 56d3b95510..bc27767d8a 100644 --- a/vector/proguard-rules.pro +++ b/vector/proguard-rules.pro @@ -20,4 +20,7 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile --keep class im.vector.riotx.features.** { *; } \ No newline at end of file +-keep class im.vector.riotx.features.** { *; } + +## print all the rules in a file +# -printconfiguration ../proguard_files/full-r8-config.txt From d4050a7b9d18a92b56960c192d5662f2b48184ba Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Thu, 2 Jul 2020 23:39:42 +0200 Subject: [PATCH 13/28] Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use --- vector/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/build.gradle b/vector/build.gradle index 92e7239dbf..f966f441b2 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -106,6 +106,11 @@ def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0 android { compileSdkVersion 29 + + // Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use + // Ref: https://issuetracker.google.com/issues/144111441 + ndkVersion "21.3.6528147" + defaultConfig { applicationId "im.vector.app" // Set to API 21: see #405 From bdfce35d9a11c8aea854b4fbe6f14013aeaad6cd Mon Sep 17 00:00:00 2001 From: Valere <valeref@matrix.org> Date: Fri, 3 Jul 2020 09:34:38 +0200 Subject: [PATCH 14/28] Fix / save media on old android + add numbers to file if needed --- CHANGES.md | 2 + .../core/utils/ExternalApplicationsUtil.kt | 195 ++++++++++++++---- .../home/room/detail/RoomDetailFragment.kt | 24 ++- .../action/MessageSharedActionViewModel.kt | 4 +- 4 files changed, 173 insertions(+), 52 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b56cbef37a..636e848c3b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ Improvements 🙌: Bugfix 🐛: - Fix crash when coming from a notification (#1601) - Fix Exception when importing keys (#1576) + - File isn't downloaded when another file with the same name already exists (#1578) + - saved images don't show up in gallery (#1324) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/riotx/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/riotx/core/utils/ExternalApplicationsUtil.kt index d93d4e9089..2520f44f50 100644 --- a/vector/src/main/java/im/vector/riotx/core/utils/ExternalApplicationsUtil.kt +++ b/vector/src/main/java/im/vector/riotx/core/utils/ExternalApplicationsUtil.kt @@ -17,29 +17,39 @@ package im.vector.riotx.core.utils import android.app.Activity +import android.app.DownloadManager import android.content.ActivityNotFoundException import android.content.ContentValues import android.content.Context import android.content.Intent import android.graphics.BitmapFactory +import android.media.MediaScannerConnection import android.net.Uri import android.os.Build +import android.os.Environment import android.provider.Browser import android.provider.MediaStore +import android.webkit.MimeTypeMap import android.widget.Toast import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsSession import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.fragment.app.Fragment +import im.vector.matrix.android.api.extensions.tryThis import im.vector.riotx.BuildConfig import im.vector.riotx.R import im.vector.riotx.features.notifications.NotificationUtils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import okio.buffer import okio.sink import okio.source import timber.log.Timber import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -301,42 +311,20 @@ fun shareMedia(context: Context, file: File, mediaMimeType: String?) { fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String?, notificationUtils: NotificationUtils) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - val externalContentUri: Uri - val values = ContentValues() - when { - mediaMimeType?.startsWith("image/") == true -> { - externalContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI - values.put(MediaStore.Images.Media.TITLE, title) - values.put(MediaStore.Images.Media.DISPLAY_NAME, title) - values.put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType) - values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis()) - values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) - } - mediaMimeType?.startsWith("video/") == true -> { - externalContentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI - values.put(MediaStore.Video.Media.TITLE, title) - values.put(MediaStore.Video.Media.DISPLAY_NAME, title) - values.put(MediaStore.Video.Media.MIME_TYPE, mediaMimeType) - values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis()) - values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis()) - } - mediaMimeType?.startsWith("audio/") == true -> { - externalContentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI - values.put(MediaStore.Audio.Media.TITLE, title) - values.put(MediaStore.Audio.Media.DISPLAY_NAME, title) - values.put(MediaStore.Audio.Media.MIME_TYPE, mediaMimeType) - values.put(MediaStore.Audio.Media.DATE_ADDED, System.currentTimeMillis()) - values.put(MediaStore.Audio.Media.DATE_TAKEN, System.currentTimeMillis()) - } - else -> { - externalContentUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI - values.put(MediaStore.Downloads.TITLE, title) - values.put(MediaStore.Downloads.DISPLAY_NAME, title) - values.put(MediaStore.Downloads.MIME_TYPE, mediaMimeType) - values.put(MediaStore.Downloads.DATE_ADDED, System.currentTimeMillis()) - values.put(MediaStore.Downloads.DATE_TAKEN, System.currentTimeMillis()) - } + val values = ContentValues().apply { + put(MediaStore.Images.Media.TITLE, title) + put(MediaStore.Images.Media.DISPLAY_NAME, title) + put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType) + put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis()) + put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) } + val externalContentUri = when { + mediaMimeType?.startsWith("image/") == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI + mediaMimeType?.startsWith("video/") == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI + mediaMimeType?.startsWith("audio/") == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI + } + val uri = context.contentResolver.insert(externalContentUri, values) if (uri == null) { Toast.makeText(context, R.string.error_saving_media_file, Toast.LENGTH_LONG).show() @@ -357,16 +345,70 @@ fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification) } } - // TODO add notification? } else { - @Suppress("DEPRECATION") - Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent -> - mediaScanIntent.data = Uri.fromFile(file) - context.sendBroadcast(mediaScanIntent) + saveMediaLegacy(context, mediaMimeType, title, file) + } +} + +@Suppress("DEPRECATION") +private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: String, file: File) { + val state = Environment.getExternalStorageState() + if (Environment.MEDIA_MOUNTED != state) { + context.toast(context.getString(R.string.error_saving_media_file)) + return + } + + GlobalScope.launch(Dispatchers.IO) { + val dest = when { + mediaMimeType?.startsWith("image/") == true -> Environment.DIRECTORY_PICTURES + mediaMimeType?.startsWith("video/") == true -> Environment.DIRECTORY_MOVIES + mediaMimeType?.startsWith("audio/") == true -> Environment.DIRECTORY_MUSIC + else -> Environment.DIRECTORY_DOWNLOADS + } + val downloadDir = Environment.getExternalStoragePublicDirectory(dest) + try { + val outputFilename = if (title.substringAfterLast('.', "").isEmpty()) { + val extension = mediaMimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) } + "$title.$extension" + } else { + title + } + val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename) + if (savedFile != null) { + val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as? DownloadManager + downloadManager?.addCompletedDownload( + savedFile.name, + title, + true, + mediaMimeType ?: "application/octet-stream", + savedFile.absolutePath, + savedFile.length(), + true) + addToGallery(savedFile, mediaMimeType, context) + } + } catch (error: Throwable) { + GlobalScope.launch(Dispatchers.Main) { + context.toast(context.getString(R.string.error_saving_media_file)) + } } } } +private fun addToGallery(savedFile: File, mediaMimeType: String?, context: Context) { + // MediaScannerConnection provides a way for applications to pass a newly created or downloaded media file to the media scanner service. + var mediaConnection: MediaScannerConnection? = null + val mediaScannerConnectionClient: MediaScannerConnection.MediaScannerConnectionClient = object : MediaScannerConnection.MediaScannerConnectionClient { + override fun onMediaScannerConnected() { + mediaConnection?.scanFile(savedFile.path, mediaMimeType) + } + + override fun onScanCompleted(path: String, uri: Uri?) { + if (path == savedFile.path) mediaConnection?.disconnect() + } + } + mediaConnection = MediaScannerConnection(context, mediaScannerConnectionClient).apply { connect() } +} + /** * Open the play store to the provided application Id, default to this app */ @@ -381,3 +423,76 @@ fun openPlayStore(activity: Activity, appId: String = BuildConfig.APPLICATION_ID } } } + +// ============================================================================================================== +// Media utils +// ============================================================================================================== +/** + * Copy a file into a dstPath directory. + * The output filename can be provided. + * The output file is not overridden if it is already exist. + * + * ~~ This is copied from the old matrix sdk ~~ + * + * @param sourceFile the file source path + * @param dstDirPath the dst path + * @param outputFilename optional the output filename + * @param callback the asynchronous callback + */ +@Suppress("DEPRECATION") +fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?): File? { + // defines another name for the external media + val dstFileName: String + + // build a filename is not provided + if (null == outputFilename) { + // extract the file extension from the uri + val dotPos = sourceFile.name.lastIndexOf(".") + var fileExt = "" + if (dotPos > 0) { + fileExt = sourceFile.name.substring(dotPos) + } + dstFileName = "vector_" + System.currentTimeMillis() + fileExt + } else { + dstFileName = outputFilename + } + + var dstFile = File(dstDirPath, dstFileName) + + // if the file already exists, append a marker + if (dstFile.exists()) { + var baseFileName = dstFileName + var fileExt = "" + val lastDotPos = dstFileName.lastIndexOf(".") + if (lastDotPos > 0) { + baseFileName = dstFileName.substring(0, lastDotPos) + fileExt = dstFileName.substring(lastDotPos) + } + var counter = 1 + while (dstFile.exists()) { + dstFile = File(dstDirPath, "$baseFileName($counter)$fileExt") + counter++ + } + } + + // Copy source file to destination + var inputStream: FileInputStream? = null + var outputStream: FileOutputStream? = null + try { + dstFile.createNewFile() + inputStream = FileInputStream(sourceFile) + outputStream = FileOutputStream(dstFile) + val buffer = ByteArray(1024 * 10) + var len: Int + while (inputStream.read(buffer).also { len = it } != -1) { + outputStream.write(buffer, 0, len) + } + return dstFile + } catch (failure: Throwable) { + return null + } finally { + // Close resources + tryThis { inputStream?.close() } + tryThis { outputStream?.close() } + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 2d7a26efb7..ea5376fd17 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -22,6 +22,7 @@ import android.content.DialogInterface import android.content.Intent import android.graphics.Typeface import android.net.Uri +import android.os.Build import android.os.Bundle import android.os.Parcelable import android.text.Spannable @@ -222,6 +223,7 @@ class RoomDetailFragment @Inject constructor( private const val AUDIO_CALL_PERMISSION_REQUEST_CODE = 1 private const val VIDEO_CALL_PERMISSION_REQUEST_CODE = 2 + private const val SAVE_ATTACHEMENT_REQUEST_CODE = 3 /** * Sanitize the display name. @@ -1194,17 +1196,12 @@ class RoomDetailFragment @Inject constructor( override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { if (allGranted(grantResults)) { when (requestCode) { -// PERMISSION_REQUEST_CODE_DOWNLOAD_FILE -> { -// val action = roomDetailViewModel.pendingAction -// if (action != null) { -// (action as? RoomDetailAction.DownloadFile) -// ?.messageFileContent -// ?.getFileName() -// ?.let { showSnackWithMessage(getString(R.string.downloading_file, it)) } -// roomDetailViewModel.pendingAction = null -// roomDetailViewModel.handle(action) -// } -// } + SAVE_ATTACHEMENT_REQUEST_CODE -> { + sharedActionViewModel.pendingAction?.let { + handleActions(it) + sharedActionViewModel.pendingAction = null + } + } PERMISSION_REQUEST_CODE_INCOMING_URI -> { val pendingUri = roomDetailViewModel.pendingUri if (pendingUri != null) { @@ -1357,6 +1354,11 @@ class RoomDetailFragment @Inject constructor( } private fun onSaveActionClicked(action: EventSharedAction.Save) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && + !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) { + sharedActionViewModel.pendingAction = action + return + } session.fileService().downloadFile( downloadMode = FileService.DownloadMode.FOR_EXTERNAL_SHARE, id = action.eventId, diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt index 2e041fd2ea..ec5c49f814 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt @@ -21,4 +21,6 @@ import javax.inject.Inject /** * Activity shared view model to handle message actions */ -class MessageSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel<EventSharedAction>() +class MessageSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel<EventSharedAction>() { + var pendingAction : EventSharedAction? = null +} From 85ee183e4f7a730e6aafb19613d53666157fbd1c Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Fri, 3 Jul 2020 12:28:32 +0200 Subject: [PATCH 15/28] Update vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt --- .../riotx/features/home/room/detail/RoomDetailFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index ea5376fd17..c941784842 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -1354,7 +1354,7 @@ class RoomDetailFragment @Inject constructor( } private fun onSaveActionClicked(action: EventSharedAction.Save) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) { sharedActionViewModel.pendingAction = action return From c4ad90696f782dcdf2e85c4fa5d125d52fff389c Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Fri, 3 Jul 2020 12:28:38 +0200 Subject: [PATCH 16/28] Update vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt --- .../riotx/features/home/room/detail/RoomDetailFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index c941784842..9d7ea58bb5 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -1355,7 +1355,7 @@ class RoomDetailFragment @Inject constructor( private fun onSaveActionClicked(action: EventSharedAction.Save) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q - !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) { + && !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) { sharedActionViewModel.pendingAction = action return } From e9ba7342d5d3ad5c07136de3bc3160378302b597 Mon Sep 17 00:00:00 2001 From: Tulir Asokan <tulir@maunium.net> Date: Fri, 3 Jul 2020 23:10:44 +0300 Subject: [PATCH 17/28] Fix reply fallback format Signed-off-by: Tulir Asokan <tulir@maunium.net> --- CHANGES.md | 1 + .../session/room/send/LocalEchoEventFactory.kt | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c5cae43f67..9138eb6ad2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ Improvements 🙌: Bugfix 🐛: - Fix crash when coming from a notification (#1601) - Fix Exception when importing keys (#1576) + - Fix reply fallback leaking sender locale (#429) Translations 🗣: - 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 08dc4e80d8..370a81e409 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 @@ -177,7 +177,6 @@ internal class LocalEchoEventFactory @Inject constructor( val body = bodyForReply(originalEvent.getLastMessageContent(), originalEvent.root.getClearContent().toModel()) val replyFormatted = REPLY_PATTERN.format( permalink, - stringProvider.getString(R.string.message_reply_to_prefix), userLink, originalEvent.senderInfo.disambiguatedDisplayName, body.takeFormatted(), @@ -372,7 +371,6 @@ internal class LocalEchoEventFactory @Inject constructor( val body = bodyForReply(eventReplied.getLastMessageContent(), eventReplied.root.getClearContent().toModel()) val replyFormatted = REPLY_PATTERN.format( permalink, - stringProvider.getString(R.string.message_reply_to_prefix), userLink, userId, body.takeFormatted(), @@ -434,10 +432,10 @@ internal class LocalEchoEventFactory @Inject constructor( TextContent(content.body, formattedText) } } - MessageType.MSGTYPE_FILE -> return TextContent(stringProvider.getString(R.string.reply_to_a_file)) - MessageType.MSGTYPE_AUDIO -> return TextContent(stringProvider.getString(R.string.reply_to_an_audio_file)) - MessageType.MSGTYPE_IMAGE -> return TextContent(stringProvider.getString(R.string.reply_to_an_image)) - MessageType.MSGTYPE_VIDEO -> return TextContent(stringProvider.getString(R.string.reply_to_a_video)) + MessageType.MSGTYPE_FILE -> return TextContent("sent a file.") + MessageType.MSGTYPE_AUDIO -> return TextContent("sent an audio file.") + MessageType.MSGTYPE_IMAGE -> return TextContent("sent an image.") + MessageType.MSGTYPE_VIDEO -> return TextContent("sent a video.") else -> return TextContent(content?.body ?: "") } } @@ -489,6 +487,6 @@ internal class LocalEchoEventFactory @Inject constructor( // </blockquote> // </mx-reply> // No whitespace because currently breaks temporary formatted text to Span - const val REPLY_PATTERN = """<mx-reply><blockquote><a href="%s">%s</a><a href="%s">%s</a><br />%s</blockquote></mx-reply>%s""" + const val REPLY_PATTERN = """<mx-reply><blockquote><a href="%s">In reply to</a> <a href="%s">%s</a><br />%s</blockquote></mx-reply>%s""" } } From 51e63c5d1de60eabd1c095214ec1b20038667643 Mon Sep 17 00:00:00 2001 From: Tulir Asokan <tulir@maunium.net> Date: Fri, 3 Jul 2020 23:12:38 +0300 Subject: [PATCH 18/28] Remove unused reply fallback translations Signed-off-by: Tulir Asokan <tulir@maunium.net> --- matrix-sdk-android/src/main/res/values-ar/strings.xml | 6 ------ matrix-sdk-android/src/main/res/values-az/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-bg/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-ca/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-cs/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-de/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-el/strings.xml | 6 ------ matrix-sdk-android/src/main/res/values-eo/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-es-rMX/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-es/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-et/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-eu/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-fa/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-fi/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-fr/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-gl/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-hu/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-is/strings.xml | 1 - matrix-sdk-android/src/main/res/values-it/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-ja/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-ko/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-nl/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-nn/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-pl/strings.xml | 6 ------ matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-ru/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-sk/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-sq/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-uk/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-vls/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml | 7 ------- matrix-sdk-android/src/main/res/values/strings.xml | 7 ------- 33 files changed, 222 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-ar/strings.xml b/matrix-sdk-android/src/main/res/values-ar/strings.xml index ab48ea9934..e9aba1721a 100644 --- a/matrix-sdk-android/src/main/res/values-ar/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ar/strings.xml @@ -63,12 +63,6 @@ <string name="summary_user_sent_sticker">أرسل %1$s ملصقا.</string> <string name="notice_avatar_changed_too">(تغيّرت الصورة أيضا)</string> - <string name="message_reply_to_prefix">ردا على</string> - - <string name="reply_to_an_image">أرسل صورة.</string> - <string name="reply_to_a_video">أرسل فديوهًا.</string> - <string name="reply_to_an_audio_file">أرسل ملف صوت.</string> - <string name="reply_to_a_file">أرسل ملفًا.</string> <string name="room_displayname_invite_from">دعوة من %s</string> <string name="room_displayname_empty_room">غرفة فارغة</string> diff --git a/matrix-sdk-android/src/main/res/values-az/strings.xml b/matrix-sdk-android/src/main/res/values-az/strings.xml index c4347619d0..9c60dfafa7 100644 --- a/matrix-sdk-android/src/main/res/values-az/strings.xml +++ b/matrix-sdk-android/src/main/res/values-az/strings.xml @@ -52,8 +52,6 @@ <string name="notice_crypto_unable_to_decrypt">** Şifrəni aça bilmir: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Göndərənin cihazı bu mesaj üçün açarları bizə göndərməyib.</string> - <string name="message_reply_to_prefix">Cavab olaraq</string> - <string name="could_not_redact">Redaktə etmək olmur</string> <string name="unable_to_send_message">Mesaj göndərmək olmur</string> @@ -69,11 +67,6 @@ <string name="medium_email">Elektron poçt ünvanı</string> <string name="medium_phone_number">Telefon nömrəsi</string> - <string name="reply_to_an_image">şəkil göndərdi.</string> - <string name="reply_to_a_video">video göndərdi.</string> - <string name="reply_to_an_audio_file">səs faylı göndərdi.</string> - <string name="reply_to_a_file">fayl göndərdi.</string> - <string name="room_displayname_invite_from">%s-dən dəvət</string> <string name="room_displayname_room_invite">Otağa dəvət</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 ea53f593fa..07d59852f3 100644 --- a/matrix-sdk-android/src/main/res/values-bg/strings.xml +++ b/matrix-sdk-android/src/main/res/values-bg/strings.xml @@ -63,13 +63,6 @@ <string name="summary_user_sent_sticker">%1$s изпрати стикер.</string> - <string name="message_reply_to_prefix">В отговор на</string> - - <string name="reply_to_an_image">изпрати снимка.</string> - <string name="reply_to_a_video">изпрати видео.</string> - <string name="reply_to_an_audio_file">изпрати аудио файл.</string> - <string name="reply_to_a_file">изпрати файл.</string> - <string name="room_displayname_invite_from">Покана от %s</string> <string name="room_displayname_room_invite">Покана за стая</string> <string name="room_displayname_two_members">%1$s и %2$s</string> diff --git a/matrix-sdk-android/src/main/res/values-ca/strings.xml b/matrix-sdk-android/src/main/res/values-ca/strings.xml index c59ee3b23d..2dc2206c8c 100644 --- a/matrix-sdk-android/src/main/res/values-ca/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ca/strings.xml @@ -76,11 +76,4 @@ <string name="summary_user_sent_sticker">%1$s ha enviat un adhesiu.</string> - <string name="message_reply_to_prefix">En resposta a</string> - - <string name="reply_to_an_image">ha enviat una imatge.</string> - <string name="reply_to_a_video">ha enviat un vídeo.</string> - <string name="reply_to_an_audio_file">ha enviat un fitxer d\'àudio.</string> - <string name="reply_to_a_file">ha enviat un fitxer.</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values-cs/strings.xml b/matrix-sdk-android/src/main/res/values-cs/strings.xml index 7e5081b6e9..44908c38f7 100644 --- a/matrix-sdk-android/src/main/res/values-cs/strings.xml +++ b/matrix-sdk-android/src/main/res/values-cs/strings.xml @@ -46,8 +46,6 @@ <string name="notice_crypto_unable_to_decrypt">** Nelze dešifrovat: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Odesílatelovo zařízení neposlalo klíče pro tuto zprávu.</string> - <string name="message_reply_to_prefix">V odpovědi na</string> - <string name="could_not_redact">Nelze vymazat</string> <string name="unable_to_send_message">Zprávu nelze odeslat</string> @@ -63,11 +61,6 @@ <string name="medium_email">E-mailová adresa</string> <string name="medium_phone_number">Telefonní číslo</string> - <string name="reply_to_an_image">odeslal obrázek.</string> - <string name="reply_to_a_video">odeslal video.</string> - <string name="reply_to_an_audio_file">odeslal zvukový soubor.</string> - <string name="reply_to_a_file">odeslal soubor.</string> - <string name="room_displayname_invite_from">Pozvání od %s</string> <string name="room_displayname_room_invite">Pozvání do místnosti</string> diff --git a/matrix-sdk-android/src/main/res/values-de/strings.xml b/matrix-sdk-android/src/main/res/values-de/strings.xml index d19396d932..94da3369d8 100644 --- a/matrix-sdk-android/src/main/res/values-de/strings.xml +++ b/matrix-sdk-android/src/main/res/values-de/strings.xml @@ -73,13 +73,6 @@ <string name="summary_user_sent_sticker">%1$s sandte einen Sticker.</string> - <string name="message_reply_to_prefix">Als Antwort auf</string> - - <string name="reply_to_an_image">hat ein Bild gesendet.</string> - <string name="reply_to_a_video">hat ein Video gesendet.</string> - <string name="reply_to_an_audio_file">hat eine Audio-Datei gesendet.</string> - <string name="reply_to_a_file">sandte eine Datei.</string> - <!-- Room display name --> <string name="room_displayname_invite_from">Einladung von %s</string> <string name="room_displayname_room_invite">Raumeinladung</string> diff --git a/matrix-sdk-android/src/main/res/values-el/strings.xml b/matrix-sdk-android/src/main/res/values-el/strings.xml index 37eac5351e..9db4e91849 100644 --- a/matrix-sdk-android/src/main/res/values-el/strings.xml +++ b/matrix-sdk-android/src/main/res/values-el/strings.xml @@ -40,8 +40,6 @@ <string name="notice_crypto_unable_to_decrypt">** Αδυναμία αποκρυπτογράφησης: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Η συσκευή του/της αποστολέα δεν μας έχει στείλει τα κλειδιά για αυτό το μήνυμα.</string> - <string name="message_reply_to_prefix">Προς απάντηση στο</string> - <string name="unable_to_send_message">Αποτυχία αποστολής μηνύματος</string> <string name="message_failed_to_upload">Αποτυχία αναφόρτωσης εικόνας</string> @@ -56,10 +54,6 @@ <string name="notice_voip_finished">Η VoIP διάσκεψη έληξε</string> <string name="notice_room_join">Ο/Η %1$s εισήλθε στο δωμάτιο</string> - <string name="reply_to_an_image">έστειλε μία εικόνα.</string> - <string name="reply_to_a_video">έστειλε ένα βίντεο.</string> - <string name="reply_to_an_audio_file">έστειλε ένα αρχείο ήχου.</string> - <string name="reply_to_a_file">έστειλε ένα αρχείο.</string> <string name="room_displayname_invite_from">Πρόσκληση από %s</string> <string name="room_displayname_room_invite">Πρόσκληση στο δωμάτιο</string> diff --git a/matrix-sdk-android/src/main/res/values-eo/strings.xml b/matrix-sdk-android/src/main/res/values-eo/strings.xml index 69600394ac..4a1e2c4c65 100644 --- a/matrix-sdk-android/src/main/res/values-eo/strings.xml +++ b/matrix-sdk-android/src/main/res/values-eo/strings.xml @@ -17,8 +17,6 @@ <string name="notice_crypto_unable_to_decrypt">** Ne eblas malĉifri: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">La aparato de la sendanto ne sendis al ni la ŝlosilojn por tiu mesaĝo.</string> - <string name="message_reply_to_prefix">Responde al</string> - <string name="summary_message">%1$s: %2$s</string> <string name="notice_display_name_set">%1$s ŝanĝis sian vidigan nomon al %2$s</string> <string name="notice_display_name_changed_from">%1$s ŝanĝis sian vidigan nomon de %2$s al %3$s</string> @@ -62,11 +60,6 @@ <string name="medium_email">Retpoŝtadreso</string> <string name="medium_phone_number">Telefonnumero</string> - <string name="reply_to_an_image">sendis bildon.</string> - <string name="reply_to_a_video">sendis filmon.</string> - <string name="reply_to_an_audio_file">sendis sondosieron.</string> - <string name="reply_to_a_file">sendis dosieron.</string> - <string name="room_displayname_invite_from">Invito de %s</string> <string name="room_displayname_room_invite">Ĉambra invito</string> diff --git a/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml b/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml index 56cbe6ace5..35b7bfc829 100644 --- a/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml @@ -73,13 +73,6 @@ <string name="summary_user_sent_sticker">%1$s envió una calcomanía.</string> - <string name="message_reply_to_prefix">En respuesta a</string> - - <string name="reply_to_an_image">envió una imagen.</string> - <string name="reply_to_a_video">envió un video.</string> - <string name="reply_to_an_audio_file">envió un archivo de audio.</string> - <string name="reply_to_a_file">envió un archivo.</string> - <!-- Room display name --> <string name="room_displayname_invite_from">Invitación de %s</string> <string name="room_displayname_room_invite">Invitación de Sala</string> diff --git a/matrix-sdk-android/src/main/res/values-es/strings.xml b/matrix-sdk-android/src/main/res/values-es/strings.xml index 69f02d2ef4..3c019b3b80 100644 --- a/matrix-sdk-android/src/main/res/values-es/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es/strings.xml @@ -73,13 +73,6 @@ <string name="summary_user_sent_sticker">%1$s envió una pegatina.</string> - <string name="message_reply_to_prefix">En respuesta a</string> - - <string name="reply_to_an_image">envió una imagen.</string> - <string name="reply_to_a_video">envió un vídeo.</string> - <string name="reply_to_an_audio_file">envió un archivo de audio.</string> - <string name="reply_to_a_file">envió un archivo.</string> - <!-- Room display name --> <string name="room_displayname_invite_from">Invitación de %s</string> <string name="room_displayname_room_invite">Invitación a Sala</string> diff --git a/matrix-sdk-android/src/main/res/values-et/strings.xml b/matrix-sdk-android/src/main/res/values-et/strings.xml index 3a5a1ff767..2536500247 100644 --- a/matrix-sdk-android/src/main/res/values-et/strings.xml +++ b/matrix-sdk-android/src/main/res/values-et/strings.xml @@ -50,8 +50,6 @@ <string name="notice_crypto_unable_to_decrypt">** Ei õnnestu dekrüptida: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Sõnumi saatja seade ei ole selle sõnumi jaoks saatnud dekrüptimisvõtmeid.</string> - <string name="message_reply_to_prefix">Vastuseks kasutajale</string> - <string name="could_not_redact">Ei saanud muuta sõnumit</string> <string name="unable_to_send_message">Sõnumi saatmine ei õnnestunud</string> @@ -67,11 +65,6 @@ <string name="medium_email">E-posti aadress</string> <string name="medium_phone_number">Telefoninumber</string> - <string name="reply_to_an_image">saatis pildi.</string> - <string name="reply_to_a_video">saatis video.</string> - <string name="reply_to_an_audio_file">saatis helifaili.</string> - <string name="reply_to_a_file">saatis faili.</string> - <string name="room_displayname_invite_from">Kutse kasutajalt %s</string> <string name="room_displayname_room_invite">Kutse jututuppa</string> diff --git a/matrix-sdk-android/src/main/res/values-eu/strings.xml b/matrix-sdk-android/src/main/res/values-eu/strings.xml index 7938db3cbd..1a5c81fe5e 100644 --- a/matrix-sdk-android/src/main/res/values-eu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-eu/strings.xml @@ -63,13 +63,6 @@ <string name="summary_user_sent_sticker">%1$s erabiltzaileak eranskailu bat bidali du.</string> - <string name="message_reply_to_prefix">Honi erantzunez</string> - - <string name="reply_to_an_image">irudi bat bidali du.</string> - <string name="reply_to_a_video">bideo bat bidali du.</string> - <string name="reply_to_an_audio_file">audio fitxategi bat bidali du.</string> - <string name="reply_to_a_file">fitxategi bat bidali du.</string> - <string name="room_displayname_invite_from">%s gelarako gonbidapena</string> <string name="room_displayname_room_invite">Gela gonbidapena</string> <string name="room_displayname_two_members">%1$s eta %2$s</string> diff --git a/matrix-sdk-android/src/main/res/values-fa/strings.xml b/matrix-sdk-android/src/main/res/values-fa/strings.xml index 7addf22ca8..18d8578e54 100644 --- a/matrix-sdk-android/src/main/res/values-fa/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fa/strings.xml @@ -51,8 +51,6 @@ <string name="notice_crypto_unable_to_decrypt">** ناتوان در رمزگشایی: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">دستگاه فرستنده، کلیدهای این پیام را برایمان نفرستاده است.</string> - <string name="message_reply_to_prefix">در پاسخ به</string> - <string name="unable_to_send_message">ناتوان در فرستادن پیام</string> <string name="message_failed_to_upload">شکست در بارگذاری تصویر</string> @@ -67,11 +65,6 @@ <string name="medium_email">نشانی رایانامه</string> <string name="medium_phone_number">شماره تلفن</string> - <string name="reply_to_an_image">تصویری فرستاد.</string> - <string name="reply_to_a_video">ویدیویی فرستاد.</string> - <string name="reply_to_an_audio_file">پروندهای صوتی فرستاد.</string> - <string name="reply_to_a_file">پروندهای فرستاد.</string> - <string name="room_displayname_invite_from">دعوت از %s</string> <string name="room_displayname_room_invite">دعوت اتاق</string> diff --git a/matrix-sdk-android/src/main/res/values-fi/strings.xml b/matrix-sdk-android/src/main/res/values-fi/strings.xml index 06820183fd..078769942c 100644 --- a/matrix-sdk-android/src/main/res/values-fi/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fi/strings.xml @@ -70,13 +70,6 @@ <string name="summary_user_sent_sticker">%1$s lähetti tarran.</string> - <string name="message_reply_to_prefix">Vastauksena käyttäjälle</string> - - <string name="reply_to_an_image">oli lähettänyt kuvan.</string> - <string name="reply_to_a_video">lähetti videon.</string> - <string name="reply_to_an_audio_file">lähetti äänitiedoston.</string> - <string name="reply_to_a_file">lähetti tiedoston.</string> - <plurals name="room_displayname_three_and_more_members"> <item quantity="one">%1$s ja yksi muu</item> <item quantity="other">%1$s ja %2$d muuta</item> diff --git a/matrix-sdk-android/src/main/res/values-fr/strings.xml b/matrix-sdk-android/src/main/res/values-fr/strings.xml index a744c35b99..aad3bd1afb 100644 --- a/matrix-sdk-android/src/main/res/values-fr/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fr/strings.xml @@ -63,13 +63,6 @@ <string name="summary_user_sent_sticker">%1$s a envoyé un sticker.</string> - <string name="message_reply_to_prefix">En réponse à</string> - - <string name="reply_to_an_image">a envoyé une image.</string> - <string name="reply_to_a_video">a envoyé une vidéo.</string> - <string name="reply_to_an_audio_file">a envoyé un fichier audio.</string> - <string name="reply_to_a_file">a envoyé un fichier.</string> - <string name="room_displayname_invite_from">Invitation de %s</string> <string name="room_displayname_room_invite">Invitation au salon</string> <string name="room_displayname_empty_room">Salon vide</string> diff --git a/matrix-sdk-android/src/main/res/values-gl/strings.xml b/matrix-sdk-android/src/main/res/values-gl/strings.xml index 907730f154..77868e7df3 100644 --- a/matrix-sdk-android/src/main/res/values-gl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-gl/strings.xml @@ -50,8 +50,6 @@ <string name="notice_crypto_unable_to_decrypt">** Imposíbel descifrar: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">O dispositivo do que envía non enviou as chaves desta mensaxe.</string> - <string name="message_reply_to_prefix">Respondéndolle a</string> - <string name="could_not_redact">Non se puido redactar</string> <string name="unable_to_send_message">Non foi posíbel enviar a mensaxe</string> @@ -64,11 +62,6 @@ <string name="medium_phone_number">Número de teléfono</string> - <string name="reply_to_an_image">Responder a</string> - <string name="reply_to_a_video">enviar un vídeo.</string> - <string name="reply_to_an_audio_file">enviar un ficheiro de son.</string> - <string name="reply_to_a_file">enviar un ficheiro.</string> - <string name="room_displayname_two_members">%1$s e %2$s</string> diff --git a/matrix-sdk-android/src/main/res/values-hu/strings.xml b/matrix-sdk-android/src/main/res/values-hu/strings.xml index 03d52bef44..35f35eaecd 100644 --- a/matrix-sdk-android/src/main/res/values-hu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-hu/strings.xml @@ -62,13 +62,6 @@ <string name="summary_user_sent_sticker">%1$s küldött egy matricát.</string> - <string name="message_reply_to_prefix">Válasz erre:</string> - - <string name="reply_to_an_image">képet küldött.</string> - <string name="reply_to_a_video">videót küldött.</string> - <string name="reply_to_an_audio_file">hangfájlt küldött.</string> - <string name="reply_to_a_file">fájlt küldött.</string> - <string name="room_displayname_invite_from">Meghívó tőle: %s</string> <string name="room_displayname_room_invite">Meghívó egy szobába</string> <string name="room_displayname_two_members">%1$s és %2$s</string> diff --git a/matrix-sdk-android/src/main/res/values-is/strings.xml b/matrix-sdk-android/src/main/res/values-is/strings.xml index 01954ae2b4..ecf19edb8a 100644 --- a/matrix-sdk-android/src/main/res/values-is/strings.xml +++ b/matrix-sdk-android/src/main/res/values-is/strings.xml @@ -24,7 +24,6 @@ <string name="notice_avatar_changed_too">(einnig var skipt um auðkennismynd)</string> <string name="notice_crypto_unable_to_decrypt">** Mistókst að afkóða: %s **</string> - <string name="message_reply_to_prefix">Sem svar til</string> <string name="unable_to_send_message">Gat ekki sent skilaboð</string> diff --git a/matrix-sdk-android/src/main/res/values-it/strings.xml b/matrix-sdk-android/src/main/res/values-it/strings.xml index ec86122313..42328b836f 100644 --- a/matrix-sdk-android/src/main/res/values-it/strings.xml +++ b/matrix-sdk-android/src/main/res/values-it/strings.xml @@ -62,13 +62,6 @@ <string name="summary_user_sent_sticker">%1$s ha inviato un adesivo.</string> - <string name="message_reply_to_prefix">In risposta a</string> - - <string name="reply_to_an_image">inviata un\'immagine.</string> - <string name="reply_to_a_video">inviato un video.</string> - <string name="reply_to_an_audio_file">inviato un file audio.</string> - <string name="reply_to_a_file">inviato un file.</string> - <!-- Room display name --> <string name="room_displayname_invite_from">Invito da %s</string> <string name="room_displayname_room_invite">Invito nella stanza</string> diff --git a/matrix-sdk-android/src/main/res/values-ja/strings.xml b/matrix-sdk-android/src/main/res/values-ja/strings.xml index b72d1a13ca..366c743494 100644 --- a/matrix-sdk-android/src/main/res/values-ja/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ja/strings.xml @@ -56,8 +56,6 @@ <string name="notice_crypto_unable_to_decrypt">** 解読できません: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">送信者の端末からこのメッセージのキーが送信されていません。</string> - <string name="message_reply_to_prefix">に返信</string> - <string name="could_not_redact">修正できませんでした</string> <string name="unable_to_send_message">メッセージを送信できません</string> @@ -73,9 +71,4 @@ <string name="medium_email">メールアドレス</string> <string name="medium_phone_number">電話番号</string> - <string name="reply_to_an_image">画像を送信しました。</string> - <string name="reply_to_a_video">動画を送りました。</string> - <string name="reply_to_an_audio_file">音声ファイルを送信しました。</string> - <string name="reply_to_a_file">ファイルを送信しました。</string> - </resources> 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 68e94bb641..88c5e7d618 100644 --- a/matrix-sdk-android/src/main/res/values-ko/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ko/strings.xml @@ -52,8 +52,6 @@ <string name="notice_crypto_unable_to_decrypt">** 암호를 복호화할 수 없음: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">발신인의 기기에서 이 메시지의 키를 보내지 않았습니다.</string> - <string name="message_reply_to_prefix">관련 대화</string> - <string name="could_not_redact">검열할 수 없습니다</string> <string name="unable_to_send_message">메시지를 보낼 수 없습니다</string> @@ -69,11 +67,6 @@ <string name="medium_email">이메일 주소</string> <string name="medium_phone_number">전화번호</string> - <string name="reply_to_an_image">사진을 보냈습니다.</string> - <string name="reply_to_a_video">동영상을 보냈습니다.</string> - <string name="reply_to_an_audio_file">오디오 파일을 보냈습니다.</string> - <string name="reply_to_a_file">파일을 보냈습니다.</string> - <string name="room_displayname_invite_from">%s에서 초대함</string> <string name="room_displayname_room_invite">방 초대</string> diff --git a/matrix-sdk-android/src/main/res/values-nl/strings.xml b/matrix-sdk-android/src/main/res/values-nl/strings.xml index d08b3c7845..22eb61f109 100644 --- a/matrix-sdk-android/src/main/res/values-nl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-nl/strings.xml @@ -71,13 +71,6 @@ <string name="summary_user_sent_sticker">%1$s heeft een sticker gestuurd.</string> - <string name="message_reply_to_prefix">Als antwoord op</string> - - <string name="reply_to_an_image">heeft een afbeelding gestuurd.</string> - <string name="reply_to_a_video">heeft een video gestuurd.</string> - <string name="reply_to_an_audio_file">heeft een audiobestand gestuurd.</string> - <string name="reply_to_a_file">heeft een bestand gestuurd.</string> - <!-- Room display name --> <string name="room_displayname_invite_from">Uitnodiging van %s</string> <string name="room_displayname_room_invite">Gespreksuitnodiging</string> diff --git a/matrix-sdk-android/src/main/res/values-nn/strings.xml b/matrix-sdk-android/src/main/res/values-nn/strings.xml index edc50a5a0e..601cf4c9df 100644 --- a/matrix-sdk-android/src/main/res/values-nn/strings.xml +++ b/matrix-sdk-android/src/main/res/values-nn/strings.xml @@ -49,8 +49,6 @@ <string name="notice_crypto_unable_to_decrypt">** Fekk ikkje til å dekryptera: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Avsendareiningi hev ikkje sendt oss nyklane fyr denna meldingi.</string> - <string name="message_reply_to_prefix">Som svar til</string> - <string name="could_not_redact">Kunde ikkje gjera um</string> <string name="unable_to_send_message">Fekk ikkje å senda meldingi</string> @@ -64,11 +62,6 @@ <string name="medium_email">Epostadresse</string> <string name="medium_phone_number">Telefonnummer</string> - <string name="reply_to_an_image">sende eit bilæte.</string> - <string name="reply_to_a_video">sende ein video.</string> - <string name="reply_to_an_audio_file">sende ei ljodfil.</string> - <string name="reply_to_a_file">sende ei fil.</string> - <string name="room_displayname_invite_from">Innbjoding frå %s</string> <string name="room_displayname_room_invite">Rominnbjoding</string> <string name="room_displayname_two_members">%1$s og %2$s</string> diff --git a/matrix-sdk-android/src/main/res/values-pl/strings.xml b/matrix-sdk-android/src/main/res/values-pl/strings.xml index 4e1d256788..dc380516b7 100644 --- a/matrix-sdk-android/src/main/res/values-pl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-pl/strings.xml @@ -42,7 +42,6 @@ <string name="notice_room_withdraw">%1$s wycofał(a) zaproszenie %2$s</string> <string name="notice_answered_call">%s odebrał(a) połączenie.</string> <string name="notice_avatar_changed_too">(awatar też został zmieniony)</string> - <string name="message_reply_to_prefix">W odpowiedzi do</string> <string name="room_displayname_invite_from">Zaproszenie od %s</string> <string name="room_displayname_room_invite">Zaproszenie do pokoju</string> @@ -76,11 +75,6 @@ <string name="could_not_redact">Nie można zredagować</string> <string name="room_error_join_failed_empty_room">Obecnie nie jest możliwe ponowne dołączenie do pustego pokoju.</string> - <string name="reply_to_an_image">wyślij zdjęcie.</string> - <string name="reply_to_a_video">wyślij wideo.</string> - <string name="reply_to_an_audio_file">wyślij plik audio.</string> - <string name="reply_to_a_file">wyślij plik.</string> - <string name="notice_event_redacted">Wiadomość usunięta</string> <string name="notice_event_redacted_by">Wiadomość usunięta przez %1$s</string> <string name="notice_event_redacted_with_reason">Wiadomość usunięta [powód: %1$s]</string> diff --git a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml index 17e7ae33a1..a573c659a6 100644 --- a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml +++ b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml @@ -74,13 +74,6 @@ <string name="summary_user_sent_sticker">%1$s enviou um sticker.</string> - <string name="message_reply_to_prefix">Em resposta a</string> - - <string name="reply_to_an_image">enviou uma imagem.</string> - <string name="reply_to_a_video">enviou um vídeo.</string> - <string name="reply_to_an_audio_file">enviou um arquivo de áudio.</string> - <string name="reply_to_a_file">enviou um arquivo.</string> - <!-- Room display name --> <string name="room_displayname_invite_from">Convite de %s</string> <string name="room_displayname_room_invite">Convite para sala</string> diff --git a/matrix-sdk-android/src/main/res/values-ru/strings.xml b/matrix-sdk-android/src/main/res/values-ru/strings.xml index 3e20353b7d..bd0dcef3dd 100644 --- a/matrix-sdk-android/src/main/res/values-ru/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ru/strings.xml @@ -73,13 +73,6 @@ <string name="summary_user_sent_sticker">%1$s отправил стикер.</string> - <string name="message_reply_to_prefix">В ответ на</string> - - <string name="reply_to_an_image">отправил изображение.</string> - <string name="reply_to_a_video">отправил видео.</string> - <string name="reply_to_an_audio_file">отправил аудиофайл.</string> - <string name="reply_to_a_file">отправил файл.</string> - <!-- Room display name --> <string name="room_displayname_invite_from">Приглашение от %s</string> <string name="room_displayname_room_invite">Приглашение в комнату</string> diff --git a/matrix-sdk-android/src/main/res/values-sk/strings.xml b/matrix-sdk-android/src/main/res/values-sk/strings.xml index c6eb6b896b..8aec8fccf9 100644 --- a/matrix-sdk-android/src/main/res/values-sk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sk/strings.xml @@ -62,13 +62,6 @@ <string name="summary_user_sent_sticker">%1$s poslal nálepku.</string> - <string name="message_reply_to_prefix">Odpoveď na</string> - - <string name="reply_to_an_image">odoslal obrázok.</string> - <string name="reply_to_a_video">odoslal video.</string> - <string name="reply_to_an_audio_file">odoslal zvukový súbor.</string> - <string name="reply_to_a_file">Odoslal súbor.</string> - <string name="room_displayname_invite_from">Pozvanie od %s</string> <string name="room_displayname_room_invite">Pozvanie do miestnosti</string> <string name="room_displayname_two_members">%1$s a %2$s</string> diff --git a/matrix-sdk-android/src/main/res/values-sq/strings.xml b/matrix-sdk-android/src/main/res/values-sq/strings.xml index 853d4729af..e63e28288f 100644 --- a/matrix-sdk-android/src/main/res/values-sq/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sq/strings.xml @@ -34,8 +34,6 @@ <string name="notice_crypto_unable_to_decrypt">** S’arrihet të shfshehtëzohet: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Pajisja e dërguesit nuk na ka dërguar kyçet për këtë mesazh.</string> - <string name="message_reply_to_prefix">Në përgjigje të</string> - <string name="could_not_redact">S’u redaktua dot</string> <string name="unable_to_send_message">S’arrihet të dërgohet mesazh</string> @@ -51,11 +49,6 @@ <string name="medium_email">Adresë email</string> <string name="medium_phone_number">Numër telefoni</string> - <string name="reply_to_an_image">dërgoi një figurë.</string> - <string name="reply_to_a_video">dërgoi një video.</string> - <string name="reply_to_an_audio_file">dërgoi një kartelë audio.</string> - <string name="reply_to_a_file">dërgoi një kartelë.</string> - <string name="room_displayname_invite_from">Ftesë nga %s</string> <string name="room_displayname_room_invite">Ftesë Dhome</string> diff --git a/matrix-sdk-android/src/main/res/values-uk/strings.xml b/matrix-sdk-android/src/main/res/values-uk/strings.xml index bf83e39d72..eb5071f190 100644 --- a/matrix-sdk-android/src/main/res/values-uk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-uk/strings.xml @@ -56,8 +56,6 @@ <string name="notice_crypto_unable_to_decrypt">** Неможливо розшифрувати: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Пристрій відправника не надіслав нам ключ для цього повідомлення.</string> - <string name="message_reply_to_prefix">У відповідь на</string> - <string name="could_not_redact">Неможливо відредагувати</string> <string name="unable_to_send_message">Не вдалося надіслати повідомлення</string> @@ -71,11 +69,6 @@ <string name="medium_email">Адреса електронної пошти</string> <string name="medium_phone_number">Номер телефону</string> - <string name="reply_to_an_image">надіслав зображення.</string> - <string name="reply_to_a_video">надіслав відео.</string> - <string name="reply_to_an_audio_file">надіслав аудіо файл.</string> - <string name="reply_to_a_file">надіслав файл.</string> - <plurals name="room_displayname_three_and_more_members"> <item quantity="one">%1$s та 1 інший</item> <item quantity="few">%1$s та %2$d інші</item> diff --git a/matrix-sdk-android/src/main/res/values-vls/strings.xml b/matrix-sdk-android/src/main/res/values-vls/strings.xml index dad88788e4..5c9132ed35 100644 --- a/matrix-sdk-android/src/main/res/values-vls/strings.xml +++ b/matrix-sdk-android/src/main/res/values-vls/strings.xml @@ -50,8 +50,6 @@ <string name="notice_crypto_unable_to_decrypt">** Kun nie ountsleuteln: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">’t Toestel van den afzender èt geen sleutels vo da bericht hier gesteurd.</string> - <string name="message_reply_to_prefix">Als antwoord ip</string> - <string name="could_not_redact">Kosteg nie verwyderd wordn</string> <string name="unable_to_send_message">Kosteg ’t bericht nie verzendn</string> @@ -67,11 +65,6 @@ <string name="medium_email">E-mailadresse</string> <string name="medium_phone_number">Telefongnumero</string> - <string name="reply_to_an_image">èt e fotootje gesteurd.</string> - <string name="reply_to_a_video">èt e filmtje gesteurd.</string> - <string name="reply_to_an_audio_file">èt e geluudsfragment gesteurd.</string> - <string name="reply_to_a_file">èt e bestand gesteurd.</string> - <string name="room_displayname_invite_from">Uutnodigienge van %s</string> <string name="room_displayname_room_invite">Gespreksuutnodigienge</string> diff --git a/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml index 0c0953c92d..48dbd27a1b 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml @@ -63,13 +63,6 @@ <string name="summary_message">%1$s:%2$s</string> <string name="summary_user_sent_sticker">%1$s 发送了一张贴纸。</string> - <string name="reply_to_an_image">发送了一张图片。</string> - <string name="reply_to_a_video">发送了一个视频。</string> - <string name="reply_to_an_audio_file">发送了一段音频。</string> - <string name="reply_to_a_file">发送了一个文件。</string> - - <string name="message_reply_to_prefix">回复</string> - <string name="room_displayname_empty_room">空聊天室</string> <string name="room_displayname_invite_from">来自 %s 的邀请</string> <string name="room_displayname_room_invite">聊天室邀请</string> diff --git a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml index ca2fd79aa2..f3da62dccc 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml @@ -62,13 +62,6 @@ <string name="summary_user_sent_sticker">%1$s 傳送了一張貼圖。</string> - <string name="message_reply_to_prefix">回覆</string> - - <string name="reply_to_an_image">傳送了圖片。</string> - <string name="reply_to_a_video">傳送了影片。</string> - <string name="reply_to_an_audio_file">傳送了音訊檔案。</string> - <string name="reply_to_a_file">傳送了檔案。</string> - <string name="room_displayname_invite_from">來自%s 的邀請</string> <string name="room_displayname_room_invite">聊天室邀請</string> <string name="room_displayname_two_members">%1$s 和 %2$s</string> diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml index 9b7fa01eaf..0dc64c1b4b 100644 --- a/matrix-sdk-android/src/main/res/values/strings.xml +++ b/matrix-sdk-android/src/main/res/values/strings.xml @@ -112,7 +112,6 @@ <string name="notice_crypto_error_unkwown_inbound_session_id">The sender\'s device has not sent us the keys for this message.</string> <!-- Messages --> - <string name="message_reply_to_prefix">In reply to</string> <!-- Room Screen --> <string name="could_not_redact">Could not redact</string> @@ -139,12 +138,6 @@ <string name="medium_email">Email address</string> <string name="medium_phone_number">Phone number</string> - <!-- Reply to --> - <string name="reply_to_an_image">sent an image.</string> - <string name="reply_to_a_video">sent a video.</string> - <string name="reply_to_an_audio_file">sent an audio file.</string> - <string name="reply_to_a_file">sent a file.</string> - <!-- Room display name --> <string name="room_displayname_invite_from">Invite from %s</string> <string name="room_displayname_room_invite">Room Invite</string> From 0cfd33fc8b8133a24c17e1f748ab5f33cd4467ee Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Sat, 4 Jul 2020 11:15:20 +0200 Subject: [PATCH 19/28] Typo --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index c5cae43f67..3fa394c97b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,7 +18,7 @@ SDK API changes ⚠️: - Build 🧱: - - Fix lint false-positive about WorkManger (#1012) + - Fix lint false-positive about WorkManager (#1012) - Upgrade build-tools from 3.5.3 to 3.6.6 - Upgrade gradle from 5.4.1 to 5.6.4 From b853397c0a21808bb9259c2755bbefb77c99c0d0 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Sat, 4 Jul 2020 12:10:17 +0200 Subject: [PATCH 20/28] Re-activate Wellknown support with updated UI (#1614) --- CHANGES.md | 2 +- .../riotx/features/login/LoginFragment.kt | 3 +++ vector/src/main/res/layout/fragment_login.xml | 10 ++++++++++ .../fragment_login_server_selection.xml | 20 ++++--------------- vector/src/main/res/values/strings.xml | 9 +++++---- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 3fa394c97b..a6bb5d6a29 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ Changes in Riot.imX 0.91.4 (2020-XX-XX) =================================================== Features ✨: - - + - Re-activate Wellknown support with updated UI (#1614) Improvements 🙌: - diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt index eaf0a3cc78..28c2299faa 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt @@ -54,6 +54,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { private var passwordShown = false private var isSignupMode = false + // Temporary patch for https://github.com/vector-im/riotX-android/issues/1410, // waiting for https://github.com/matrix-org/synapse/issues/7576 private var isNumericOnlyUserIdForbidden = false @@ -138,6 +139,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { loginServerIcon.isVisible = false loginTitle.text = getString(R.string.login_signin_matrix_id_title) loginNotice.text = getString(R.string.login_signin_matrix_id_notice) + loginPasswordNotice.isVisible = true } else { val resId = when (state.signMode) { SignMode.Unknown -> error("developer error") @@ -165,6 +167,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { loginNotice.text = getString(R.string.login_server_other_text) } } + loginPasswordNotice.isVisible = false } } diff --git a/vector/src/main/res/layout/fragment_login.xml b/vector/src/main/res/layout/fragment_login.xml index a35a60104d..8e7fc9e418 100644 --- a/vector/src/main/res/layout/fragment_login.xml +++ b/vector/src/main/res/layout/fragment_login.xml @@ -106,6 +106,16 @@ </FrameLayout> + <TextView + android:id="@+id/loginPasswordNotice" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="start" + android:text="@string/login_signin_matrix_id_password_notice" + android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small" + android:visibility="gone" + tools:visibility="visible" /> + <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/vector/src/main/res/layout/fragment_login_server_selection.xml b/vector/src/main/res/layout/fragment_login_server_selection.xml index f634456935..16465486a2 100644 --- a/vector/src/main/res/layout/fragment_login_server_selection.xml +++ b/vector/src/main/res/layout/fragment_login_server_selection.xml @@ -188,35 +188,23 @@ android:layout_marginTop="24dp" android:text="@string/login_continue" android:transitionName="loginSubmitTransition" - app:layout_constraintBottom_toTopOf="@+id/loginServerIKnowMyIdNotice" + app:layout_constraintBottom_toTopOf="@+id/loginServerIKnowMyIdSubmit" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOther" /> - <TextView - android:id="@+id/loginServerIKnowMyIdNotice" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="24dp" - android:gravity="start" - android:text="@string/login_connect_using_matrix_id_notice" - android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small" - android:visibility="gone" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/loginServerSubmit" /> - <com.google.android.material.button.MaterialButton android:id="@+id/loginServerIKnowMyIdSubmit" style="@style/Style.Vector.Login.Button.Text" android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginTop="32dp" + android:layout_marginBottom="32dp" android:text="@string/login_connect_using_matrix_id_submit" - android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/loginServerIKnowMyIdNotice" /> + app:layout_constraintTop_toBottomOf="@+id/loginServerSubmit" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index d8aad6f539..c3f0e9df41 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1995,10 +1995,11 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming </plurals> <string name="login_connect_using_matrix_id_notice">Alternatively, if you already have an account and you know your Matrix identifier and your password, you can use this method:</string> - <string name="login_connect_using_matrix_id_submit">Sign in with my Matrix identifier</string> - <string name="login_signin_matrix_id_title">Sign in</string> - <string name="login_signin_matrix_id_notice">Enter your identifier and your password</string> - <string name="login_signin_matrix_id_hint">User identifier</string> + <string name="login_connect_using_matrix_id_submit">Sign in with Matrix ID</string> + <string name="login_signin_matrix_id_title">Sign in with Matrix ID</string> + <string name="login_signin_matrix_id_notice">If you set up an account on a homeserver, use your Matrix ID (e.g. @user:domain.com) and password below.</string> + <string name="login_signin_matrix_id_hint">Matrix ID</string> + <string name="login_signin_matrix_id_password_notice">If you don’t know your password, go back to reset it.</string> <string name="login_signin_matrix_id_error_invalid_matrix_id">This is not a valid user identifier. Expected format: \'@user:homeserver.org\'</string> <string name="autodiscover_well_known_error">Unable to find a valid homeserver. Please check your identifier</string> From 2a68c8d08be9233b6625ce37f75a9ae6b0e74ed2 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Mon, 6 Jul 2020 10:49:03 +0200 Subject: [PATCH 21/28] Simplify the server selection screen: remove the "Continue" button --- .../riotx/features/login/LoginActivity.kt | 1 + .../riotx/features/login/LoginFragment.kt | 1 + .../login/LoginServerSelectionFragment.kt | 38 ++----------------- .../LoginSignUpSignInSelectionFragment.kt | 1 + .../riotx/features/login/LoginViewModel.kt | 15 +++++++- .../riotx/features/login/LoginViewState.kt | 2 +- .../vector/riotx/features/login/ServerType.kt | 1 + .../res/drawable/bg_login_server_selector.xml | 1 + .../fragment_login_server_selection.xml | 24 +++--------- 9 files changed, 29 insertions(+), 55 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt index 86be00702c..1eebf532e7 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt @@ -235,6 +235,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable { ServerType.Other -> addFragmentToBackstack(R.id.loginFragmentContainer, LoginServerUrlFormFragment::class.java, option = commonOption) + ServerType.Unknown -> Unit /* Should not happen */ } } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt index 28c2299faa..ef8281fa89 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt @@ -166,6 +166,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { loginTitle.text = getString(resId, state.homeServerUrl.toReducedUrl()) loginNotice.text = getString(R.string.login_server_other_text) } + ServerType.Unknown -> Unit /* Should not happen */ } loginPasswordNotice.isVisible = false } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt index 79c5c7d024..3a1bba7f11 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt @@ -19,7 +19,6 @@ package im.vector.riotx.features.login import android.os.Bundle import android.view.View import butterknife.OnClick -import com.airbnb.mvrx.withState import im.vector.riotx.R import im.vector.riotx.core.utils.openUrlInChromeCustomTab import kotlinx.android.synthetic.main.fragment_login_server_selection.* @@ -40,11 +39,7 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment } private fun updateSelectedChoice(state: LoginViewState) { - state.serverType.let { - loginServerChoiceMatrixOrg.isChecked = it == ServerType.MatrixOrg - loginServerChoiceModular.isChecked = it == ServerType.Modular - loginServerChoiceOther.isChecked = it == ServerType.Other - } + loginServerChoiceMatrixOrg.isChecked = state.serverType == ServerType.MatrixOrg } private fun initTextViews() { @@ -61,42 +56,17 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment @OnClick(R.id.loginServerChoiceMatrixOrg) fun selectMatrixOrg() { - if (loginServerChoiceMatrixOrg.isChecked) { - // Consider this is a submit - submit() - } else { - loginViewModel.handle(LoginAction.UpdateServerType(ServerType.MatrixOrg)) - } + loginViewModel.handle(LoginAction.UpdateServerType(ServerType.MatrixOrg)) } @OnClick(R.id.loginServerChoiceModular) fun selectModular() { - if (loginServerChoiceModular.isChecked) { - // Consider this is a submit - submit() - } else { - loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Modular)) - } + loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Modular)) } @OnClick(R.id.loginServerChoiceOther) fun selectOther() { - if (loginServerChoiceOther.isChecked) { - // Consider this is a submit - submit() - } else { - loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Other)) - } - } - - @OnClick(R.id.loginServerSubmit) - fun submit() = withState(loginViewModel) { state -> - if (state.serverType == ServerType.MatrixOrg) { - // Request login flow here - loginViewModel.handle(LoginAction.UpdateHomeServer(getString(R.string.matrix_org_server_url))) - } else { - loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnServerSelectionDone)) - } + loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Other)) } @OnClick(R.id.loginServerIKnowMyIdSubmit) diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginSignUpSignInSelectionFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginSignUpSignInSelectionFragment.kt index 427ad99b41..6ac5993f30 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginSignUpSignInSelectionFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginSignUpSignInSelectionFragment.kt @@ -49,6 +49,7 @@ open class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractLo loginSignupSigninTitle.text = getString(R.string.login_server_other_title) loginSignupSigninText.text = getString(R.string.login_connect_to, state.homeServerUrl.toReducedUrl()) } + ServerType.Unknown -> Unit /* Should not happen */ } } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt index fc970297d1..47736ec047 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt @@ -321,7 +321,7 @@ class LoginViewModel @AssistedInject constructor( LoginAction.ResetHomeServerType -> { setState { copy( - serverType = ServerType.MatrixOrg + serverType = ServerType.Unknown ) } } @@ -390,6 +390,15 @@ class LoginViewModel @AssistedInject constructor( serverType = action.serverType ) } + + when (action.serverType) { + ServerType.Unknown -> Unit /* Should not happen */ + ServerType.MatrixOrg -> + // Request login flow here + handle(LoginAction.UpdateHomeServer(stringProvider.getString(R.string.matrix_org_server_url))) + ServerType.Modular, + ServerType.Other -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone) + }.exhaustive } private fun handleInitWith(action: LoginAction.InitWith) { @@ -682,7 +691,9 @@ class LoginViewModel @AssistedInject constructor( _viewEvents.post(LoginViewEvents.Failure(failure)) setState { copy( - asyncHomeServerLoginFlowRequest = Uninitialized + asyncHomeServerLoginFlowRequest = Uninitialized, + // If we were trying to retrieve matrix.org login flow, also reset the serverType + serverType = if (serverType == ServerType.MatrixOrg) ServerType.Unknown else serverType ) } } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt index 944d1f7d82..655966ce25 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt @@ -35,7 +35,7 @@ data class LoginViewState( // User choices @PersistState - val serverType: ServerType = ServerType.MatrixOrg, + val serverType: ServerType = ServerType.Unknown, @PersistState val signMode: SignMode = SignMode.Unknown, @PersistState diff --git a/vector/src/main/java/im/vector/riotx/features/login/ServerType.kt b/vector/src/main/java/im/vector/riotx/features/login/ServerType.kt index 4c7007c137..50dfee19f0 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/ServerType.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/ServerType.kt @@ -17,6 +17,7 @@ package im.vector.riotx.features.login enum class ServerType { + Unknown, MatrixOrg, Modular, Other diff --git a/vector/src/main/res/drawable/bg_login_server_selector.xml b/vector/src/main/res/drawable/bg_login_server_selector.xml index 57be1e5d54..3fcc4e006a 100644 --- a/vector/src/main/res/drawable/bg_login_server_selector.xml +++ b/vector/src/main/res/drawable/bg_login_server_selector.xml @@ -2,6 +2,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/bg_login_server_checked" android:state_checked="true" /> + <item android:drawable="@drawable/bg_login_server_checked" android:state_pressed="true" /> <item android:drawable="@drawable/bg_login_server" /> diff --git a/vector/src/main/res/layout/fragment_login_server_selection.xml b/vector/src/main/res/layout/fragment_login_server_selection.xml index 16465486a2..de7bf65cbb 100644 --- a/vector/src/main/res/layout/fragment_login_server_selection.xml +++ b/vector/src/main/res/layout/fragment_login_server_selection.xml @@ -43,6 +43,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/loginServerTitle" /> + <!-- Use a CheckableConstraintLayout to keep the pressed state when retrieving login flow --> <im.vector.riotx.core.platform.CheckableConstraintLayout android:id="@+id/loginServerChoiceMatrixOrg" android:layout_width="match_parent" @@ -84,7 +85,7 @@ </im.vector.riotx.core.platform.CheckableConstraintLayout> - <im.vector.riotx.core.platform.CheckableConstraintLayout + <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/loginServerChoiceModular" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -135,9 +136,9 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/loginServerChoiceModularText" /> - </im.vector.riotx.core.platform.CheckableConstraintLayout> + </androidx.constraintlayout.widget.ConstraintLayout> - <im.vector.riotx.core.platform.CheckableConstraintLayout + <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/loginServerChoiceOther" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -178,20 +179,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOtherTitle" /> - </im.vector.riotx.core.platform.CheckableConstraintLayout> - - <com.google.android.material.button.MaterialButton - android:id="@+id/loginServerSubmit" - style="@style/Style.Vector.Login.Button" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="24dp" - android:text="@string/login_continue" - android:transitionName="loginSubmitTransition" - app:layout_constraintBottom_toTopOf="@+id/loginServerIKnowMyIdSubmit" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOther" /> + </androidx.constraintlayout.widget.ConstraintLayout> <com.google.android.material.button.MaterialButton android:id="@+id/loginServerIKnowMyIdSubmit" @@ -204,7 +192,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/loginServerSubmit" /> + app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOther" /> </androidx.constraintlayout.widget.ConstraintLayout> From e7f13c9efec817a3a8622610554a5fecce10abb6 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Sun, 5 Jul 2020 23:41:19 +0200 Subject: [PATCH 22/28] Handle JobCancellationException --- .../im/vector/riotx/features/login/AbstractLoginFragment.kt | 3 +++ .../main/java/im/vector/riotx/features/login/LoginViewModel.kt | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/login/AbstractLoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/AbstractLoginFragment.kt index 5927e5b117..90be21b6be 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/AbstractLoginFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/AbstractLoginFragment.kt @@ -73,6 +73,9 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed { override fun showFailure(throwable: Throwable) { when (throwable) { + is Failure.Cancelled -> + /* Ignore this error, user has cancelled the action */ + Unit is Failure.ServerError -> if (throwable.error.code == MatrixError.M_FORBIDDEN && throwable.httpCode == HttpsURLConnection.HTTP_FORBIDDEN /* 403 */) { diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt index 47736ec047..b7db9fd229 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt @@ -436,7 +436,6 @@ class LoginViewModel @AssistedInject constructor( } override fun onFailure(failure: Throwable) { - // TODO Handled JobCancellationException setState { copy( asyncResetPassword = Fail(failure) @@ -478,7 +477,6 @@ class LoginViewModel @AssistedInject constructor( } override fun onFailure(failure: Throwable) { - // TODO Handled JobCancellationException setState { copy( asyncResetMailConfirmed = Fail(failure) @@ -593,7 +591,6 @@ class LoginViewModel @AssistedInject constructor( } override fun onFailure(failure: Throwable) { - // TODO Handled JobCancellationException setState { copy( asyncLoginAction = Fail(failure) From e859357c6aea56742978b02945ad82107dc8e9da Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Mon, 6 Jul 2020 13:49:39 +0200 Subject: [PATCH 23/28] Handle certificate error in case of Direct Login --- .../internal/auth/login/DirectLoginTask.kt | 23 ++++- .../internal/wellknown/GetWellknownTask.kt | 7 ++ .../im/vector/riotx/core/utils/UrlUtils.kt | 8 ++ .../login/LoginServerUrlFormFragment.kt | 3 +- .../riotx/features/login/LoginViewModel.kt | 97 +++++++++++++------ 5 files changed, 104 insertions(+), 34 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/login/DirectLoginTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/login/DirectLoginTask.kt index 22a921a094..51dbac2cc3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/login/DirectLoginTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/login/DirectLoginTask.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.auth.login import dagger.Lazy import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig +import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.internal.auth.AuthAPI import im.vector.matrix.android.internal.auth.SessionCreator @@ -27,6 +28,7 @@ import im.vector.matrix.android.internal.di.Unauthenticated import im.vector.matrix.android.internal.network.RetrofitFactory import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.httpclient.addSocketFactory +import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException import im.vector.matrix.android.internal.task.Task import okhttp3.OkHttpClient import javax.inject.Inject @@ -49,13 +51,28 @@ internal class DefaultDirectLoginTask @Inject constructor( override suspend fun execute(params: DirectLoginTask.Params): Session { val client = buildClient(params.homeServerConnectionConfig) - val authAPI = retrofitFactory.create(client, params.homeServerConnectionConfig.homeServerUri.toString()) + val homeServerUrl = params.homeServerConnectionConfig.homeServerUri.toString() + + val authAPI = retrofitFactory.create(client, homeServerUrl) .create(AuthAPI::class.java) val loginParams = PasswordLoginParams.userIdentifier(params.userId, params.password, params.deviceName) - val credentials = executeRequest<Credentials>(null) { - apiCall = authAPI.login(loginParams) + val credentials = try { + executeRequest<Credentials>(null) { + apiCall = authAPI.login(loginParams) + } + } catch (throwable: Throwable) { + when (throwable) { + is UnrecognizedCertificateException -> { + throw Failure.UnrecognizedCertificateFailure( + homeServerUrl, + throwable.fingerprint + ) + } + else -> + throw throwable + } } return sessionCreator.createSession(credentials, params.homeServerConnectionConfig) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/wellknown/GetWellknownTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/wellknown/GetWellknownTask.kt index 8ded737c64..b42aef5f88 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/wellknown/GetWellknownTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/wellknown/GetWellknownTask.kt @@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.di.Unauthenticated import im.vector.matrix.android.internal.network.RetrofitFactory import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.httpclient.addSocketFactory +import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException import im.vector.matrix.android.internal.session.homeserver.CapabilitiesAPI import im.vector.matrix.android.internal.session.identity.IdentityAuthAPI import im.vector.matrix.android.internal.task.Task @@ -106,6 +107,12 @@ internal class DefaultGetWellknownTask @Inject constructor( } } catch (throwable: Throwable) { when (throwable) { + is UnrecognizedCertificateException -> { + throw Failure.UnrecognizedCertificateFailure( + "https://$domain", + throwable.fingerprint + ) + } is Failure.NetworkConnection -> { WellknownResult.Ignore } diff --git a/vector/src/main/java/im/vector/riotx/core/utils/UrlUtils.kt b/vector/src/main/java/im/vector/riotx/core/utils/UrlUtils.kt index 0361fc9d71..c26cd85dc7 100644 --- a/vector/src/main/java/im/vector/riotx/core/utils/UrlUtils.kt +++ b/vector/src/main/java/im/vector/riotx/core/utils/UrlUtils.kt @@ -37,3 +37,11 @@ internal fun String.ensureProtocol(): String { else -> this } } + +internal fun String.ensureTrailingSlash(): String { + return when { + isEmpty() -> this + !endsWith("/") -> "$this/" + else -> this + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt index cb90ef2397..28331bc99e 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt @@ -70,7 +70,7 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_modular_hint) loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_modular_notice) } - ServerType.Other -> { + else -> { loginServerUrlFormIcon.isVisible = false loginServerUrlFormTitle.text = getString(R.string.login_server_other_title) loginServerUrlFormText.text = getString(R.string.login_connect_to_a_custom_server) @@ -78,7 +78,6 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_other_hint) loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_other_notice) } - else -> error("This fragment should not be displayed in matrix.org mode") } } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt index b7db9fd229..a7c58f4b04 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt @@ -39,6 +39,7 @@ import im.vector.matrix.android.api.auth.registration.RegistrationResult import im.vector.matrix.android.api.auth.registration.RegistrationWizard import im.vector.matrix.android.api.auth.registration.Stage import im.vector.matrix.android.api.auth.wellknown.WellknownResult +import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.util.Cancelable import im.vector.riotx.R @@ -47,6 +48,7 @@ import im.vector.riotx.core.extensions.configureAndStart import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.resources.StringProvider +import im.vector.riotx.core.utils.ensureTrailingSlash import im.vector.riotx.features.call.WebRtcPeerConnectionManager import im.vector.riotx.features.notifications.PushRuleTriggerListener import im.vector.riotx.features.session.SessionListener @@ -87,8 +89,12 @@ class LoginViewModel @AssistedInject constructor( } } + // Store the last action, to redo it after user has trusted the untrusted certificate + private var lastAction: LoginAction? = null private var currentHomeServerConnectionConfig: HomeServerConnectionConfig? = null + private val matrixOrgUrl = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash() + val currentThreePid: String? get() = registrationWizard?.currentThreePid @@ -111,8 +117,8 @@ class LoginViewModel @AssistedInject constructor( is LoginAction.UpdateServerType -> handleUpdateServerType(action) is LoginAction.UpdateSignMode -> handleUpdateSignMode(action) is LoginAction.InitWith -> handleInitWith(action) - is LoginAction.UpdateHomeServer -> handleUpdateHomeserver(action) - is LoginAction.LoginOrRegister -> handleLoginOrRegister(action) + is LoginAction.UpdateHomeServer -> handleUpdateHomeserver(action).also { lastAction = action } + is LoginAction.LoginOrRegister -> handleLoginOrRegister(action).also { lastAction = action } is LoginAction.LoginWithToken -> handleLoginWithToken(action) is LoginAction.WebLoginSuccess -> handleWebLoginSuccess(action) is LoginAction.ResetPassword -> handleResetPassword(action) @@ -126,10 +132,23 @@ class LoginViewModel @AssistedInject constructor( } private fun handleUserAcceptCertificate(action: LoginAction.UserAcceptCertificate) { - // It happen when we get the login flow, so alter the homeserver config and retrieve again the login flow - currentHomeServerConnectionConfig - ?.let { it.copy(allowedFingerprints = it.allowedFingerprints + action.fingerprint) } - ?.let { getLoginFlow(it) } + // It happen when we get the login flow, or during direct authentication. + // So alter the homeserver config and retrieve again the login flow + when (val finalLastAction = lastAction) { + is LoginAction.UpdateHomeServer -> + currentHomeServerConnectionConfig + ?.let { it.copy(allowedFingerprints = it.allowedFingerprints + action.fingerprint) } + ?.let { getLoginFlow(it) } + is LoginAction.LoginOrRegister -> + handleDirectLogin( + finalLastAction, + HomeServerConnectionConfig.Builder() + // Will be replaced by the task + .withHomeServerUri("https://dummy.org") + .withAllowedFingerPrints(listOf(action.fingerprint)) + .build() + ) + } } private fun handleLoginWithToken(action: LoginAction.LoginWithToken) { @@ -333,6 +352,7 @@ class LoginViewModel @AssistedInject constructor( asyncHomeServerLoginFlowRequest = Uninitialized, homeServerUrl = null, loginMode = LoginMode.Unknown, + serverType = ServerType.Unknown, loginModeSupportedTypes = emptyList() ) } @@ -395,7 +415,7 @@ class LoginViewModel @AssistedInject constructor( ServerType.Unknown -> Unit /* Should not happen */ ServerType.MatrixOrg -> // Request login flow here - handle(LoginAction.UpdateHomeServer(stringProvider.getString(R.string.matrix_org_server_url))) + handle(LoginAction.UpdateHomeServer(matrixOrgUrl)) ServerType.Modular, ServerType.Other -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone) }.exhaustive @@ -492,23 +512,22 @@ class LoginViewModel @AssistedInject constructor( SignMode.Unknown -> error("Developer error, invalid sign mode") SignMode.SignIn -> handleLogin(action) SignMode.SignUp -> handleRegisterWith(action) - SignMode.SignInWithMatrixId -> handleDirectLogin(action) + SignMode.SignInWithMatrixId -> handleDirectLogin(action, null) }.exhaustive } - private fun handleDirectLogin(action: LoginAction.LoginOrRegister) { + private fun handleDirectLogin(action: LoginAction.LoginOrRegister, homeServerConnectionConfig: HomeServerConnectionConfig?) { setState { copy( asyncLoginAction = Loading() ) } - // TODO Handle certificate error in this case. Direct login is deactivated now, so we will handle that later - authenticationService.getWellKnownData(action.username, null, object : MatrixCallback<WellknownResult> { + authenticationService.getWellKnownData(action.username, homeServerConnectionConfig, object : MatrixCallback<WellknownResult> { override fun onSuccess(data: WellknownResult) { when (data) { is WellknownResult.Prompt -> - onWellknownSuccess(action, data) + onWellknownSuccess(action, data, homeServerConnectionConfig) is WellknownResult.InvalidMatrixId -> { setState { copy( @@ -529,23 +548,26 @@ class LoginViewModel @AssistedInject constructor( } override fun onFailure(failure: Throwable) { - setState { - copy( - asyncLoginAction = Fail(failure) - ) - } + onDirectLoginError(failure) } }) } - private fun onWellknownSuccess(action: LoginAction.LoginOrRegister, wellKnownPrompt: WellknownResult.Prompt) { - val homeServerConnectionConfig = HomeServerConnectionConfig( - homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl), - identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) } - ) + private fun onWellknownSuccess(action: LoginAction.LoginOrRegister, + wellKnownPrompt: WellknownResult.Prompt, + homeServerConnectionConfig: HomeServerConnectionConfig?) { + val alteredHomeServerConnectionConfig = homeServerConnectionConfig + ?.copy( + homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl), + identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) } + ) + ?: HomeServerConnectionConfig( + homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl), + identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) } + ) authenticationService.directAuthentication( - homeServerConnectionConfig, + alteredHomeServerConnectionConfig, action.username, action.password, action.initialDeviceName, @@ -555,15 +577,29 @@ class LoginViewModel @AssistedInject constructor( } override fun onFailure(failure: Throwable) { - setState { - copy( - asyncLoginAction = Fail(failure) - ) - } + onDirectLoginError(failure) } }) } + private fun onDirectLoginError(failure: Throwable) { + if (failure is Failure.UnrecognizedCertificateFailure) { + // Display this error in a dialog + _viewEvents.post(LoginViewEvents.Failure(failure)) + setState { + copy( + asyncLoginAction = Uninitialized + ) + } + } else { + setState { + copy( + asyncLoginAction = Fail(failure) + ) + } + } + } + private fun handleLogin(action: LoginAction.LoginOrRegister) { val safeLoginWizard = loginWizard @@ -679,7 +715,10 @@ class LoginViewModel @AssistedInject constructor( setState { copy( - asyncHomeServerLoginFlowRequest = Loading() + asyncHomeServerLoginFlowRequest = Loading(), + // If user has entered https://matrix.org, ensure that server type is ServerType.MatrixOrg + // It is also useful to set the value again in the case of a certificate error on matrix.org + serverType = if (homeServerConnectionConfig.homeServerUri.toString() == matrixOrgUrl) ServerType.MatrixOrg else serverType ) } From cfdf5cb552fbf40ac2c450d81723ff789dca17d1 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Mon, 6 Jul 2020 14:57:28 +0200 Subject: [PATCH 24/28] Add a delay to avoid crash. Sounds like a workaround... --- .../vector/riotx/features/login/LoginViewModel.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt index a7c58f4b04..f68290e862 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt @@ -19,6 +19,7 @@ package im.vector.riotx.features.login import android.content.Context import android.net.Uri import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading @@ -53,6 +54,8 @@ import im.vector.riotx.features.call.WebRtcPeerConnectionManager import im.vector.riotx.features.notifications.PushRuleTriggerListener import im.vector.riotx.features.session.SessionListener import im.vector.riotx.features.signout.soft.SoftLogoutActivity +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import timber.log.Timber import java.util.concurrent.CancellationException @@ -399,9 +402,16 @@ class LoginViewModel @AssistedInject constructor( when (action.signMode) { SignMode.SignUp -> startRegistrationFlow() SignMode.SignIn -> startAuthenticationFlow() - SignMode.SignInWithMatrixId -> _viewEvents.post(LoginViewEvents.OnSignModeSelected) + SignMode.SignInWithMatrixId -> { + viewModelScope.launch { + // Add a delay to avoid crash + delay(50) + _viewEvents.post(LoginViewEvents.OnSignModeSelected) + } + Unit + } SignMode.Unknown -> Unit - }.exhaustive + } } private fun handleUpdateServerType(action: LoginAction.UpdateServerType) { From f998cb6b18f9cdbc68113529bac07f67fe0ca1a0 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Mon, 6 Jul 2020 17:12:47 +0200 Subject: [PATCH 25/28] Upload device keys only once to the homeserver and fix crash when no network (#1629) --- CHANGES.md | 2 +- .../internal/crypto/DefaultCryptoService.kt | 22 +++++++++++++------ .../internal/crypto/store/IMXCryptoStore.kt | 3 +++ .../crypto/store/db/RealmCryptoStore.kt | 12 ++++++++++ .../store/db/RealmCryptoStoreMigration.kt | 10 ++++++++- .../store/db/model/CryptoMetadataEntity.kt | 3 +++ 6 files changed, 43 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 20b3b34375..a8313cc722 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features ✨: - Improvements 🙌: - - + - Upload device keys only once to the homeserver and fix crash when no network (#1629) Bugfix 🐛: - Fix crash when coming from a notification (#1601) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt index 02197fb5f3..01dd0ca17d 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt @@ -70,7 +70,6 @@ import im.vector.matrix.android.internal.crypto.model.event.RoomKeyWithHeldConte import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse -import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody import im.vector.matrix.android.internal.crypto.model.toRest import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository @@ -343,8 +342,11 @@ internal class DefaultCryptoService @Inject constructor( cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { // Open the store cryptoStore.open() - // TODO why do that everytime? we should mark that it was done - uploadDeviceKeys() + // this can throw if no network + tryThis { + uploadDeviceKeys() + } + oneTimeKeysUploader.maybeUploadOneTimeKeys() // this can throw if no backup tryThis { @@ -389,7 +391,7 @@ internal class DefaultCryptoService @Inject constructor( // } else { // Why would we do that? it will be called at end of syn - incomingGossipingRequestManager.processReceivedGossipingRequests() + incomingGossipingRequestManager.processReceivedGossipingRequests() // } }.fold( { @@ -888,7 +890,7 @@ internal class DefaultCryptoService @Inject constructor( */ private fun handleSDKLevelGossip(secretName: String?, secretValue: String): Boolean { return when (secretName) { - MASTER_KEY_SSSS_NAME -> { + MASTER_KEY_SSSS_NAME -> { crossSigningService.onSecretMSKGossip(secretValue) true } @@ -980,7 +982,11 @@ internal class DefaultCryptoService @Inject constructor( /** * Upload my user's device keys. */ - private suspend fun uploadDeviceKeys(): KeysUploadResponse { + private suspend fun uploadDeviceKeys() { + if (cryptoStore.getDeviceKeysUploaded()) { + Timber.d("Keys already uploaded, nothing to do") + return + } // Prepare the device keys data to send // Sign it val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary()) @@ -991,7 +997,9 @@ internal class DefaultCryptoService @Inject constructor( ) val uploadDeviceKeysParams = UploadKeysTask.Params(rest, null) - return uploadKeysTask.execute(uploadDeviceKeysParams) + uploadKeysTask.execute(uploadDeviceKeysParams) + + cryptoStore.setDeviceKeysUploaded(true) } /** diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt index 3540f57608..f518332298 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt @@ -433,4 +433,7 @@ internal interface IMXCryptoStore { fun getOutgoingSecretRequest(secretName: String): OutgoingSecretRequest? fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest> fun getGossipingEventsTrail(): List<Event> + + fun setDeviceKeysUploaded(uploaded: Boolean) + fun getDeviceKeysUploaded(): Boolean } 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 ec5e64dde8..0e67850304 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 @@ -842,6 +842,18 @@ internal class RealmCryptoStore @Inject constructor( } ?: false } + override fun setDeviceKeysUploaded(uploaded: Boolean) { + doRealmTransaction(realmConfiguration) { + it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer = uploaded + } + } + + override fun getDeviceKeysUploaded(): Boolean { + return doWithRealm(realmConfiguration) { + it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer + } ?: false + } + override fun setRoomsListBlacklistUnverifiedDevices(roomIds: List<String>) { doRealmTransaction(realmConfiguration) { // Reset all diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt index 7bf8e2478f..0cca430799 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -54,7 +54,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi // 0, 1, 2: legacy Riot-Android // 3: migrate to RiotX schema // 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6) - const val CRYPTO_STORE_SCHEMA_VERSION = 10L + const val CRYPTO_STORE_SCHEMA_VERSION = 11L } override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { @@ -70,6 +70,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi if (oldVersion <= 7) migrateTo8(realm) if (oldVersion <= 8) migrateTo9(realm) if (oldVersion <= 9) migrateTo10(realm) + if (oldVersion <= 10) migrateTo11(realm) } private fun migrateTo1Legacy(realm: DynamicRealm) { @@ -446,4 +447,11 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi .addField(SharedSessionEntityFields.CHAIN_INDEX, Long::class.java) .setNullable(SharedSessionEntityFields.CHAIN_INDEX, true) } + + // Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity + private fun migrateTo11(realm: DynamicRealm) { + Timber.d("Step 10 -> 11") + realm.schema.get("CryptoMetadataEntity") + ?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java) + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt index 2d4706ba76..f3c34af586 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt @@ -36,6 +36,9 @@ internal open class CryptoMetadataEntity( // The keys backup version currently used. Null means no backup. var backupVersion: String? = null, + // The device keys has been sent to the homeserver + var deviceKeysSentToServer: Boolean = false, + var xSignMasterPrivateKey: String? = null, var xSignUserPrivateKey: String? = null, var xSignSelfSignedPrivateKey: String? = null, From 38c54e0f2ccb90ed6fe8dcabf26d2020b5ebb983 Mon Sep 17 00:00:00 2001 From: Valere <valeref@matrix.org> Date: Mon, 6 Jul 2020 18:51:39 +0200 Subject: [PATCH 26/28] QuickFix / crash when starting in airplane mode --- .../matrix/android/internal/crypto/DefaultCryptoService.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt index 02197fb5f3..0af7a2d36d 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt @@ -98,6 +98,7 @@ import im.vector.matrix.android.internal.session.sync.model.SyncResponse import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.configureWith +import im.vector.matrix.android.internal.task.launchToCallback import im.vector.matrix.android.internal.util.JsonCanonicalizer import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.fetchCopied @@ -340,7 +341,7 @@ internal class DefaultCryptoService @Inject constructor( } fun ensureDevice() { - cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { + cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) { // Open the store cryptoStore.open() // TODO why do that everytime? we should mark that it was done From 8b1a07b8a89252185be1a89ba4b7966b294f125f Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Mon, 6 Jul 2020 23:01:45 +0200 Subject: [PATCH 27/28] Add the new value to the ViewEvent, because the state is maybe not up to date. --- .../vector/riotx/features/login/LoginActivity.kt | 13 +++++++------ .../riotx/features/login/LoginViewEvents.kt | 4 ++-- .../riotx/features/login/LoginViewModel.kt | 16 +++------------- .../features/signout/soft/SoftLogoutFragment.kt | 5 +++-- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt index 1eebf532e7..f71b0ecba4 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt @@ -151,8 +151,8 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable { // TODO Disabled because it provokes a flickering // ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim) }) - is LoginViewEvents.OnServerSelectionDone -> onServerSelectionDone() - is LoginViewEvents.OnSignModeSelected -> onSignModeSelected() + is LoginViewEvents.OnServerSelectionDone -> onServerSelectionDone(loginViewEvents) + is LoginViewEvents.OnSignModeSelected -> onSignModeSelected(loginViewEvents) is LoginViewEvents.OnLoginFlowRetrieved -> addFragmentToBackstack(R.id.loginFragmentContainer, if (loginViewEvents.isSso) { @@ -228,8 +228,8 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable { .show() } - private fun onServerSelectionDone() = withState(loginViewModel) { state -> - when (state.serverType) { + private fun onServerSelectionDone(loginViewEvents: LoginViewEvents.OnServerSelectionDone) { + when (loginViewEvents.serverType) { ServerType.MatrixOrg -> Unit // In this case, we wait for the login flow ServerType.Modular, ServerType.Other -> addFragmentToBackstack(R.id.loginFragmentContainer, @@ -239,8 +239,9 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable { } } - private fun onSignModeSelected() = withState(loginViewModel) { state -> - when (state.signMode) { + private fun onSignModeSelected(loginViewEvents: LoginViewEvents.OnSignModeSelected) = withState(loginViewModel) { state -> + // state.signMode could not be ready yet. So use value from the ViewEvent + when (loginViewEvents.signMode) { SignMode.Unknown -> error("Sign mode has to be set before calling this method") SignMode.SignUp -> { // This is managed by the LoginViewEvents diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewEvents.kt index 9b69ba8a4f..fe5c00399b 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewEvents.kt @@ -33,9 +33,9 @@ sealed class LoginViewEvents : VectorViewEvents { // Navigation event object OpenServerSelection : LoginViewEvents() - object OnServerSelectionDone : LoginViewEvents() + data class OnServerSelectionDone(val serverType: ServerType) : LoginViewEvents() data class OnLoginFlowRetrieved(val isSso: Boolean) : LoginViewEvents() - object OnSignModeSelected : LoginViewEvents() + data class OnSignModeSelected(val signMode: SignMode) : LoginViewEvents() object OnForgetPasswordClicked : LoginViewEvents() object OnResetPasswordSendThreePidDone : LoginViewEvents() object OnResetPasswordMailConfirmationSuccess : LoginViewEvents() diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt index f68290e862..7edc674b11 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt @@ -19,7 +19,6 @@ package im.vector.riotx.features.login import android.content.Context import android.net.Uri import androidx.fragment.app.FragmentActivity -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading @@ -54,8 +53,6 @@ import im.vector.riotx.features.call.WebRtcPeerConnectionManager import im.vector.riotx.features.notifications.PushRuleTriggerListener import im.vector.riotx.features.session.SessionListener import im.vector.riotx.features.signout.soft.SoftLogoutActivity -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import timber.log.Timber import java.util.concurrent.CancellationException @@ -402,14 +399,7 @@ class LoginViewModel @AssistedInject constructor( when (action.signMode) { SignMode.SignUp -> startRegistrationFlow() SignMode.SignIn -> startAuthenticationFlow() - SignMode.SignInWithMatrixId -> { - viewModelScope.launch { - // Add a delay to avoid crash - delay(50) - _viewEvents.post(LoginViewEvents.OnSignModeSelected) - } - Unit - } + SignMode.SignInWithMatrixId -> _viewEvents.post(LoginViewEvents.OnSignModeSelected(SignMode.SignInWithMatrixId)) SignMode.Unknown -> Unit } } @@ -427,7 +417,7 @@ class LoginViewModel @AssistedInject constructor( // Request login flow here handle(LoginAction.UpdateHomeServer(matrixOrgUrl)) ServerType.Modular, - ServerType.Other -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone) + ServerType.Other -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone(action.serverType)) }.exhaustive } @@ -661,7 +651,7 @@ class LoginViewModel @AssistedInject constructor( // Ensure Wizard is ready loginWizard - _viewEvents.post(LoginViewEvents.OnSignModeSelected) + _viewEvents.post(LoginViewEvents.OnSignModeSelected(SignMode.SignIn)) } private fun onFlowResponse(flowResult: FlowResult) { diff --git a/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutFragment.kt b/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutFragment.kt index 13b90f26e8..fadcaa8055 100644 --- a/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutFragment.kt @@ -93,8 +93,9 @@ class SoftLogoutFragment @Inject constructor( softLogoutViewModel.handle(SoftLogoutAction.SignInAgain(password)) } - override fun signinFallbackSubmit() { - loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnSignModeSelected)) + override fun signinFallbackSubmit() = withState(loginViewModel) { state -> + // The loginViewModel has been prepared for a SSO/login fallback recovery (above) + loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnSignModeSelected(state.signMode))) } override fun clearData() { From 1e6d98a121470f7f0ccea1954231c671642ba278 Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoitm@matrix.org> Date: Mon, 6 Jul 2020 23:31:03 +0200 Subject: [PATCH 28/28] Prepare release 0.91.04-beta --- CHANGES.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 62aeb5473d..e264facd8e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,20 +14,11 @@ Bugfix 🐛: - saved images don't show up in gallery (#1324) - Fix reply fallback leaking sender locale (#429) -Translations 🗣: - - - -SDK API changes ⚠️: - - - Build 🧱: - Fix lint false-positive about WorkManager (#1012) - Upgrade build-tools from 3.5.3 to 3.6.6 - Upgrade gradle from 5.4.1 to 5.6.4 -Other changes: - - - Changes in Riot.imX 0.91.3 (2020-07-01) ===================================================