From 96cf5d2105127f4e0349556449f498abbe58e905 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 24 Aug 2020 14:32:43 +0200 Subject: [PATCH 01/13] Cleanup: propoerly inject things to PushRulesFragment and move PushRulesController to its own file --- .../im/vector/app/core/di/FragmentModule.kt | 6 +++ .../settings/push/PushRulesController.kt | 44 +++++++++++++++++++ .../settings/push/PushRulesFragment.kt | 29 ++---------- 3 files changed, 54 insertions(+), 25 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/push/PushRulesController.kt diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index 1aa9902137..591d1c0474 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -102,6 +102,7 @@ import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment import im.vector.app.features.settings.locale.LocalePickerFragment import im.vector.app.features.settings.push.PushGatewaysFragment +import im.vector.app.features.settings.push.PushRulesFragment import im.vector.app.features.share.IncomingShareFragment import im.vector.app.features.signout.soft.SoftLogoutFragment import im.vector.app.features.terms.ReviewTermsFragment @@ -282,6 +283,11 @@ interface FragmentModule { @FragmentKey(VectorSettingsLabsFragment::class) fun bindVectorSettingsLabsFragment(fragment: VectorSettingsLabsFragment): Fragment + @Binds + @IntoMap + @FragmentKey(PushRulesFragment::class) + fun bindPushRulesFragment(fragment: PushRulesFragment): Fragment + @Binds @IntoMap @FragmentKey(VectorSettingsPreferencesFragment::class) diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesController.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesController.kt new file mode 100644 index 0000000000..a8a1ab2e17 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesController.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.push + +import com.airbnb.epoxy.TypedEpoxyController +import im.vector.app.R +import im.vector.app.core.resources.StringProvider +import im.vector.app.core.ui.list.genericFooterItem +import javax.inject.Inject + +class PushRulesController @Inject constructor( + private val stringProvider: StringProvider +) : TypedEpoxyController() { + + override fun buildModels(data: PushRulesViewState?) { + data?.let { + it.rules.forEach { + pushRuleItem { + id(it.ruleId) + pushRule(it) + } + } + } ?: run { + genericFooterItem { + id("footer") + text(stringProvider.getString(R.string.settings_push_rules_no_rules)) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt index 44cb5d8ea2..c361e21254 100644 --- a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt @@ -17,7 +17,6 @@ package im.vector.app.features.settings.push import android.os.Bundle import android.view.View -import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -25,19 +24,18 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment -import im.vector.app.core.resources.StringProvider -import im.vector.app.core.ui.list.genericFooterItem import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import javax.inject.Inject // Referenced in vector_settings_notifications.xml -class PushRulesFragment : VectorBaseFragment() { +class PushRulesFragment @Inject constructor( + private val epoxyController: PushRulesController +) : VectorBaseFragment() { override fun getLayoutResId() = R.layout.fragment_generic_recycler private val viewModel: PushRulesViewModel by fragmentViewModel(PushRulesViewModel::class) - private val epoxyController by lazy { PushRulesController(StringProvider(requireContext().resources)) } - override fun onResume() { super.onResume() (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_push_rules) @@ -56,23 +54,4 @@ class PushRulesFragment : VectorBaseFragment() { override fun invalidate() = withState(viewModel) { state -> epoxyController.setData(state) } - - class PushRulesController(private val stringProvider: StringProvider) : TypedEpoxyController() { - - override fun buildModels(data: PushRulesViewState?) { - data?.let { - it.rules.forEach { - pushRuleItem { - id(it.ruleId) - pushRule(it) - } - } - } ?: run { - genericFooterItem { - id("footer") - text(stringProvider.getString(R.string.settings_push_rules_no_rules)) - } - } - } - } } From 69e9a79ac1885335a6c55a1e5a547d5ee0892aa4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 24 Aug 2020 14:49:42 +0200 Subject: [PATCH 02/13] Inject StringProvider instead of Context --- .../membership/RoomDisplayNameResolver.kt | 19 ++++++++++--------- .../sdk/internal/util/StringProvider.kt | 8 ++++---- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt index d11226bdb1..942da9995e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.session.room.membership -import android.content.Context +import io.realm.Realm import org.matrix.android.sdk.R import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel @@ -34,14 +34,15 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.query.getOrNull import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.UserId -import io.realm.Realm +import org.matrix.android.sdk.internal.util.StringProvider import javax.inject.Inject /** * This class computes room display name */ -internal class RoomDisplayNameResolver @Inject constructor(private val context: Context, - @UserId private val userId: String +internal class RoomDisplayNameResolver @Inject constructor( + private val stringProvider: StringProvider, + @UserId private val userId: String ) { /** @@ -89,7 +90,7 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context: .findFirst() ?.displayName } else { - context.getString(R.string.room_displayname_room_invite) + stringProvider.getString(R.string.room_displayname_room_invite) } } else if (roomEntity?.membership == Membership.JOIN) { val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() @@ -108,13 +109,13 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context: } val otherMembersCount = otherMembersSubset.count() name = when (otherMembersCount) { - 0 -> context.getString(R.string.room_displayname_empty_room) - 1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers) - 2 -> context.getString(R.string.room_displayname_two_members, + 0 -> stringProvider.getString(R.string.room_displayname_empty_room) + 1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers) + 2 -> stringProvider.getString(R.string.room_displayname_two_members, resolveRoomMemberName(otherMembersSubset[0], roomMembers), resolveRoomMemberName(otherMembersSubset[1], roomMembers) ) - else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members, + else -> stringProvider.getQuantityString(R.plurals.room_displayname_three_and_more_members, roomMembers.getNumberOfJoinedMembers() - 1, resolveRoomMemberName(otherMembersSubset[0], roomMembers), roomMembers.getNumberOfJoinedMembers() - 1) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt index 902d7d3316..9233b2b807 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt @@ -18,8 +18,8 @@ package org.matrix.android.sdk.internal.util import android.content.res.Resources -import androidx.annotation.ArrayRes import androidx.annotation.NonNull +import androidx.annotation.PluralsRes import androidx.annotation.StringRes import dagger.Reusable import javax.inject.Inject @@ -56,8 +56,8 @@ internal class StringProvider @Inject constructor(private val resources: Resourc return resources.getString(resId, *formatArgs) } - @Throws(Resources.NotFoundException::class) - fun getStringArray(@ArrayRes id: Int): Array { - return resources.getStringArray(id) + @NonNull + fun getQuantityString(@PluralsRes resId: Int, quantity: Int, vararg formatArgs: Any?): String { + return resources.getQuantityString(resId, quantity, *formatArgs) } } From efa3aa5cf8e24726c18ce4a3493feff618db2e13 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 24 Aug 2020 15:08:52 +0200 Subject: [PATCH 03/13] Stop using internal context of VectorLocal in CallHeadsUpActionReceiver... --- .../call/service/CallHeadsUpActionReceiver.kt | 22 ++++++------------- .../app/features/settings/VectorLocale.kt | 2 +- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt b/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt index 179ba288eb..04e7401e6c 100644 --- a/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt +++ b/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt @@ -21,8 +21,6 @@ import android.content.Context import android.content.Intent import im.vector.app.core.di.HasVectorInjector import im.vector.app.features.call.WebRtcPeerConnectionManager -import im.vector.app.features.notifications.NotificationUtils -import im.vector.app.features.settings.VectorLocale.context import timber.log.Timber class CallHeadsUpActionReceiver : BroadcastReceiver() { @@ -32,20 +30,14 @@ class CallHeadsUpActionReceiver : BroadcastReceiver() { const val CALL_ACTION_REJECT = 0 } - private lateinit var peerConnectionManager: WebRtcPeerConnectionManager - private lateinit var notificationUtils: NotificationUtils - - init { - val appContext = context.applicationContext - if (appContext is HasVectorInjector) { - peerConnectionManager = appContext.injector().webRtcPeerConnectionManager() - notificationUtils = appContext.injector().notificationUtils() - } - } - override fun onReceive(context: Context, intent: Intent?) { + val peerConnectionManager = (context.applicationContext as? HasVectorInjector) + ?.injector() + ?.webRtcPeerConnectionManager() + ?: return + when (intent?.getIntExtra(EXTRA_CALL_ACTION_KEY, 0)) { - CALL_ACTION_REJECT -> onCallRejectClicked() + CALL_ACTION_REJECT -> onCallRejectClicked(peerConnectionManager) } // Not sure why this should be needed @@ -56,7 +48,7 @@ class CallHeadsUpActionReceiver : BroadcastReceiver() { // context.stopService(Intent(context, CallHeadsUpService::class.java)) } - private fun onCallRejectClicked() { + private fun onCallRejectClicked(peerConnectionManager: WebRtcPeerConnectionManager) { Timber.d("onCallRejectClicked") peerConnectionManager.endCall() } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt index d2f92e300e..b9d81ab005 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt @@ -52,7 +52,7 @@ object VectorLocale { var applicationLocale = defaultLocale private set - lateinit var context: Context + private lateinit var context: Context /** * Init this object From 116e6fb3c07ca53d64f60f12af453918bd4fc312 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 24 Aug 2020 15:50:47 +0200 Subject: [PATCH 04/13] Call restart() extension --- .../java/im/vector/app/core/platform/VectorBaseActivity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 11a6e326ac..856e84ea14 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -60,6 +60,7 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.observeEvent import im.vector.app.core.extensions.observeNotNull +import im.vector.app.core.extensions.restart import im.vector.app.core.extensions.vectorComponent import im.vector.app.core.utils.toast import im.vector.app.features.MainActivity @@ -79,10 +80,10 @@ import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.themes.ThemeUtils import im.vector.app.receivers.DebugReceiver -import org.matrix.android.sdk.api.failure.GlobalError import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable +import org.matrix.android.sdk.api.failure.GlobalError import timber.log.Timber import kotlin.system.measureTimeMillis @@ -198,8 +199,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { configurationViewModel.activityRestarter.observe(this, Observer { if (!it.hasBeenHandled) { // Recreate the Activity because configuration has changed - startActivity(intent) - finish() + restart() } }) pinLocker.getLiveState().observeNotNull(this) { From ed98613b2d9c82d6dd36b705456043f078ea2712 Mon Sep 17 00:00:00 2001 From: Tobias Preuss Date: Wed, 19 Aug 2020 22:59:57 +0200 Subject: [PATCH 05/13] Use File extension functions to make code more concise. + This change replaces a few usages of ByteArrayInputStream, FileInputStream, FileOutputStream with their equivalent Kotlin extension functions. --- CHANGES.md | 2 +- .../sdk/internal/crypto/AttachmentEncryptionTest.kt | 3 +-- .../crypto/attachments/MXEncryptedAttachments.kt | 3 +-- .../android/sdk/internal/crypto/store/db/Helper.kt | 3 +-- .../sdk/internal/session/content/UploadContentWorker.kt | 9 +++------ .../internal/session/securestorage/SecretStoringUtils.kt | 2 +- .../org/matrix/android/sdk/internal/util/FileSaver.kt | 3 +-- .../im/vector/app/core/glide/VectorGlideModelLoader.kt | 3 +-- .../im/vector/app/core/utils/ExternalApplicationsUtil.kt | 4 ++-- .../features/notifications/NotificationDrawerManager.kt | 3 +-- 10 files changed, 13 insertions(+), 22 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d3a16c9b29..a9f2e896aa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -20,7 +20,7 @@ Build 🧱: - Some dependencies have been upgraded (coroutine, recyclerView, appCompat, core-ktx, firebase-messaging) Other changes: - - + - Use File extension functions to make code more concise (#1996) Changes in Element 1.0.5 (2020-08-21) =================================================== diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt index 05dbc40e1e..cb24cbb242 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt @@ -29,7 +29,6 @@ import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters -import java.io.ByteArrayInputStream import java.io.InputStream /** @@ -46,7 +45,7 @@ class AttachmentEncryptionTest { val inputStream: InputStream inputStream = if (`in`.isEmpty()) { - ByteArrayInputStream(`in`) + `in`.inputStream() } else { val memoryFile = MemoryFile("file" + System.currentTimeMillis(), `in`.size) memoryFile.outputStream.write(`in`) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt index cec1480d7b..a6d95cc87a 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt @@ -21,7 +21,6 @@ import android.util.Base64 import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey import timber.log.Timber -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.InputStream import java.security.MessageDigest @@ -179,7 +178,7 @@ internal object MXEncryptedAttachments { return null } - return ByteArrayInputStream(outputStream.toByteArray()) + return outputStream.toByteArray().inputStream() .also { Timber.v("Decrypt in ${System.currentTimeMillis() - t0}ms") } } catch (oom: OutOfMemoryError) { Timber.e(oom, "## decryptAttachment() failed: OOM") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt index 978c82303e..67e06b5455 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt @@ -21,7 +21,6 @@ import android.util.Base64 import io.realm.Realm import io.realm.RealmConfiguration import io.realm.RealmObject -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.ObjectOutputStream import java.util.zip.GZIPInputStream @@ -96,7 +95,7 @@ fun deserializeFromRealm(string: String?): T? { } val decodedB64 = Base64.decode(string.toByteArray(), Base64.DEFAULT) - val bais = ByteArrayInputStream(decodedB64) + val bais = decodedB64.inputStream() val gzis = GZIPInputStream(bais) val ois = SafeObjectInputStream(gzis) return ois.use { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt index 6d354cdcbe..720269404f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt @@ -42,10 +42,7 @@ import org.matrix.android.sdk.internal.worker.SessionWorkerParams import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.android.sdk.internal.worker.getSessionComponent import timber.log.Timber -import java.io.ByteArrayInputStream import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream import java.util.UUID import javax.inject.Inject @@ -130,7 +127,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter val contentUploadResponse = if (params.isEncrypted) { Timber.v("Encrypt thumbnail") notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) } - val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType) + val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream(), thumbnailData.mimeType) uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo fileUploader.uploadByteArray(encryptionResult.encryptedByteArray, "thumb_${attachment.name}", @@ -176,7 +173,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter cacheFile.createNewFile() cacheFile.deleteOnExit() - val outputStream = FileOutputStream(cacheFile) + val outputStream = cacheFile.outputStream() outputStream.use { inputStream.copyTo(outputStream) } @@ -203,7 +200,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter Timber.v("Encrypt file") notifyTracker(params) { contentUploadStateTracker.setEncrypting(it) } - val encryptionResult = MXEncryptedAttachments.encryptAttachment(FileInputStream(cacheFile), attachment.getSafeMimeType()) + val encryptionResult = MXEncryptedAttachments.encryptAttachment(cacheFile.inputStream(), attachment.getSafeMimeType()) uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo fileUploader diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt index 2ae115f325..8eab44366c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt @@ -219,7 +219,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte @RequiresApi(Build.VERSION_CODES.M) private fun decryptStringM(encryptedChunk: ByteArray, keyAlias: String): String { - val (iv, encryptedText) = formatMExtract(ByteArrayInputStream(encryptedChunk)) + val (iv, encryptedText) = formatMExtract(encryptedChunk.inputStream()) val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt index 27625d90bc..da524cc1b2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt @@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.util import androidx.annotation.WorkerThread import java.io.File -import java.io.FileOutputStream import java.io.InputStream /** @@ -27,7 +26,7 @@ import java.io.InputStream */ @WorkerThread fun writeToFile(inputStream: InputStream, outputFile: File) { - FileOutputStream(outputFile).use { + outputFile.outputStream().use { inputStream.copyTo(it) } } diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt index 295609548f..9ac8a4d3bc 100644 --- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt +++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt @@ -31,7 +31,6 @@ import okhttp3.OkHttpClient import okhttp3.Request import timber.log.Timber import java.io.File -import java.io.FileInputStream import java.io.IOException import java.io.InputStream @@ -97,7 +96,7 @@ class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolde Timber.v("Load data: $data") if (data.isLocalFile() && data.url != null) { val initialFile = File(data.url) - callback.onDataReady(FileInputStream(initialFile)) + callback.onDataReady(initialFile.inputStream()) return } val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() diff --git a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt index b314401138..b1c63a406a 100644 --- a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt +++ b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt @@ -518,8 +518,8 @@ fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: Strin var outputStream: FileOutputStream? = null try { dstFile.createNewFile() - inputStream = FileInputStream(sourceFile) - outputStream = FileOutputStream(dstFile) + inputStream = sourceFile.inputStream() + outputStream = dstFile.outputStream() val buffer = ByteArray(1024 * 10) var len: Int while (inputStream.read(buffer).also { len = it } != -1) { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt index 98d35dc764..e689f9df3f 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt @@ -32,7 +32,6 @@ import org.matrix.android.sdk.api.session.content.ContentUrlResolver import me.gujun.android.span.span import timber.log.Timber import java.io.File -import java.io.FileInputStream import java.io.FileOutputStream import javax.inject.Inject import javax.inject.Singleton @@ -494,7 +493,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context try { val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME) if (file.exists()) { - FileInputStream(file).use { + file.inputStream().use { val events: ArrayList? = currentSession?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE) if (events != null) { return events.toMutableList() From 52cf4d24d36e38d2fc63c662915637e7a4a4f068 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 24 Aug 2020 18:05:11 +0200 Subject: [PATCH 06/13] Fix switch language issue --- CHANGES.md | 1 + .../java/im/vector/app/VectorApplication.kt | 15 +++--- .../vector/app/core/services/VectorService.kt | 6 +++ .../configuration/VectorConfiguration.kt | 47 ++++++++++--------- .../VectorSettingsPreferencesFragment.kt | 1 + .../settings/locale/LocalePickerViewModel.kt | 5 +- .../vector/app/features/themes/ThemeUtils.kt | 6 +++ 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d3a16c9b29..1bde8a7dfd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Improvements 🙌: Bugfix 🐛: - Display name not shown under Settings/General (#1926) + - Fix changing language issue Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index 303b9d585a..f64ebf9245 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -32,10 +32,6 @@ import com.airbnb.epoxy.EpoxyAsyncUtil import com.airbnb.epoxy.EpoxyController import com.facebook.stetho.Stetho import com.gabrielittner.threetenbp.LazyThreeTen -import org.matrix.android.sdk.api.Matrix -import org.matrix.android.sdk.api.MatrixConfiguration -import org.matrix.android.sdk.api.auth.AuthenticationService -import org.matrix.android.sdk.api.legacy.LegacySessionImporter import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.DaggerVectorComponent import im.vector.app.core.di.HasVectorInjector @@ -50,16 +46,21 @@ import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.pin.PinLocker import im.vector.app.features.popup.PopupAlertManager import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler +import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences +import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.version.VersionProvider import im.vector.app.push.fcm.FcmHelper +import org.matrix.android.sdk.api.Matrix +import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.auth.AuthenticationService +import org.matrix.android.sdk.api.legacy.LegacySessionImporter import timber.log.Timber import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.concurrent.Executors import javax.inject.Inject - import androidx.work.Configuration as WorkConfiguration class VectorApplication : @@ -119,7 +120,9 @@ class VectorApplication : R.array.com_google_android_gms_fonts_certs ) FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler()) - vectorConfiguration.initConfiguration() + VectorLocale.init(this) + ThemeUtils.init(this) + vectorConfiguration.applyToApplicationContext() emojiCompatWrapper.init(fontRequest) diff --git a/vector/src/main/java/im/vector/app/core/services/VectorService.kt b/vector/src/main/java/im/vector/app/core/services/VectorService.kt index 888f7a8cac..223d720d8a 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorService.kt @@ -17,8 +17,10 @@ package im.vector.app.core.services import android.app.Service +import android.content.Context import android.content.Intent import android.os.IBinder +import im.vector.app.core.extensions.vectorComponent import timber.log.Timber /** @@ -31,6 +33,10 @@ abstract class VectorService : Service() { */ private var mIsSelfDestroyed = false + override fun attachBaseContext(base: Context) { + super.attachBaseContext(vectorComponent().vectorConfiguration().getLocalisedContext(base)) + } + override fun onCreate() { super.onCreate() diff --git a/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt b/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt index 5567a138de..394eca030b 100644 --- a/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt +++ b/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt @@ -16,10 +16,11 @@ package im.vector.app.features.configuration -import android.annotation.SuppressLint import android.content.Context import android.content.res.Configuration import android.os.Build +import android.os.LocaleList +import androidx.annotation.RequiresApi import im.vector.app.features.settings.FontScale import im.vector.app.features.settings.VectorLocale import im.vector.app.features.themes.ThemeUtils @@ -40,14 +41,9 @@ class VectorConfiguration @Inject constructor(private val context: Context) { } } - /** - * Init the configuration from the saved one - */ - fun initConfiguration() { - VectorLocale.init(context) + fun applyToApplicationContext() { val locale = VectorLocale.applicationLocale val fontScale = FontScale.getFontScaleValue(context) - val theme = ThemeUtils.getApplicationTheme(context) Locale.setDefault(locale) val config = Configuration(context.resources.configuration) @@ -56,9 +52,6 @@ class VectorConfiguration @Inject constructor(private val context: Context) { config.fontScale = fontScale.scale @Suppress("DEPRECATION") context.resources.updateConfiguration(config, context.resources.displayMetrics) - - // init the theme - ThemeUtils.setApplicationTheme(context, theme) } /** @@ -67,26 +60,22 @@ class VectorConfiguration @Inject constructor(private val context: Context) { * @param context the context * @return the localised context */ - @SuppressLint("NewApi") fun getLocalisedContext(context: Context): Context { try { - val resources = context.resources val locale = VectorLocale.applicationLocale - val configuration = resources.configuration + + // create new configuration passing old configuration from original Context + val configuration = Configuration(context.resources.configuration) + configuration.fontScale = FontScale.getFontScaleValue(context).scale if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - configuration.setLocale(locale) - configuration.setLayoutDirection(locale) - return context.createConfigurationContext(configuration) + setLocaleForApi24(configuration, locale) } else { - @Suppress("DEPRECATION") - configuration.locale = locale - configuration.setLayoutDirection(locale) - @Suppress("DEPRECATION") - resources.updateConfiguration(configuration, resources.displayMetrics) - return context + configuration.setLocale(locale) } + configuration.setLayoutDirection(locale) + return context.createConfigurationContext(configuration) } catch (e: Exception) { Timber.e(e, "## getLocalisedContext() failed") } @@ -94,6 +83,20 @@ class VectorConfiguration @Inject constructor(private val context: Context) { return context } + @RequiresApi(Build.VERSION_CODES.N) + private fun setLocaleForApi24(config: Configuration, locale: Locale) { + val set: MutableSet = LinkedHashSet() + // bring the user locale to the front of the list + set.add(locale) + val all = LocaleList.getDefault() + for (i in 0 until all.size()) { + // append other locales supported by the user + set.add(all[i]) + } + val locales = set.toTypedArray() + config.setLocales(LocaleList(*locales)) + } + /** * Compute the locale status value * @return the local status value diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt index 0d29137289..a84a10f74c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt @@ -168,6 +168,7 @@ class VectorSettingsPreferencesFragment @Inject constructor( v.setOnClickListener { dialog.dismiss() FontScale.updateFontScale(activity, i) + vectorConfiguration.applyToApplicationContext() activity.restart() } } diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt index fd20007c99..df7cc4ba84 100644 --- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt @@ -26,11 +26,13 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.configuration.VectorConfiguration import im.vector.app.features.settings.VectorLocale import kotlinx.coroutines.launch class LocalePickerViewModel @AssistedInject constructor( - @Assisted initialState: LocalePickerViewState + @Assisted initialState: LocalePickerViewState, + private val vectorConfiguration: VectorConfiguration ) : VectorViewModel(initialState) { @AssistedInject.Factory @@ -70,6 +72,7 @@ class LocalePickerViewModel @AssistedInject constructor( private fun handleSelectLocale(action: LocalePickerAction.SelectLocale) { VectorLocale.saveApplicationLocale(action.locale) + vectorConfiguration.applyToApplicationContext() _viewEvents.post(LocalePickerViewEvents.RestartActivity) } } diff --git a/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt b/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt index ef806b55b4..d337b790a3 100644 --- a/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt +++ b/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt @@ -44,6 +44,12 @@ object ThemeUtils { private val mColorByAttr = HashMap() + // init the theme + fun init(context: Context) { + val theme = getApplicationTheme(context) + setApplicationTheme(context, theme) + } + /** * @return true if current theme is Light or Status */ From cb7a1bc9c302752d73237fb91a083adcfa7e6a6b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 24 Aug 2020 18:20:09 +0200 Subject: [PATCH 07/13] Fix FontSize issue (#1483, #1787) --- CHANGES.md | 1 + .../app/core/platform/VectorBaseActivity.kt | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1bde8a7dfd..ca35023ede 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ Improvements 🙌: Bugfix 🐛: - Display name not shown under Settings/General (#1926) - Fix changing language issue + - Fix FontSize issue (#1483, #1787) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 856e84ea14..bedb02949f 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -76,6 +76,7 @@ import im.vector.app.features.rageshake.BugReportActivity import im.vector.app.features.rageshake.BugReporter import im.vector.app.features.rageshake.RageShake import im.vector.app.features.session.SessionListener +import im.vector.app.features.settings.FontScale import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.themes.ThemeUtils @@ -219,6 +220,9 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { doBeforeSetContentView() + // Hack for font size + applyFontSize() + if (getLayoutRes() != -1) { setContentView(getLayoutRes()) } @@ -239,6 +243,16 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { } } + /** + * This method has to be called for the font size setting be supported correctly. + */ + private fun applyFontSize() { + resources.configuration.fontScale = FontScale.getFontScaleValue(this).scale + + @Suppress("DEPRECATION") + resources.updateConfiguration(resources.configuration, resources.displayMetrics) + } + private fun handleGlobalError(globalError: GlobalError) { when (globalError) { is GlobalError.InvalidToken -> @@ -302,10 +316,10 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PinActivity.PIN_REQUEST_CODE) { when (resultCode) { - Activity.RESULT_OK -> { + Activity.RESULT_OK -> { pinLocker.unlock() } - else -> { + else -> { pinLocker.block() moveTaskToBack(true) } From 776d892d27a8e2583b03c912f1d58bb12c7a7cdc Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 26 Aug 2020 12:27:12 +0300 Subject: [PATCH 08/13] Increase version of uCrop library which supports Android 10. --- CHANGES.md | 1 + vector/build.gradle | 2 +- .../im/vector/app/features/media/BigImageViewerActivity.kt | 4 +--- .../im/vector/app/features/roomprofile/RoomProfileFragment.kt | 4 +--- .../app/features/settings/VectorSettingsGeneralFragment.kt | 3 +-- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d3a16c9b29..0ab511820a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Improvements 🙌: Bugfix 🐛: - Display name not shown under Settings/General (#1926) + - Change user or room avatar: when selecting Gallery, I'm not proposed to crop the selected image (#1590) Translations 🗣: - diff --git a/vector/build.gradle b/vector/build.gradle index c04de62367..ef2d6c3d9e 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -378,7 +378,7 @@ dependencies { implementation "com.github.bumptech.glide:glide:$glide_version" kapt "com.github.bumptech.glide:compiler:$glide_version" implementation 'com.danikula:videocache:2.7.1' - implementation 'com.github.yalantis:ucrop:2.2.4' + implementation 'com.github.yalantis:ucrop:2.2.6' // Badge for compatibility implementation 'me.leolin:ShortcutBadger:1.1.22@aar' diff --git a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt index 9d0a931a32..c619b4aa92 100644 --- a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt @@ -144,9 +144,7 @@ class BigImageViewerActivity : VectorBaseActivity() { .get(MultiPicker.IMAGE) .getSelectedFiles(this, requestCode, resultCode, data) .firstOrNull()?.let { - // TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is. - // onRoomAvatarSelected(it) - onAvatarCropped(it.contentUri) + onRoomAvatarSelected(it) } } UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 2722d54950..075ba1bc10 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -301,9 +301,7 @@ class RoomProfileFragment @Inject constructor( .get(MultiPicker.IMAGE) .getSelectedFiles(requireContext(), requestCode, resultCode, data) .firstOrNull()?.let { - // TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is. - // onRoomAvatarSelected(it) - onAvatarCropped(it.contentUri) + onRoomAvatarSelected(it) } } UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index 31de5ddd67..e31b81b162 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -356,8 +356,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { .get(MultiPicker.IMAGE) .getSelectedFiles(requireContext(), requestCode, resultCode, data) .firstOrNull()?.let { - // TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is. - onAvatarCropped(it.contentUri) + onAvatarSelected(it) } } UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) } From d014872e3b06c024be4005ec161b81136f637529 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Aug 2020 11:57:27 +0200 Subject: [PATCH 09/13] Add long click gesture to copy userId, user display name, room name, room topic and room alias (#1774) --- CHANGES.md | 2 +- .../im/vector/app/core/extensions/TextView.kt | 17 +++++++++++++++++ .../RoomMemberProfileFragment.kt | 11 +++++++++-- .../roomprofile/RoomProfileFragment.kt | 18 +++++++++++++----- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a9f2e896aa..2135401efb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features ✨: - Improvements 🙌: - - + - Add long click gesture to copy userId, user display name, room name, room topic and room alias (#1774) Bugfix 🐛: - Display name not shown under Settings/General (#1926) diff --git a/vector/src/main/java/im/vector/app/core/extensions/TextView.kt b/vector/src/main/java/im/vector/app/core/extensions/TextView.kt index cafcf6d1d8..44b85df93a 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/TextView.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/TextView.kt @@ -24,7 +24,9 @@ import android.widget.TextView import androidx.annotation.AttrRes import androidx.annotation.StringRes import androidx.core.view.isVisible +import com.google.android.material.snackbar.Snackbar import im.vector.app.R +import im.vector.app.core.utils.copyToClipboard import im.vector.app.features.themes.ThemeUtils /** @@ -68,3 +70,18 @@ fun TextView.setTextWithColoredPart(@StringRes fullTextRes: Int, } } } + +/** + * Set long click listener to copy the current text of the TextView to the clipboard and show a Snackbar + */ +fun TextView.copyOnLongClick() { + setOnLongClickListener { view -> + (view as? TextView) + ?.text + ?.let { text -> + copyToClipboard(view.context, text, false) + Snackbar.make(view, view.resources.getString(R.string.copied_to_clipboard), Snackbar.LENGTH_SHORT).show() + } + true + } +} diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt index 9c6e813f0b..cda2d83e3d 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -35,6 +35,7 @@ import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener import im.vector.app.core.dialogs.ConfirmationDialogBuilder import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith +import im.vector.app.core.extensions.copyOnLongClick import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.StateView @@ -44,11 +45,11 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheet import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs -import org.matrix.android.sdk.api.session.room.powerlevels.Role -import org.matrix.android.sdk.api.util.MatrixItem import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_matrix_profile.* import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.* +import org.matrix.android.sdk.api.session.room.powerlevels.Role +import org.matrix.android.sdk.api.util.MatrixItem import javax.inject.Inject @Parcelize @@ -110,6 +111,12 @@ class RoomMemberProfileFragment @Inject constructor( is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit }.exhaustive } + setupLongClicks() + } + + private fun setupLongClicks() { + memberProfileNameView.copyOnLongClick() + memberProfileIdView.copyOnLongClick() } private fun handleShowPowerLevelDemoteWarning(event: RoomMemberProfileViewEvents.ShowPowerLevelDemoteWarning) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 2722d54950..518932fdcb 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -34,16 +34,12 @@ import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.yalantis.ucrop.UCrop -import im.vector.lib.multipicker.MultiPicker -import im.vector.lib.multipicker.entity.MultiPickerImageType -import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState -import org.matrix.android.sdk.api.util.MatrixItem -import org.matrix.android.sdk.api.util.toMatrixItem import im.vector.app.R import im.vector.app.core.animations.AppBarStateChangeListener import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith +import im.vector.app.core.extensions.copyOnLongClick import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.intent.getFilenameFromUri @@ -62,9 +58,14 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.media.BigImageViewerActivity import im.vector.app.features.media.createUCropWithDefaultSettings +import im.vector.lib.multipicker.MultiPicker +import im.vector.lib.multipicker.entity.MultiPickerImageType import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_matrix_profile.* import kotlinx.android.synthetic.main.view_stub_room_profile_header.* +import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState +import org.matrix.android.sdk.api.util.MatrixItem +import org.matrix.android.sdk.api.util.toMatrixItem import timber.log.Timber import java.io.File import javax.inject.Inject @@ -120,6 +121,13 @@ class RoomProfileFragment @Inject constructor( .observe() .subscribe { handleQuickActions(it) } .disposeOnDestroyView() + setupLongClicks() + } + + private fun setupLongClicks() { + roomProfileNameView.copyOnLongClick() + roomProfileAliasView.copyOnLongClick() + roomProfileTopicView.copyOnLongClick() } override fun onOptionsItemSelected(item: MenuItem): Boolean { From ef912e066bafabc909d17a10dcb6d0d18d3f6953 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Aug 2020 12:29:46 +0200 Subject: [PATCH 10/13] Remove unused resource --- .../disclaimer_top_banner_foreground.xml | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 vector/src/main/res/drawable/disclaimer_top_banner_foreground.xml diff --git a/vector/src/main/res/drawable/disclaimer_top_banner_foreground.xml b/vector/src/main/res/drawable/disclaimer_top_banner_foreground.xml deleted file mode 100644 index c031da1e5b..0000000000 --- a/vector/src/main/res/drawable/disclaimer_top_banner_foreground.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - From 9f3f981ab07fdf0813b860415949a459cc585a09 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Aug 2020 12:30:26 +0200 Subject: [PATCH 11/13] Use cached Views --- .../im/vector/app/core/preference/PushRulePreference.kt | 3 +-- .../app/core/preference/VectorEditTextPreference.kt | 2 +- .../im/vector/app/core/preference/VectorPreference.kt | 8 ++++---- .../app/core/preference/VectorPreferenceCategory.kt | 2 +- .../vector/app/core/preference/VectorSwitchPreference.kt | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt b/vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt index 87584a9db0..9c4878ef06 100755 --- a/vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt +++ b/vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt @@ -20,7 +20,6 @@ import android.content.Context import android.util.AttributeSet import android.view.View import android.widget.RadioGroup -import android.widget.TextView import androidx.preference.PreferenceViewHolder import im.vector.app.R import org.matrix.android.sdk.api.pushrules.RuleSetKey @@ -162,7 +161,7 @@ class PushRulePreference : VectorPreference { override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) - holder.itemView.findViewById(android.R.id.summary)?.visibility = View.GONE + holder.findViewById(android.R.id.summary)?.visibility = View.GONE holder.itemView.setOnClickListener(null) holder.itemView.setOnLongClickListener(null) diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorEditTextPreference.kt b/vector/src/main/java/im/vector/app/core/preference/VectorEditTextPreference.kt index 840e5fa510..348fcffc9b 100644 --- a/vector/src/main/java/im/vector/app/core/preference/VectorEditTextPreference.kt +++ b/vector/src/main/java/im/vector/app/core/preference/VectorEditTextPreference.kt @@ -45,7 +45,7 @@ class VectorEditTextPreference : EditTextPreference { override fun onBindViewHolder(holder: PreferenceViewHolder) { // display the title in multi-line to avoid ellipsis. try { - holder.itemView.findViewById(android.R.id.title)?.isSingleLine = false + (holder.findViewById(android.R.id.title) as? TextView)?.isSingleLine = false } catch (e: Exception) { Timber.e(e, "onBindView") } diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt b/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt index 4a9bb6a6f5..dd887dba67 100755 --- a/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt +++ b/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt @@ -84,15 +84,15 @@ open class VectorPreference : Preference { // display the title in multi-line to avoid ellipsis. try { - val title = itemView.findViewById(android.R.id.title) - val summary = itemView.findViewById(android.R.id.summary) + val title = holder.findViewById(android.R.id.title) as? TextView + val summary = holder.findViewById(android.R.id.summary) as? TextView if (title != null) { title.isSingleLine = false title.setTypeface(null, mTypeface) } - if (title !== summary) { - summary.setTypeface(null, mTypeface) + summary?.setTypeface(null, mTypeface) + } // cancel existing animation (find a way to resume if happens during anim?) diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorPreferenceCategory.kt b/vector/src/main/java/im/vector/app/core/preference/VectorPreferenceCategory.kt index e61cde8ebd..eb59da640d 100644 --- a/vector/src/main/java/im/vector/app/core/preference/VectorPreferenceCategory.kt +++ b/vector/src/main/java/im/vector/app/core/preference/VectorPreferenceCategory.kt @@ -45,7 +45,7 @@ class VectorPreferenceCategory : PreferenceCategory { override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) - val titleTextView = holder.itemView.findViewById(android.R.id.title) + val titleTextView = holder.findViewById(android.R.id.title) as? TextView titleTextView?.setTypeface(null, Typeface.BOLD) titleTextView?.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_primary)) diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorSwitchPreference.kt b/vector/src/main/java/im/vector/app/core/preference/VectorSwitchPreference.kt index c97991bfcb..346e8488b9 100644 --- a/vector/src/main/java/im/vector/app/core/preference/VectorSwitchPreference.kt +++ b/vector/src/main/java/im/vector/app/core/preference/VectorSwitchPreference.kt @@ -58,7 +58,7 @@ class VectorSwitchPreference : SwitchPreference { override fun onBindViewHolder(holder: PreferenceViewHolder) { // display the title in multi-line to avoid ellipsis. - holder.itemView.findViewById(android.R.id.title)?.isSingleLine = false + (holder.findViewById(android.R.id.title) as? TextView)?.isSingleLine = false // cancel existing animation (find a way to resume if happens during anim?) currentHighlightAnimator?.cancel() From 249f268fb52b949926a1dad4089b8d27547453bb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Aug 2020 12:55:49 +0200 Subject: [PATCH 12/13] Fix bad color for settings icon on Android < 24 (#1786) --- CHANGES.md | 1 + .../app/core/preference/VectorPreference.kt | 17 +++++++++++++++++ .../settings/VectorSettingsRootFragment.kt | 13 ++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index a9f2e896aa..f7682028e1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Improvements 🙌: Bugfix 🐛: - Display name not shown under Settings/General (#1926) + - Fix bad color for settings icon on Android < 24 (#1786) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt b/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt index dd887dba67..a40ddef6ab 100755 --- a/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt +++ b/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt @@ -20,12 +20,15 @@ import android.animation.Animator import android.animation.ArgbEvaluator import android.animation.ValueAnimator import android.content.Context +import android.content.res.ColorStateList import android.graphics.Color import android.graphics.Typeface import android.util.AttributeSet import android.view.View +import android.widget.ImageView import android.widget.TextView import androidx.core.animation.doOnEnd +import androidx.core.widget.ImageViewCompat import androidx.preference.Preference import androidx.preference.PreferenceViewHolder import im.vector.app.R @@ -76,6 +79,12 @@ open class VectorPreference : Preference { notifyChanged() } + var tintIcon = false + set(value) { + field = value + notifyChanged() + } + var currentHighlightAnimator: Animator? = null override fun onBindViewHolder(holder: PreferenceViewHolder) { @@ -93,6 +102,14 @@ open class VectorPreference : Preference { summary?.setTypeface(null, mTypeface) + if (tintIcon) { + // Tint icons (See #1786) + val icon = holder.findViewById(android.R.id.icon) as? ImageView + + icon?.let { + val color = ThemeUtils.getColor(context, R.attr.riotx_header_panel_text_secondary) + ImageViewCompat.setImageTintList(it, ColorStateList.valueOf(color)) + } } // cancel existing animation (find a way to resume if happens during anim?) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt index d2ec1a1543..3f3811ce76 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt @@ -16,7 +16,9 @@ package im.vector.app.features.settings +import android.os.Build import im.vector.app.R +import im.vector.app.core.preference.VectorPreference import javax.inject.Inject class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() { @@ -25,6 +27,15 @@ class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragm override val preferenceXmlRes = R.xml.vector_settings_root override fun bindPref() { - // Nothing to do + // Tint icon on API < 24 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + tintIcons() + } + } + + private fun tintIcons() { + for (i in 0 until preferenceScreen.preferenceCount) { + (preferenceScreen.getPreference(i) as? VectorPreference)?.let { it.tintIcon = true } + } } } From 25ea221d4727c1cbba6a29ce5a742db65c17cc4d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Aug 2020 15:28:48 +0200 Subject: [PATCH 13/13] Create a script to import SAS strings (#1909) It will be run at the next Weblate sync, since we have to remove previous translations --- CHANGES.md | 1 + tools/import_sas_strings.py | 103 ++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100755 tools/import_sas_strings.py diff --git a/CHANGES.md b/CHANGES.md index f48436d279..ab4a121c6a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,7 @@ Build 🧱: Other changes: - Use File extension functions to make code more concise (#1996) + - Create a script to import SAS strings (#1909) Changes in Element 1.0.5 (2020-08-21) =================================================== diff --git a/tools/import_sas_strings.py b/tools/import_sas_strings.py new file mode 100755 index 0000000000..faf4ed7080 --- /dev/null +++ b/tools/import_sas_strings.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2020 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import json +import os +import os.path +# Run `pip3 install requests` if not installed yet +import requests + +### Arguments + +parser = argparse.ArgumentParser(description='Download sas string from matrix-doc.') +parser.add_argument('-v', + '--verbose', + help="increase output verbosity.", + action="store_true") + +args = parser.parse_args() + +if args.verbose: + print("Argument:") + print(args) + +base_url = "https://raw.githubusercontent.com/matrix-org/matrix-doc/master/data-definitions/sas-emoji.json" + +print("Downloading " + base_url + "…") + +r0 = requests.get(base_url) +data0 = json.loads(r0.content.decode()) + +if args.verbose: + print("Json data:") + print(data0) + +print() + +# emoji -> translation +default = dict() +# Language -> emoji -> translation +cumul = dict() + +for emoji in data0: + description = emoji["description"] + if args.verbose: + print("Description: " + description) + default[description] = description + + for lang in emoji["translated_descriptions"]: + if args.verbose: + print("Lang: " + lang) + if not (lang in cumul): + cumul[lang] = dict() + cumul[lang][description] = emoji["translated_descriptions"][lang] + +if args.verbose: + print(default) + print(cumul) + +def write_file(file, dict): + print("Writing file " + file) + if args.verbose: + print("With") + print(dict) + os.makedirs(os.path.dirname(file), exist_ok=True) + with open(file, mode="w", encoding="utf8") as o: + o.write("\n") + o.write("\n") + o.write(" \n") + for key in dict: + if dict[key] is None: + continue + o.write(" " + dict[key].replace("'", "\\'") + "\n") + o.write("\n") + +scripts_dir = os.path.dirname(os.path.abspath(__file__)) +data_defs_dir = os.path.join(scripts_dir, "../matrix-sdk-android/src/main/res") + +# Write default file +write_file(os.path.join(data_defs_dir, "values/strings_sas.xml"), default) + +# Write each language file +for lang in cumul: + androidLang = lang\ + .replace("_", "-r")\ + .replace("zh-rHans", "zh-rCN") + write_file(os.path.join(data_defs_dir, "values-" + androidLang + "/strings_sas.xml"), cumul[lang]) + +print() +print("Success!")