From d52f3ab5868f2a1c4eeb5c05dfa19b308a1d9921 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Wed, 3 Aug 2022 14:21:44 +0100 Subject: [PATCH 001/485] Clarify that an FCM Rewrite Proxy is not necessary --- docs/unifiedpush.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/unifiedpush.md b/docs/unifiedpush.md index 2851644e66..9f44c6b2f9 100644 --- a/docs/unifiedpush.md +++ b/docs/unifiedpush.md @@ -18,7 +18,7 @@ The recently started UnifiedPush project is an Android protocol and library for The *F-Droid* and *Gplay* flavors of Element Android support UnifiedPush, so the user can use any distributor installed on their devices. This would make it possible to have push notifications without depending on Google services or libraries. Currently, the main distributors are [ntfy](https://ntfy.sh) which does not require any setup (like manual registration) to use the public server and [NextPush](https://github.com/UP-NextPush/android), available as a nextcloud application. -The *Gplay* variant uses a UnifiedPush library which basically embed a FCM distributor built into the application (so a user doesn't need to do anything other than install the app to get FCM notifications). This variant uses Google Services to receive notifications if the user has not installed any distributor. +The *Gplay* variant uses a UnifiedPush library which basically embed a FCM distributor built into the application (so a user doesn't need to do anything other than install the app to get FCM notifications). This variant uses Google Services to receive notifications if the user has not installed any distributor. A [FCM Rewrite Proxy](https://unifiedpush.org/developers/embedded_fcm/#fcm-rewrite-proxy) is not required for Element Android's implementation of the FCM distributor - it will work with an existing Matrix push provider, such as [Sygnal](https://github.com/matrix-org/sygnal). The *F-Droid* variant does not use this library to avoid any proprietary blob. It will use a polling service if the user has not installed any distributor. From e00a9a10fb1d1fe79e781b346b73705f5ca9f28c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Aug 2022 14:26:19 +0100 Subject: [PATCH 002/485] changelog --- changelog.d/6727.doc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6727.doc diff --git a/changelog.d/6727.doc b/changelog.d/6727.doc new file mode 100644 index 0000000000..ab65e7a5b7 --- /dev/null +++ b/changelog.d/6727.doc @@ -0,0 +1 @@ +Clarify that setting up a FCM Rewrite Proxy is not necessary for use of the UnifiedPush FCM distributor. From d130dd5e1b541be577dc4c31281f2703e7cd44fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Aug 2022 23:09:05 +0000 Subject: [PATCH 003/485] Bump com.autonomousapps.dependency-analysis from 1.12.0 to 1.13.1 Bumps com.autonomousapps.dependency-analysis from 1.12.0 to 1.13.1. --- updated-dependencies: - dependency-name: com.autonomousapps.dependency-analysis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index aa8a3e2c4c..1db97c69e9 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ plugins { id "io.gitlab.arturbosch.detekt" version "1.21.0" // Dependency Analysis - id 'com.autonomousapps.dependency-analysis' version "1.12.0" + id 'com.autonomousapps.dependency-analysis' version "1.13.1" } // https://github.com/jeremylong/DependencyCheck From 02d54878c315e765d0264d951caedf1752d3a012 Mon Sep 17 00:00:00 2001 From: sim Date: Wed, 24 Aug 2022 22:50:08 +0200 Subject: [PATCH 005/485] Set distributor dialog always cancelable ATM, it uses the default fallback if cancelled --- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 0993485471..de5b881029 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -104,8 +104,7 @@ class UnifiedPushHelper @Inject constructor( pushersManager = pushersManager, onDoneRunnable = onDoneRunnable, distributors = distributors, - unregisterFirst = force, - cancellable = !force + unregisterFirst = force ) } } @@ -122,7 +121,6 @@ class UnifiedPushHelper @Inject constructor( pushersManager, onDoneRunnable, distributors, unregisterFirst = true, - cancellable = true, ) } @@ -132,7 +130,6 @@ class UnifiedPushHelper @Inject constructor( onDoneRunnable: Runnable?, distributors: List, unregisterFirst: Boolean, - cancellable: Boolean, ) { val internalDistributorName = stringProvider.getString( if (fcmHelper.isFirebaseAvailable()) { @@ -176,7 +173,7 @@ class UnifiedPushHelper @Inject constructor( UnifiedPush.registerApp(context) onDoneRunnable?.run() } - .setCancelable(cancellable) + .setCancelable(true) .show() } From a4dd08ddb33f97e4e1bd92bd1eeb32a041698898 Mon Sep 17 00:00:00 2001 From: sim Date: Wed, 24 Aug 2022 23:08:19 +0200 Subject: [PATCH 006/485] Always use register to open the distributor dialog The forced unregistration always happens in register function --- .../app/core/pushers/UnifiedPushHelper.kt | 41 +++++++------------ ...rSettingsNotificationPreferenceFragment.kt | 2 +- .../TestEndpointAsTokenRegistration.kt | 2 +- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index de5b881029..ec646440b6 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -46,6 +46,7 @@ class UnifiedPushHelper @Inject constructor( private val vectorFeatures: VectorFeatures, private val fcmHelper: FcmHelper, ) { + fun register( activity: FragmentActivity, onDoneRunnable: Runnable? = null, @@ -56,7 +57,14 @@ class UnifiedPushHelper @Inject constructor( ) } - fun reRegister( + // If registration is forced: + // * the current distributor (if any) is removed + // * The dialog is opened + // + // The registration is forced in 2 cases : + // * in the settings + // * in the troubleshoot list (doFix) + fun forceRegister( activity: FragmentActivity, pushersManager: PushersManager, onDoneRunnable: Runnable? = null @@ -86,7 +94,8 @@ class UnifiedPushHelper @Inject constructor( // Un-register first unregister(pushersManager) } - if (UnifiedPush.getDistributor(context).isNotEmpty()) { + // the !force should not be needed + if (!force && UnifiedPush.getDistributor(context).isNotEmpty()) { UnifiedPush.registerApp(context) onDoneRunnable?.run() return@launch @@ -94,42 +103,24 @@ class UnifiedPushHelper @Inject constructor( val distributors = UnifiedPush.getDistributors(context) - if (distributors.size == 1 && !force) { + if (!force && distributors.size == 1) { UnifiedPush.saveDistributor(context, distributors.first()) UnifiedPush.registerApp(context) onDoneRunnable?.run() } else { openDistributorDialogInternal( activity = activity, - pushersManager = pushersManager, onDoneRunnable = onDoneRunnable, - distributors = distributors, - unregisterFirst = force + distributors = distributors ) } } } - fun openDistributorDialog( - activity: FragmentActivity, - pushersManager: PushersManager, - onDoneRunnable: Runnable, - ) { - val distributors = UnifiedPush.getDistributors(activity) - openDistributorDialogInternal( - activity, - pushersManager, - onDoneRunnable, distributors, - unregisterFirst = true, - ) - } - private fun openDistributorDialogInternal( activity: FragmentActivity, - pushersManager: PushersManager?, onDoneRunnable: Runnable?, - distributors: List, - unregisterFirst: Boolean, + distributors: List ) { val internalDistributorName = stringProvider.getString( if (fcmHelper.isFirebaseAvailable()) { @@ -157,10 +148,6 @@ class UnifiedPushHelper @Inject constructor( } activity.lifecycleScope.launch { - if (unregisterFirst) { - // Un-register first - unregister(pushersManager) - } UnifiedPush.saveDistributor(context, distributor) Timber.i("Saving distributor: $distributor") UnifiedPush.registerApp(context) diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index a09bb1e6a4..ab25f83a91 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -158,7 +158,7 @@ class VectorSettingsNotificationPreferenceFragment : if (vectorFeatures.allowExternalUnifiedPushDistributors()) { it.summary = unifiedPushHelper.getCurrentDistributorName() it.onPreferenceClickListener = Preference.OnPreferenceClickListener { - unifiedPushHelper.openDistributorDialog(requireActivity(), pushersManager) { + unifiedPushHelper.forceRegister(requireActivity(), pushersManager) { it.summary = unifiedPushHelper.getCurrentDistributorName() session.pushersService().refreshPushers() refreshBackgroundSyncPrefs() diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt index 66222f759e..7875e3a21d 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt @@ -60,7 +60,7 @@ class TestEndpointAsTokenRegistration @Inject constructor( ) quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_endpoint_registration_quick_fix) { override fun doFix() { - unifiedPushHelper.reRegister( + unifiedPushHelper.forceRegister( context, pushersManager ) From 42c580c249a753603eed224087bdb578e4e53305 Mon Sep 17 00:00:00 2001 From: sim Date: Thu, 25 Aug 2022 08:57:27 +0200 Subject: [PATCH 007/485] Add comments --- .../main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index ec646440b6..c65bc0db5c 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -47,6 +47,8 @@ class UnifiedPushHelper @Inject constructor( private val fcmHelper: FcmHelper, ) { + // Called when the home activity starts + // or when notifications are enabled fun register( activity: FragmentActivity, onDoneRunnable: Runnable? = null, @@ -117,6 +119,8 @@ class UnifiedPushHelper @Inject constructor( } } + // There is no case where this function is called + // with a saved distributor and/or a pusher private fun openDistributorDialogInternal( activity: FragmentActivity, onDoneRunnable: Runnable?, From e2646c3243551e32123ffb706046678b36401f10 Mon Sep 17 00:00:00 2001 From: sim Date: Thu, 25 Aug 2022 08:58:42 +0200 Subject: [PATCH 008/485] Remove never-matched if --- .../main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index c65bc0db5c..8d8c2d5097 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -146,10 +146,6 @@ class UnifiedPushHelper @Inject constructor( .setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) .setItems(distributorsName.toTypedArray()) { _, which -> val distributor = distributors[which] - if (distributor == UnifiedPush.getDistributor(context)) { - Timber.d("Same distributor selected again, no action") - return@setItems - } activity.lifecycleScope.launch { UnifiedPush.saveDistributor(context, distributor) From f7ae377874e561cbb31dd80443b83195a74816a3 Mon Sep 17 00:00:00 2001 From: sim Date: Thu, 25 Aug 2022 09:33:26 +0200 Subject: [PATCH 009/485] Add changelog Signed-off-by: sim --- changelog.d/6936.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6936.misc diff --git a/changelog.d/6936.misc b/changelog.d/6936.misc new file mode 100644 index 0000000000..f032ad9805 --- /dev/null +++ b/changelog.d/6936.misc @@ -0,0 +1 @@ +Smaff refactor of UnifiedPushHelper From 50034599628a320ca7ea32ef5f6a4a31ebf515e1 Mon Sep 17 00:00:00 2001 From: NIkita Fedrunov Date: Thu, 1 Sep 2022 14:39:13 +0200 Subject: [PATCH 010/485] empty state for new invites screen --- changelog.d/6876.feature | 1 + .../room/list/home/invites/InvitesFragment.kt | 43 ++++++++++----- .../list/home/invites/InvitesViewEvents.kt | 1 - .../list/home/invites/InvitesViewModel.kt | 53 +++++++++++++++---- .../list/home/invites/InvitesViewState.kt | 15 +++++- .../main/res/drawable/ic_invites_empty.xml | 14 +++++ .../src/main/res/layout/fragment_invites.xml | 21 +++++--- vector/src/main/res/values/strings.xml | 3 ++ 8 files changed, 117 insertions(+), 34 deletions(-) create mode 100644 changelog.d/6876.feature create mode 100644 vector/src/main/res/drawable/ic_invites_empty.xml diff --git a/changelog.d/6876.feature b/changelog.d/6876.feature new file mode 100644 index 0000000000..12a2b78a1e --- /dev/null +++ b/changelog.d/6876.feature @@ -0,0 +1 @@ +[App Layout] - Invites now show empty screen after you reject last invite diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt index 74b46cec33..7fbc6f5c3f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt @@ -20,15 +20,19 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope +import androidx.paging.PagedList import com.airbnb.mvrx.fragmentViewModel -import com.airbnb.mvrx.withState import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.configureWith +import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentInvitesBinding import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.home.room.list.RoomListListener import im.vector.app.features.notifications.NotificationDrawerManager +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo import javax.inject.Inject @@ -51,6 +55,8 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi setupToolbar(views.invitesToolbar) .allowBack() + views.invitesStateView.contentView = views.invitesRecycler + views.invitesRecycler.configureWith(controller) controller.listener = this @@ -62,13 +68,32 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi when (it) { is InvitesViewEvents.Failure -> showFailure(it.throwable) is InvitesViewEvents.OpenRoom -> handleOpenRoom(it.roomSummary, it.shouldCloseInviteView) - InvitesViewEvents.Close -> handleClose() } } - } - private fun handleClose() { - requireActivity().finish() + viewModel.invites.onEach { + when (it) { + is InvitesContentState.Content -> { + views.invitesStateView.state = StateView.State.Content + Suppress("UNCHECKED_CAST") + controller.submitList(it.content as? PagedList) + } + is InvitesContentState.Empty -> { + views.invitesStateView.state = StateView.State.Empty( + title = it.title, + image = it.image, + message = it.message + ) + } + is InvitesContentState.Error -> { + when (views.invitesStateView.state) { + StateView.State.Content -> showErrorInSnackbar(it.throwable) + else -> views.invitesStateView.state = StateView.State.Error(it.throwable.message) + } + } + InvitesContentState.Loading -> views.invitesStateView.state = StateView.State.Loading + } + }.launchIn(viewLifecycleOwner.lifecycleScope) } private fun handleOpenRoom(roomSummary: RoomSummary, shouldCloseInviteView: Boolean) { @@ -83,14 +108,6 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi } } - override fun invalidate(): Unit = withState(viewModel) { state -> - super.invalidate() - - state.pagedList?.observe(viewLifecycleOwner) { list -> - controller.submitList(list) - } - } - override fun onRejectRoomInvitation(room: RoomSummary) { notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) } viewModel.handle(InvitesAction.RejectInvitation(room)) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt index d68577cf95..21310592a4 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt @@ -22,5 +22,4 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary sealed class InvitesViewEvents : VectorViewEvents { data class Failure(val throwable: Throwable) : InvitesViewEvents() data class OpenRoom(val roomSummary: RoomSummary, val shouldCloseInviteView: Boolean) : InvitesViewEvents() - object Close : InvitesViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt index b0d854be66..1e5880d772 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt @@ -16,14 +16,25 @@ package im.vector.app.features.home.room.list.home.invites +import androidx.lifecycle.asFlow import androidx.paging.PagedList import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.R import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.resources.DrawableProvider +import im.vector.app.core.resources.StringProvider +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session @@ -36,6 +47,8 @@ import timber.log.Timber class InvitesViewModel @AssistedInject constructor( @Assisted val initialState: InvitesViewState, private val session: Session, + private val stringProvider: StringProvider, + private val drawableProvider: DrawableProvider ) : VectorViewModel(initialState) { private val pagedListConfig = PagedList.Config.Builder() @@ -52,6 +65,11 @@ class InvitesViewModel @AssistedInject constructor( companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + private val _invites = MutableSharedFlow(replay = 1) + val invites = _invites.asSharedFlow() + + var invitesCount = -1 + init { observeInvites() } @@ -72,8 +90,6 @@ class InvitesViewModel @AssistedInject constructor( return@withState } - val shouldCloseInviteView = state.pagedList?.value?.size == 1 - viewModelScope.launch { try { session.roomService().leaveRoom(roomId) @@ -81,9 +97,6 @@ class InvitesViewModel @AssistedInject constructor( // Instead, we wait for the room to be rejected // Known bug: if the user is invited again (after rejecting the first invitation), the loading will be displayed instead of the buttons. // If we update the state, the button will be displayed again, so it's not ideal... - if (shouldCloseInviteView) { - _viewEvents.post(InvitesViewEvents.Close) - } } catch (failure: Throwable) { // Notify the user _viewEvents.post(InvitesViewEvents.Failure(failure)) @@ -101,9 +114,7 @@ class InvitesViewModel @AssistedInject constructor( } // close invites view when navigate to a room from the last one invite - val shouldCloseInviteView = state.pagedList?.value?.size == 1 - - _viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView)) + val shouldCloseInviteView = invitesCount == 1 // quick echo setState { @@ -117,6 +128,8 @@ class InvitesViewModel @AssistedInject constructor( } ) } + + _viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView)) } private fun observeInvites() { @@ -129,8 +142,26 @@ class InvitesViewModel @AssistedInject constructor( sortOrder = RoomSortOrder.ACTIVITY ) - setState { - copy(pagedList = pagedList) - } + pagedList.asFlow() + .map { + if (it.isEmpty()) { + InvitesContentState.Empty( + title = stringProvider.getString(R.string.invites_empty_title), + image = drawableProvider.getDrawable(R.drawable.ic_invites_empty), + message = stringProvider.getString(R.string.invites_empty_message) + ) + } else { + invitesCount = it.loadedCount + InvitesContentState.Content(it) + } + } + .catch { + emit(InvitesContentState.Error(it)) + } + .onStart { + emit(InvitesContentState.Loading) + }.onEach { + _invites.emit(it) + }.launchIn(viewModelScope) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt index 708db29604..397042a96a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt @@ -16,13 +16,24 @@ package im.vector.app.features.home.room.list.home.invites -import androidx.lifecycle.LiveData +import android.graphics.drawable.Drawable import androidx.paging.PagedList import com.airbnb.mvrx.MavericksState import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.RoomSummary data class InvitesViewState( - val pagedList: LiveData>? = null, val roomMembershipChanges: Map = emptyMap(), ) : MavericksState + +sealed class InvitesContentState { + object Loading : InvitesContentState() + data class Empty( + val title: CharSequence, + val image: Drawable?, + val message: CharSequence + ) : InvitesContentState() + + data class Content(val content: PagedList) : InvitesContentState() + data class Error(val throwable: Throwable) : InvitesContentState() +} diff --git a/vector/src/main/res/drawable/ic_invites_empty.xml b/vector/src/main/res/drawable/ic_invites_empty.xml new file mode 100644 index 0000000000..79908ff380 --- /dev/null +++ b/vector/src/main/res/drawable/ic_invites_empty.xml @@ -0,0 +1,14 @@ + + + + diff --git a/vector/src/main/res/layout/fragment_invites.xml b/vector/src/main/res/layout/fragment_invites.xml index 74226357c9..070cad5ec8 100644 --- a/vector/src/main/res/layout/fragment_invites.xml +++ b/vector/src/main/res/layout/fragment_invites.xml @@ -20,17 +20,24 @@ - + app:layout_constraintTop_toBottomOf="@id/appBarLayout"> + + + + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index f8eb4b8de0..178feb2223 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -445,6 +445,9 @@ Invites + Nothing new. + This is where your new requests and invites will be. + Conversations Matrix contacts only From deaf6984c14a893311f251e39575e51f00d49f92 Mon Sep 17 00:00:00 2001 From: waclaw66 Date: Thu, 1 Sep 2022 13:47:11 +0000 Subject: [PATCH 011/485] Translated using Weblate (Czech) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/cs/ --- fastlane/metadata/android/cs-CZ/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/cs-CZ/changelogs/40104340.txt diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40104340.txt b/fastlane/metadata/android/cs-CZ/changelogs/40104340.txt new file mode 100644 index 0000000000..578549ce6c --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: Opravy různých chyb a vylepšení stability. +Úplný seznam změn: https://github.com/vector-im/element-android/releases From da7355049310179dc18dc982c429dd2105e68a33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 23:10:39 +0000 Subject: [PATCH 012/485] Bump android-embedded_fcm_distributor from 2.1.2 to 2.1.3 Bumps android-embedded_fcm_distributor from 2.1.2 to 2.1.3. --- updated-dependencies: - dependency-name: com.github.UnifiedPush:android-embedded_fcm_distributor dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vector/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/build.gradle b/vector/build.gradle index ee549fc4b6..51ee8b561c 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -264,7 +264,7 @@ dependencies { // UnifiedPush implementation 'com.github.UnifiedPush:android-connector:2.0.1' // UnifiedPush gplay flavor only - gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.2') { + gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.3') { exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' From 8535e3093782ed357c283820711a31c4ae8ef0fe Mon Sep 17 00:00:00 2001 From: "Auri B. P" Date: Thu, 1 Sep 2022 20:56:21 +0000 Subject: [PATCH 013/485] Translated using Weblate (Catalan) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/ --- .../src/main/res/values-ca/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-ca/strings.xml b/library/ui-strings/src/main/res/values-ca/strings.xml index 0c61cdf6c6..ce87e03658 100644 --- a/library/ui-strings/src/main/res/values-ca/strings.xml +++ b/library/ui-strings/src/main/res/values-ca/strings.xml @@ -2619,4 +2619,23 @@ Mostra totes les sessions (V2, WIP) Crea sala Inicia xat - + Amaga el contingut de l\'espai + Mostra el contingut de l\'espai + Verifica la teva sessió actual per a missatges segurs millorats. + Verificada · Última activitat %1$s + No verificada · Última activitat %1$s + Veure-ho tot (%1$d) + Sessió actual + Veure detalls + Verifica sessió + La sessió actual està llesta per la missatgeria segura. + Sessió no verificada + Sessió verificada + Tipus de dispositiu desconegut + Ordinador + Web + Mòbil + Aquesta sala no s\'ha trobat. +\nTorna-ho a provar més tard.%s + Invitacions + \ No newline at end of file From 578ff6bd442774e78f81f45e29ef9b3d0c9883c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Thu, 1 Sep 2022 21:02:20 +0000 Subject: [PATCH 014/485] Translated using Weblate (Estonian) Currently translated at 99.6% (2353 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/et/ --- .../src/main/res/values-et/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-et/strings.xml b/library/ui-strings/src/main/res/values-et/strings.xml index a476ec4b3a..bde744797c 100644 --- a/library/ui-strings/src/main/res/values-et/strings.xml +++ b/library/ui-strings/src/main/res/values-et/strings.xml @@ -2610,4 +2610,23 @@ Tutvu jututubadega Loo jututuba Alusta vestlust - + Verifitseerimata · Viimati kasutusel %1$s + Verifitseeritud · Viimati kasutusel %1$s + Näita kõiki (%1$d) + Praegune sessioon + Vaata lisateavet + Verifitseeri sessioon + Turvalise sõnumivahetuse nimel palun verifitseeri oma praegune sessioon. + Sinu praegune sessioon on valmis turvaliseks sõnumivahetuseks. + Verifitseerimata sessioon + Verifitseeritud sessioon + Tundmatu seadme tüüp + Töölauarakendus + Veebiliides + Mobiiltelefon + Vabandust, aga seda jututuba ei õnnestu leida. +\nPalun proovi hiljem uuesti.%s + Kutsed + Ahenda seotud kogukondade loend + Ava seotud kogukondade loend + \ No newline at end of file From cad23d147770bda2c6380c4c413f23dc4d1b028d Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Thu, 1 Sep 2022 22:26:53 +0000 Subject: [PATCH 015/485] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/uk/ --- .../src/main/res/values-uk/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-uk/strings.xml b/library/ui-strings/src/main/res/values-uk/strings.xml index 47f15c9a27..2b73664922 100644 --- a/library/ui-strings/src/main/res/values-uk/strings.xml +++ b/library/ui-strings/src/main/res/values-uk/strings.xml @@ -2719,4 +2719,23 @@ Знайти кімнати Створити кімнату Розпочати бесіду - + Не звірений · Остання активність %1$s + Звірений · Остання активність %1$s + Переглянути всі (%1$d) + Поточний сеанс + Переглянути подробиці + Звірити сеанс + Звірте свій поточний сеанс для безпечнішого обміну повідомленнями. + Ваш поточний сеанс готовий для безпечного обміну повідомленнями. + Не звірений сеанс + Звірений сеанс + Невідомий тип пристрою + Комп\'ютер + Браузер + Мобільний + Перепрошуємо, цю кімнату не знайдено. +\nСпробуйте пізніше.%s + Запрошення + Згорнути дочірні елементи простору + Розгорнути дочірні елементи простору + \ No newline at end of file From ec260fac1681ff44009512072ec442d55318559f Mon Sep 17 00:00:00 2001 From: phardyle Date: Thu, 1 Sep 2022 16:34:44 +0000 Subject: [PATCH 016/485] Translated using Weblate (Chinese (Simplified)) Currently translated at 99.7% (2356 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hans/ --- .../src/main/res/values-zh-rCN/strings.xml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-zh-rCN/strings.xml b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml index 6f7151167f..1862c67283 100644 --- a/library/ui-strings/src/main/res/values-zh-rCN/strings.xml +++ b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml @@ -2569,4 +2569,18 @@ 探索房间 创建房间 开始聊天 - + 抱歉,未发现此房间。 +\n请晚些重试。%s + 未验证 · 上次活跃 %1$s + 已验证 · 上次活跃 %1$s + 查看全部(%1$d) + 当前会话 + 查看详情 + 验证会话 + 为了获得增强的安全的消息传送,请验证你当前的会话。 + 你的当前会话已准备好安全地收发消息。 + 未验证的会话 + 已验证的会话 + 未知的设备类型 + 邀请 + \ No newline at end of file From e0e9fbc82045fdf29f464655cfa1bc293a94212f Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Sep 2022 02:42:37 +0000 Subject: [PATCH 017/485] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hant/ --- .../src/main/res/values-zh-rTW/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-zh-rTW/strings.xml b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml index 93b4a8d4c6..755d811089 100644 --- a/library/ui-strings/src/main/res/values-zh-rTW/strings.xml +++ b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml @@ -2569,4 +2569,23 @@ 探索聊天室 建立聊天室 開始聊天 - + 未驗證 · 最後活動 %1$s + 已驗證 · 最後活動 %1$s + 檢視全部 (%1$d) + 目前工作階段 + 檢視詳細資訊 + 驗證工作階段 + 驗證您目前的工作階段以強化安全通訊。 + 您目前的工作階段已準備好進行安全通訊。 + 未驗證的工作階段 + 已驗證的工作階段 + 未知的裝置類型 + 桌面 + 網頁 + 行動裝置 + 抱歉,找不到此聊天室。 +\n請稍後再試。%s + 邀請 + 折疊子空間 + 展開子空間 + \ No newline at end of file From 3c53a579a983ba7085acad27480e1ce62a587f02 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Thu, 1 Sep 2022 22:22:01 +0000 Subject: [PATCH 018/485] Translated using Weblate (Ukrainian) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/uk/ --- fastlane/metadata/android/uk/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/uk/changelogs/40104340.txt diff --git a/fastlane/metadata/android/uk/changelogs/40104340.txt b/fastlane/metadata/android/uk/changelogs/40104340.txt new file mode 100644 index 0000000000..9664c615c1 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Основні зміни в цій версії: Усунуто різні вади й поліпшено стабільність. +Перелік усіх змін: https://github.com/vector-im/element-android/releases From c302438b371c3b88995dc14e5ae32ccb47e9210e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Thu, 1 Sep 2022 20:52:38 +0000 Subject: [PATCH 019/485] Translated using Weblate (Estonian) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/et/ --- fastlane/metadata/android/et/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/et/changelogs/40104340.txt diff --git a/fastlane/metadata/android/et/changelogs/40104340.txt b/fastlane/metadata/android/et/changelogs/40104340.txt new file mode 100644 index 0000000000..1df5ac4176 --- /dev/null +++ b/fastlane/metadata/android/et/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Põhilised muutused selles versioonis: erinevate vigade parandused ja stabiilsust edendavad kohendused. +Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases From 9616cd41864873d6ade22ff7c4054f100416d18e Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Sep 2022 02:38:31 +0000 Subject: [PATCH 020/485] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/zh_Hant/ --- fastlane/metadata/android/zh-TW/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/zh-TW/changelogs/40104340.txt diff --git a/fastlane/metadata/android/zh-TW/changelogs/40104340.txt b/fastlane/metadata/android/zh-TW/changelogs/40104340.txt new file mode 100644 index 0000000000..4bcca9a0b8 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/40104340.txt @@ -0,0 +1,2 @@ +此版本中的主要變動:多個臭蟲修復與穩定性改善。 +完整的變更紀錄:https://github.com/vector-im/element-android/releases From ad360074bf523abd9b9017a2ab8c1c1ee87384ae Mon Sep 17 00:00:00 2001 From: Germain Date: Fri, 2 Sep 2022 15:54:08 +0100 Subject: [PATCH 021/485] Remove threads board automation The threads board has been closed and is now replaced by the Delight board --- .github/workflows/triage-labelled.yml | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/.github/workflows/triage-labelled.yml b/.github/workflows/triage-labelled.yml index f478d2bd7b..174e3c54c0 100644 --- a/.github/workflows/triage-labelled.yml +++ b/.github/workflows/triage-labelled.yml @@ -142,32 +142,6 @@ jobs: env: PROJECT_ID: "PN_kwDOAM0swc2KCw" GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} - - move_threads_issues: - name: A-Threads to Thread board - runs-on: ubuntu-latest - # Skip in forks - if: > - github.repository == 'vector-im/element-android' && - contains(github.event.issue.labels.*.name, 'A-Threads') - steps: - - uses: octokit/graphql-action@v2.x - with: - headers: '{"GraphQL-Features": "projects_next_graphql"}' - query: | - mutation add_to_project($projectid:ID!,$contentid:ID!) { - addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { - projectNextItem { - id - } - } - } - projectid: ${{ env.PROJECT_ID }} - contentid: ${{ github.event.issue.node_id }} - env: - PROJECT_ID: "PN_kwDOAM0swc0rRA" - GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} - move_message_bubbles_issues: name: A-Message-Bubbles to Message bubbles board runs-on: ubuntu-latest From 6917e97f49c98189aca03642aace85323b66ae52 Mon Sep 17 00:00:00 2001 From: Prat T Date: Sat, 3 Sep 2022 17:26:45 -0700 Subject: [PATCH 022/485] Suggest @room when @channel, @everyone, or @here is typed in composer (#6529) Signed-off-by: Prat T --- changelog.d/6529.feature | 1 + .../autocomplete/member/AutocompleteMemberPresenter.kt | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelog.d/6529.feature diff --git a/changelog.d/6529.feature b/changelog.d/6529.feature new file mode 100644 index 0000000000..dc51d1dad0 --- /dev/null +++ b/changelog.d/6529.feature @@ -0,0 +1 @@ +Suggest @room when @channel, @everyone, or @here is typed in composer \ No newline at end of file diff --git a/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt b/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt index a480b1c279..ff04a4db17 100644 --- a/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt +++ b/vector/src/main/java/im/vector/app/features/autocomplete/member/AutocompleteMemberPresenter.kt @@ -145,7 +145,12 @@ class AutocompleteMemberPresenter @AssistedInject constructor( private fun createEveryoneItem(query: CharSequence?) = room.roomSummary() ?.takeIf { canNotifyEveryone() } - ?.takeIf { query.isNullOrBlank() || MatrixItem.NOTIFY_EVERYONE.startsWith("@$query") } + ?.takeIf { + query.isNullOrBlank() || + SUGGEST_ROOM_KEYWORDS.any { + it.startsWith("@$query") + } + } ?.let { AutocompleteMemberItem.Everyone(it) } @@ -165,6 +170,7 @@ class AutocompleteMemberPresenter @AssistedInject constructor( companion object { private const val ID_HEADER_MEMBERS = "ID_HEADER_MEMBERS" private const val ID_HEADER_EVERYONE = "ID_HEADER_EVERYONE" + private val SUGGEST_ROOM_KEYWORDS = setOf(MatrixItem.NOTIFY_EVERYONE, "@channel", "@everyone", "@here") } } From 054802c02b346027d1da54620e628baae5289543 Mon Sep 17 00:00:00 2001 From: Vri Date: Fri, 2 Sep 2022 15:27:50 +0000 Subject: [PATCH 023/485] Translated using Weblate (German) Currently translated at 99.3% (2346 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/de/ --- .../src/main/res/values-de/strings.xml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/ui-strings/src/main/res/values-de/strings.xml b/library/ui-strings/src/main/res/values-de/strings.xml index 527b21ad56..8e502a6392 100644 --- a/library/ui-strings/src/main/res/values-de/strings.xml +++ b/library/ui-strings/src/main/res/values-de/strings.xml @@ -834,9 +834,9 @@ \nSitzungsname: %1$s \nZuletzt gesehen: %2$s \nWenn du nicht mit einer anderen Sitzung angemeldet bist, ignoriere diese Anfrage. - Eine unverifizierte Sitzung fordert Verschlüsselungs-Schlüssel an. -\nSitzungsname: %1$s -\nZuletzt gesehen: %2$s + Eine nicht verifizierte Sitzung fordert Verschlüsselungs-Schlüssel an. +\nSitzungsname: %1$s +\nZuletzt gesehen: %2$s \nWenn du nicht eine andere Sitzung angemeldet hast, ignoriere diese Anfrage. Teilen Ignorieren @@ -1426,7 +1426,7 @@ Wähle deinen Wiederherstellungsschlüssel, gib ihn ein oder füge ihn aus der Zwischenablage ein Konnte nicht auf gesicherten Speicher zugreifen Unverschlüsselt - Verschlüsselt von einem unbekannten Gerät + Verschlüsselt von einem nicht verifiziertem Gerät Überprüfe, wo du angemeldet bist Verifiziere alle deine Sitzungen, um sicherzustellen, dass dein Konto und deine Nachrichten sicher sind Bestätige neue Anmeldung zu deinem Konto: %1$s @@ -2614,4 +2614,12 @@ Kontakt aufnehmen Element Matrix Services (EMS) ist ein robuster und zuverlässiger Hosting-Dienst für schnelle und sichere Echtzeitkommunikation. Erfahre mehr unter element.io/ems Willst du deinen eigenen Server betreiben\? + Web + Mobil + Entschuldigung, dieser Raum wurde nicht gefunden. +\nBitte versuche es später erneut.%s + Einladungen + Nicht verifiziert · Letzte Aktivität %1$s + Verifiziere deine aktuelle Sitzung für besonders sichere Nachrichtenübertragung. + Nicht verifizierte Sitzung \ No newline at end of file From c3bac2f0cf1f72f8426c9bceb0c40cbd827af9f4 Mon Sep 17 00:00:00 2001 From: Danial Behzadi Date: Fri, 2 Sep 2022 16:24:48 +0000 Subject: [PATCH 024/485] Translated using Weblate (Persian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fa/ --- .../src/main/res/values-fa/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-fa/strings.xml b/library/ui-strings/src/main/res/values-fa/strings.xml index d1dbb57593..4671eab2cd 100644 --- a/library/ui-strings/src/main/res/values-fa/strings.xml +++ b/library/ui-strings/src/main/res/values-fa/strings.xml @@ -2619,4 +2619,23 @@ کاوش اتاق‌ها ایجاد اتاق آغاز گپ - + تأیید نشده · آخرین فعّالیت %1$s + تأیید شده · آخرین فعّالیت %1$s + دیدن همه (%1$d) + نشست کنونی + دیدن جزییات + تأیید نشست + نشست کنونیتان را برای پیام‌رسانی امن بهبود یافته تأیید کنید. + نشست کنونیتان برای پیام‌رسانی امن آماده است. + نشست تأیید نشده + نشست تأیید شده + گونهٔ افزاره ناشناخته + میزکار + وب + تلفن همراه + متأسفانه این اتاق پیدا نشد. +\nلطفاً بعداً دوباره تلاش کنید.%s + دعوت‌ها + جمع کردن فرزندان فضا + گسترش فرزندان فضا + \ No newline at end of file From 287e890f609933196418d43c8bed7ccae7a74557 Mon Sep 17 00:00:00 2001 From: Glandos Date: Fri, 2 Sep 2022 21:05:45 +0000 Subject: [PATCH 025/485] Translated using Weblate (French) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/ --- .../src/main/res/values-fr/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-fr/strings.xml b/library/ui-strings/src/main/res/values-fr/strings.xml index 0bc033c93a..c0a68b7d93 100644 --- a/library/ui-strings/src/main/res/values-fr/strings.xml +++ b/library/ui-strings/src/main/res/values-fr/strings.xml @@ -2619,4 +2619,23 @@ Parcourir les salons Créer un salon Commencer une discussion - + Non vérifiée · Dernière activité %1$s + Vérifié · Dernière activité %1$s + Tout voir (%1$d) + Cette session + Voir les détails + Vérifier la session + Vérifiez votre session pour une sécurité renforcée de votre messagerie. + Votre session est prête pour l’envoi de messages sécurisés. + Session non vérifiée + Session vérifiée + Type de périphérique inconnu + Ordinateur + Web + Portable + Désolé, impossible de trouver ce salon. +\nVeuillez réessayer plus tard.%s + Invitations + Réduire les enfants de l’espace + Développer les enfants de l’espace + \ No newline at end of file From db29ebb93d9e8e1bad1cac41d14c6e79d548cc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emese=20T=C3=B3th?= Date: Sun, 4 Sep 2022 08:13:40 +0000 Subject: [PATCH 026/485] Translated using Weblate (Hungarian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/hu/ --- .../src/main/res/values-hu/strings.xml | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/library/ui-strings/src/main/res/values-hu/strings.xml b/library/ui-strings/src/main/res/values-hu/strings.xml index a35595fb36..96c2d1f007 100644 --- a/library/ui-strings/src/main/res/values-hu/strings.xml +++ b/library/ui-strings/src/main/res/values-hu/strings.xml @@ -157,7 +157,7 @@ %s megváltoztatta a szerver ACL-eket ehhez a szobához. • IP címet hosztnévként használó szerverek tiltva vannak. • IP címet hosztnévként használó szerverek engedélyezve vannak. - • Engedélyezve vannak azok a szerverek, amik illeszkednek erre: %s + • Engedélyezve vannak azok a szerverek, amik illeszkednek erre: %s. • Tiltva vannak azok a szerverek, amik illeszkednek erre: %s Beállítottad a szerver ACL-eket ehhez a szobához. %s beállította a szerver ACL-eket ehhez a szobához. @@ -2600,4 +2600,42 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze %1$s és %2$s Minden beszélgetés - + Nem ellenőrzött - Utolsó aktivitás %1$s + Ellenőrzött - Utolsó tevékenység %1$s + Összes megtekintése (%1$d) + Jelenlegi munkamenet + Részletek megtekintése + Munkamenet hitelesítése + Az aktuális munkamenet készen áll a biztonságos üzenetküldésre. + Az aktuális munkamenet készen áll a biztonságos üzenetküldésre. + Ellenőrizetlen munkamenet + Ellenőrzött munkamenet + Ismeretlen eszköztípus + Asztali + Web + Mobil + Minden munkamenet megjelenítése (V2, WIP) + A legjobb biztonság érdekében ellenőrizd a munkameneteket, és jelentkezz ki minden olyan munkamenetből, melyet már nem ismersz fel vagy nem használsz. + Más munkamenetek + Munkamenetek + Nyitott területek listája + Új beszélgetés vagy szoba létrehozása + Résztvevők + Kedvencek + Olvasatlan + Mind + Sajnáljuk, ez a szoba nem található. +\nKérjük, próbáld meg később újra.%s + Meghívók + A - Z + Aktivitás + Rendezés + Legfrissebbek megjelenítése + Szűrők megjelenítése + Elrendezési beállítások + Alterem összeomlása + Az alterem bővítése + Szobák felfedezése + Szoba létrehozása + Chat indítása + \ No newline at end of file From b13546b096a60325a9fbd7ed09bc773549da21ec Mon Sep 17 00:00:00 2001 From: Linerly Date: Sat, 3 Sep 2022 14:41:59 +0000 Subject: [PATCH 027/485] Translated using Weblate (Indonesian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/id/ --- .../src/main/res/values-in/strings.xml | 145 ++++++++++-------- 1 file changed, 82 insertions(+), 63 deletions(-) diff --git a/library/ui-strings/src/main/res/values-in/strings.xml b/library/ui-strings/src/main/res/values-in/strings.xml index 031e13ed63..bd398f635f 100644 --- a/library/ui-strings/src/main/res/values-in/strings.xml +++ b/library/ui-strings/src/main/res/values-in/strings.xml @@ -47,8 +47,8 @@ Hanya kontak Matrix Ruangan Laporan kutu - Aplikasi gagal saat terakhir digunakan. Apakah Anda ingin membuka halaman laporan kegagalan\? - Gabung di Ruangan + Aplikasi mogok saat terakhir digunakan. Apakah Anda ingin membuka halaman laporan kemogokan\? + Bergabung ke Ruangan Mulai Panggilan Suara Masuk Mulai Panggilan Video @@ -69,7 +69,7 @@ TIDAK Lanjut Hapus - Gabung + Bergabung Tolak Nanti Kirim catatan gangguan @@ -88,7 +88,7 @@ Kirim tampilan layar Mohon uraikan kutu tersebut. Apa yang Anda lakukan\? Apa yang Anda harapkan terjadi\? Apa yang sebenarnya terjadi\? Catatan dari klien akan dikirim bersama laporan gangguan ini untuk mendalami kendala yang Anda temukan. Laporan gangguan ini, termasuk catatan dan tangkapan layar, tidak akan terlihat secara umum. Jika Anda hanya ingin mengirimkan tulisan di atas, silakan hapus centang: - Sepertinya Anda mengguncang ponsel akibat frustrasi. Apakah Anda ingin membuka halaman laporan kutu\? + Sepertinya Anda mengguncang ponsel akibat emosi. Apakah Anda ingin membuka halaman laporan kutu\? Pengiriman laporan kutu gagal (%s) Kemajuan (%s%%) Nama Pengguna @@ -122,9 +122,9 @@ Kirim Sticker Ambil foto Ambil video - Saat ini Anda belum memiliki pak stiker. + Saat ini Anda belum memiliki paket stiker apa pun. \n -\nMau tambah sekarang\? +\nIngin tambah sekarang\? Maaf, tidak ada aplikasi eksternal yang mendukung apa yang ingin dilakukan. Meminta ulang kunci enkripsi dari perangkat Anda yang lain. Jalankan ${app_name} di perangkat yang dapat mendekripsi pesan tersebut agar kunci dapat dikirim ke perangkat ini. @@ -146,8 +146,8 @@ Sembunyikan semua pesan dari pengguna ini Tunjukkan semua pesan dari pengguna ini Sebut - Anda tidak akan dapat mengembalikan perubahan ini setelah Anda mengangkat pengguna ini agar memiliki kuasa yang setara dengan Anda. -\nApakah anda yakin untuk melanjutkan\? + Anda tidak akan dapat mengembalikan perubahan ini setelah Anda mengangkat pengguna ini agar memiliki daya yang setara dengan Anda. +\nApakah Anda yakin untuk melanjutkan\? Melakukan pencekalan pengguna akan mengeluarkannya dari ruangan ini dan mencegahnya untuk kembali masuk. Gagal terjawab oleh pihak lain. %s sedang mengetik… @@ -210,7 +210,7 @@ Tidak dapat membuat widget. Gagal mengirim permohonan. Tingkat energi harus bilangan positif. - Anda tidak tergabung dengan ruangan ini. + Anda tidak di ruangan ini. Anda tidak memiliki permisi untuk melakukan itu di ruangan ini. Tidak ada room_id dalam permohonan. Tidak ada user_id dalam permohonan. @@ -228,7 +228,7 @@ Menghapus cekalan pengguna dengan id berikut Tentukan tingkat kuasa seorang pengguna Undang pengguna dengan id berikut bergabung ke ruangan ini - Gabung ke ruangan dengan alamat berikut + Bergabung ke ruangan dengan alamat berikut Tinggalkan ruang Tentukan topik ruang Keluarkan pengguna dengan id berikut @@ -251,10 +251,10 @@ Nonaktifkan Akun Ini akan mengakibatkan akun Anda tidak dapat digunakan secara permanen. Anda tidak akan dapat masuk dan orang lain tidak dapat mendaftar ulang dengan ID pengguna yang sama. Ini akan mengakibatkan akun Anda keluar dari semua ruangan tempat Anda berpartisipasi serta menghapus semua detail akun dari server identitas Anda. Tindakan ini tidak dapat diubah. \n -\nMenonaktifkan akun Anda tidak membuat kami melupakan pesan-pesan yang Anda kirim secara default. Jika Anda ingin kami melupakan pesan-pesan Anda, mohon centang kotak berikut. +\nMenonaktifkan akun Anda tidak membuat kami melupakan pesan-pesan yang Anda kirim secara bawaan. Jika Anda ingin kami melupakan pesan-pesan Anda, mohon centang kotak berikut. \n \nKeterbacaan pesan di Matrix serupa dengan email. Dengan kami melupakan pesan-pesan Anda berarti pesan-pesan yang Anda kirim tidak akan dibagikan kepada pengguna baru ataupun yang belum terdaftar, tetapi pengguna yang terdaftar yang mempunyai mengakses pesan-pesan tersebut masih dapat mengakses salinan mereka. - Mohon lupakan semua pesan yang telah saya kirim ketika akun saya dideaktivasi (Peringatan: ini akan mengakibatkan pengguna di masa depan melihat percakapan yang tidak lengkap) + Mohon lupakan semua pesan yang telah saya kirim ketika akun saya dinonaktifkan (Peringatan: ini akan mengakibatkan pengguna di masa depan melihat percakapan yang tidak lengkap) Nonaktifkan Akun Mohon masukkan kata sandi Anda. Ruangan ini telah berubah dan tidak lagi aktif. @@ -276,7 +276,7 @@ Jangan kirim pesan terenkripsi ke perangkat yang tidak terverifikasi dari perangkat ini. TIDAK terverifikasi Verifikasi - Untuk memastikan perangkat dapat dipercaya, mohon kontak pengguna dengan medium lain (misalnya tatap muka atau panggilan telepon) dan tanya apakah kunci yang mereka lihat di Pengaturan Pengguna untuk perangkat ini cocok dengan kunci berikut: + Konfirmasi dengan membandingkan berikut ini dengan Pengaturan Pengguna di sesi Anda yang lain: Apabila cocok, tekan tombol verifikasi berikut. Apabila tidak, seseorang sedang menyadap perangkat ini dan mungkin perlu diblokir. Di masa mendatang proses verifikasi ini akan dimutakhirkan. @@ -290,7 +290,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Siapa pun Hanya anggota (dimulai sejak opsi ini dipilih) Hanya anggota (dimulai sejak mereka diundang) - Hanya anggota (dimulai sejak mereka bergabung) + Hanya anggota (sejak mereka bergabung) Pengguna yang dicekal Lanjutan ID internal ruangan ini @@ -378,11 +378,11 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Keluarkan Periksa Keadaan Pemberitahuan Hasil diagnosa pemeriksaan keadaan - Lansungkan Ujicoba + Jalankan Pengujian Berlangsung… (%1$d of %2$d) Diagnosa dasar berlangsung lancar. Apabila Anda masih belum dapat menerima pemberitahuan, mohon kirim laporan kutu untuk kami selidiki. - Satu atau beberapa ujicoba gagal, coba sugesti yang kami tawarkan. - Satu atau beberapa ujicoba gagal, mohon kirim laporan kutu untuk kami selidiki. + Satu atau beberapa ujian gagal, coba saran yang kami tawarkan. + Satu atau beberapa ujian gagal, mohon kirim laporan kutu untuk kami selidiki. Pengaturan Sistem. Pemberitahuan diperbolehkan dalam pengaturan sistem. Notifikasi dinonaktifkan dalam pengaturan sistem. @@ -400,7 +400,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Perbolehkan Pemeriksaan Layanan Google Play APK Layanan Google Play ditemukan dan telah diperbaharui. - ${app_name} menggunakan Layanan Google Play untuk mendorong pesan tapi tampaknya tidak diatur sebagaimana harusnya. + ${app_name} menggunakan Layanan Google Play untuk mendorong pesan tapi tampaknya tidak diatur sebagaimana harusnya: \n%1$s Perbaiki Layanan Google Play Token Firebase @@ -417,7 +417,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Layanan tidak akan mulai ketika perangkat dinyalakan kembali, Anda tidak akan menerima pemberitahuan hingga Anda membuka ${app_name}. Perbolehkan memulai ketika perangkat dinyalakan Periksa halangan di balik layar - Larangan background dinonaktifkan untuk ${app_name}. Percobaan ini sebaiknya dijalankan menggunakan jaringan mobile data (bukan WIFI). + Larangan latar belakang dinonaktifkan untuk ${app_name}. Percobaan ini sebaiknya dijalankan menggunakan jaringan data ponsel (bukan WiFi). \n%1$s Larangan background dinonaktifkan untuk ${app_name}. \nAktivitas yang dilakukan aplikasi ini akan terhalang ketika beroperasi di balik layar, dan ini dapat mempengaruhi pemunculan notifikasi. @@ -446,7 +446,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. [%1$s] \nError ini di luar kendali ${app_name} dan menurut Google, error ini muncul ketika terlalu banyak aplikasi terdaftar dengan FCM pada perangkat tersebut. Error ini tidak seharusnya mempengaruhi pengguna biasa. [%1$s] -\nError ini di luar kendali ${app_name}, dan dapat muncul karena berbagai alasan. Coba lagi nanti, atau Anda juga dapat memeriksa apabila penggunaan jaringan data Layanan Google Play tidak terhalang oleh sistem, atau waktu pada perangkat sudah benar, atau ini dapat terjadi pada ROM tidak resmi. +\nKesalahan ini di luar kendali ${app_name}, dan dapat muncul karena berbagai alasan. Coba lagi nanti, atau Anda juga dapat memeriksa apabila penggunaan jaringan data Layanan Google Play tidak terhalang oleh sistem, atau waktu pada perangkat sudah benar, atau ini dapat terjadi pada ROM tidak resmi. [%1$s] \nError ini di luar kendali ${app_name}. Tidak terdapat akun Google pada perangkat. Mohon buka pengelola akun dan tambahkan akun Google. Tambah Akun @@ -493,7 +493,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. %s melakukan panggilan suara. Anda melakukan panggilan video. %s melakukan panggilan video. - Anda mengubah nama kamar menjadi: %1$s + Anda mengubah nama ruangan menjadi: %1$s %1$s mengubah nama ruangan menjadi: %2$s Anda mengubah avatar ruangan ini %1$s mengubah avatar ruangan ini @@ -546,7 +546,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Aplikasi ini sedang menunggu push Aplikasi ini menerima push Gagal menerima push. Solusinya adalah untuk menginstal ulang aplikasi. - Percobaan Push + Percobaan Dorongan Pastikan Anda mengeklik tautan di email yang telah kami kirimkan kepada Anda. Hapus %s\? Tidak ada nomor telepon yang ditambahkan ke akun Anda @@ -578,7 +578,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Batalkan pencekalan pengguna Alasan untuk mencekal Cekal pengguna - Pengguna yang dikeluarkan akan menghilangkannya dari ruangan ini. + Pengguna akan dikeluarkan dari ruangan ini. \n \nUntuk mencegah mereka bergabung lagi, Anda seharusnya mencekalnya. Alasan untuk mengeluarkan @@ -657,7 +657,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Gagal menambahkan widget Anda tidak dapat melakukan panggilan dengan diri sendiri, tunggu untuk peserta untuk menerima undangan Anda tidak dapat melakukan panggilan dengan diri sendiri - Pertemuan menggunakan kebijakan keamanan dan izin Jitsi. Semua orang saat ini berada di ruangan akan melihat undangan untuk bergabung saat pertemuan Anda sedang berlangsung. + Pertemuan menggunakan kebijakan keamanan dan perizinan Jitsi. Semua orang saat ini berada di ruangan akan melihat undangan untuk bergabung saat pertemuan Anda sedang berlangsung. Mulai rapat video Mulai rapat audio Anda tidak memiliki izin untuk memulai panggilan @@ -675,19 +675,19 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Putuskan Batalkan Tidak Ada - Standar Sistem + Bawaan Sistem Anda mengaktifkan enkripsi ujung-ke-ujung. (algoritma tidak dikenali %1$s). %1$s mengaktifkan enkripsi ujung-ke-ujung. (algoritma tidak dikenali %2$s). Anda mengaktifkan enkripsi ujung-ke-ujung. %1$s mengaktifkan enkripsi ujung-ke-ujung. - Anda telah mencegah para tamu untuk bergabung ruangan. - %1$s telah mencegah para tamu untuk bergabung ruangan. - Anda telah mencegah para tamu untuk bergabung ruangan. - %1$s telah mencegah para tamu untuk bergabung ruangan. - %1$s telah mengizinkan para tamu untuk bergabung ruangan. - Anda telah mengizinkan para tamu untuk bergabung ruangan. - Anda telah mengizinkan para tamu untuk bergabung disini. - %1$s telah mengizinkan para tamu untuk bergabung disini. + Anda telah mencegah para tamu untuk bergabung ke ruangan. + %1$s telah mencegah para tamu untuk bergabung ke ruangan. + Anda telah mencegah para tamu untuk bergabung ke ruangan. + %1$s telah mencegah para tamu untuk bergabung ke ruangan. + %1$s telah mengizinkan para tamu untuk bergabung ke ruangan. + Anda telah mengizinkan para tamu untuk bergabung ke ruangan. + Anda telah mengizinkan para tamu untuk bergabung di sini. + %1$s telah mengizinkan para tamu untuk bergabung di sini. Anda mengubah alamat untuk ruangan ini. %1$s mengubah alamat untuk ruangan ini. Anda mengubah alamat utama dan alamat alternatif untuk ruangan ini. @@ -740,12 +740,12 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. %1$s meninggalkan ruangan. Alasan: %2$s Anda meninggalkan ruangan. Alasan: %1$s %1$s meninggalkan ruangan. Alasan: %2$s - Anda bergabung. Alasan %1$s - %1$s bergabung. Alasan %2$s - %1$s bergabung ruangan. Alasan: %2$s + Anda bergabung. Alasan: %1$s + %1$s bergabung. Alasan: %2$s + %1$s bergabung ke ruangan. Alasan: %2$s %1$s mengundang Anda. Alasan: %2$s Anda mengundang %1$s. Alasan: %2$s - Anda bergabung ruangan. Alasan %1$s + Anda bergabung ke ruangan. Alasan: %1$s %1$s mengundang %2$s. Alasan: %3$s Undangan Anda. Alasan: %1$s Undangan %1$s. Alasan: %2$s @@ -800,12 +800,12 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. %1$s menerima undangan untuk %2$s Anda membatalkan undangan untuk %1$s %1$s membatalkan undangan untuk %2$s - Anda membatalkan undangan untuk %1$s untuk bergabung ruangan - %1$s membatalkan undangan untuk %2$s untuk bergabung ruangan + Anda membatalkan undangan untuk %1$s untuk bergabung ke ruangan + %1$s membatalkan undangan untuk %2$s untuk bergabung ke ruangan Anda mengundang %1$s %1$s mengundang %2$s - Anda mengirimkan undangan ke %1$s untuk bergabung ruangan - %1$s mengirimkan undangan ke %2$s untuk bergabung ruangan + Anda mengirimkan undangan ke %1$s untuk bergabung ke ruangan + %1$s mengirimkan undangan ke %2$s untuk bergabung ke ruangan Anda menghapus avatar ruangan %1$s menghapus avatar ruangan Anda menghapus topik ruangan @@ -833,8 +833,8 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Maaf, terjadi kesalahan Mohon masukkan nama pengguna. Diam - Penurunan harga telah dinonaktifkan. - Penurunan harga telah diaktifkan. + Markdown telah dinonaktifkan. + Markdown telah diaktifkan. Perintah \"%s\" membutuhkan parameter tambahan, atau beberapa parameter salah. Abaikan Permintaan Pembagian Kunci @@ -965,9 +965,9 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Beritahu saya untuk Putar suara rana Pilih - Sumber media default + Sumber media bawaan Pilih - Kompresi default + Kompresi bawaan Media Kelola email dan nomor telepon yang ditautkan ke akun Matrix Anda Email dan nomor telepon @@ -992,7 +992,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Gunakan perintah /confetti atau kirim pesan yang berisi ❄️ atau 🎉 Tampilkan efek chat Gunakan pengelola integrasi untuk mengelola bot, jembatan, widget, dan paket stiker. -\nPengelola integrasi menerima data konfigurasi, dan dapat memodifikasi widget, mengirim undangan ruang, dan mengatur tingkat daya dengan sepengetahuan Anda. +\nPengelola integrasi menerima data konfigurasi, dan dapat memodifikasi widget, mengirim undangan ruang, dan mengatur tingkat daya dengan pengetahuan Anda. Integrasi %d detik @@ -1047,11 +1047,11 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Email ini tidak terkait dengan akun apa pun. Aplikasi tidak dapat membuat akun di homeserver ini. \n -\nApakah Anda ingin mendaftar menggunakan client web\? +\nApakah Anda ingin mendaftar menggunakan klien web\? Maaf, server ini tidak menerima akun baru. Aplikasi tidak dapat masuk ke homeserver ini. Homeserver mendukung jenis masuk berikut: %1$s. \n -\nApakah Anda ingin masuk menggunakan client web\? +\nApakah Anda ingin masuk menggunakan klien web\? Ada kesalahan terjadi saat memuat halaman: %1$s (%2$d) Masukkan alamat server yang ingin Anda gunakan Masukkan alamat Modular Element atau Server yang ingin Anda gunakan @@ -1076,7 +1076,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Lainnya Pelajari lebih lanjut Hosting premium untuk organisasi - Bergabunglah dengan jutaan orang secara gratis di server publik terbesar + Bergabung dengan jutaan orang secara gratis di server publik terbesar Sama seperti email, akun memiliki satu tempat, tetapi Anda dapat berkomunikasi dengan siapa saja Pilih server Mulai @@ -1374,7 +1374,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. BUAT Pesan Langsung Ruangan - Ruangan ini tidak dapat ditampilkan. Apakah Anda masih mau bergabung\? + Ruangan ini tidak dapat ditampilkan. Apakah Anda masih ingin bergabung\? Ruangan ini tidak dapat di akses di waktu ini. \nCoba lagi nanti, atau tanya admin ruangan untuk memeriksa jika Anda punya akses. Ruangan ini tidak dapat di tampilkan @@ -1424,7 +1424,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Tidak ada informasi cryptographic unstable stable - Versi Default + Versi Bawaan Versi Ruangan 👓 Batas tidak diketahui. Homeserver Anda menerima lampiran (file, media, dsb.) dengan ukuran hingga %s. @@ -1435,7 +1435,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Kelola Sesi Tampilkan Semua Sesi Sesi Aktif - Admin server Anda telah menonaktifkan enkripsi ujung-ke-ujung secara default di kamar pribadi & pesan langsung. + Admin server Anda telah menonaktifkan enkripsi ujung-ke-ujung secara bawaan di ruangan & Pesan Langsung privat. Tanda Tangan Silang dinonaktifkan Tanda Tangan Silang diaktifkan. \nKunci dipercaya. @@ -1710,7 +1710,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Tambahkan ruangan dan space yang sudah ada Anda adalah admin satu-satunya di space ini. Meninggalkannya berarti siapa saja tidak akan mempunyai kontrol atas space-nya. Anda tidak akan dapat bergabung lagi kecuali jika Anda diundang lagi. - Anda orang satu-satunya di sini. Jika Anda tinggalkan, siapa saja tidak dapat bergabung di masa depan, termasuk Anda. + Anda adalah orang satu-satunya di sini. Jika Anda tinggalkan, siapa saja tidak dapat bergabung di masa depan, termasuk Anda. Apakah Anda yakin untuk meninggalkan %s\? Tinggalkan Tambahkan ruangan @@ -2015,7 +2015,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Gagal mengimpor kunci Menunggu untuk %s… Hampir selesai! Menunggu untuk konfirmasi… - Hampir selesai! Apakah perangkat yang lain menunjukkan centang yang sama\? + Hampir selesai! Apakah perangkat yang lain menunjukkan sebuah centang\? "Topik: " Tambahkan topik %s untuk memberi tahu orang-orang tentang ruangan ini. @@ -2043,7 +2043,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Mengsinkronisasikan Kunci Penandatanganan Diri Mengsinkronisasikan Kunci Pengguna Mengsinkronisasikan Kunci Utama - Mendefinisikan Kunci SSSS default + Mendefinisikan Kunci SSSS bawaan Membuat kunci aman dari frasa sandi Mempublikasikan kunci identitas yang telah dibuat Selesai @@ -2071,7 +2071,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Jika Anda batalkan, Anda tidak dapat membaca pesan terenkripsi di perangkat ini dan pengguna lain tidak akan mempercayainya Akun Anda mungkin dikompromikan Ini bukan saya - Login baru. Apakah itu Anda\? + Pemasukan baru. Apakah itu Anda\? Segarkan Akses riwayat pesan terenkripsi Ekspor Audit @@ -2091,13 +2091,13 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Kirim gambar dengan ukuran asli - Apakah Anda mau mengirim lampiran ini ke %1$s\? + Apakah Anda ingin mengirim lampiran ini ke %1$s\? Hapus… Tidak dapat menemukan rahasia di penyimpanan Jika Anda tidak dapat mengakses sesi yang sudah ada Peringatan tingkat kepercayaan Level kepercayaan peringatan - Level kepercayaan default + Level kepercayaan bawaan Dipilih Video mempunyai draf yang belum dikirim @@ -2109,7 +2109,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Buka widget Tangkap layar Gagal mengotentikasi - ${app_name} meminta Anda untuk memasukkan kredential untuk melakukan aksi ini. + ${app_name} meminta Anda untuk memasukkan kredensial untuk melakukan tindakan ini. Otentikasi Ulang Dibutuhkan Geser untuk mengakhirkan panggilan Orang tak dikenal @@ -2155,7 +2155,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Koneksi ke server telah hilang Tidak Ya - Hampir selesai! Apakah %s menampilkan centang yang sama\? + Hampir selesai! Apakah %s menampilkan sebuah centang\? Kode QR Atur Ulang Kunci Memulai Tanda Tangan Silang @@ -2186,9 +2186,9 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Izin space Menghapus cekalan akan mengizinkan pengguna untuk bergabung ke space lagi. Mencekal pengguna akan mengeluarkan pengguna dari space ini dan mencegah pengguna untuk bergabung lagi. - mengeluarkan pengguna akan mengeluarkannya dari space ini. + Pengguna akan dikeluarkan dari space ini. \n -\nUntuk mencegah pengguna untuk bergabung lagi, Anda seharusnya cekal pengguna itu saja. +\nUntuk mencegah mereka untuk bergabung lagi, Anda seharusnya mencekalnya. Berhenti Merekam Menambahkan ( ͡° ͜ʖ ͡°) ke pesan teks biasa Tidak ada kebijakan yang disediakan oleh server identitasnya @@ -2571,4 +2571,23 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Jelajahi Ruangan Buat Ruangan Mulai Obrolan - + Maaf, ruangan ini tidak ditemukan. +\nMohon coba lagi nanti.%s + Belum diverifikasi · Aktivitas terakhir %1$s + Terverifikasi · Aktivitas terakhir %1$s + Tampilkan Semua (%1$d) + Sesi Saat Ini + Tampilkan Detail + Verifikasi Sesi + Verifikasi sesi Anda saat ini untuk perpesanan yang aman. + Sesi Anda saat ini siap untuk perpesanan yang aman. + Sesi belum diverifikasi + Sesi terverifikasi + Tipe perangkat tidak diketahui + Desktop + Web + Ponsel + Undangan + Tutup anak space + Buka anak space + \ No newline at end of file From 34a424678db6b924b353d0bfd713456dc074c901 Mon Sep 17 00:00:00 2001 From: random Date: Fri, 2 Sep 2022 12:33:03 +0000 Subject: [PATCH 028/485] Translated using Weblate (Italian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/it/ --- .../src/main/res/values-it/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-it/strings.xml b/library/ui-strings/src/main/res/values-it/strings.xml index 5dd17d5cbe..bab29f3169 100644 --- a/library/ui-strings/src/main/res/values-it/strings.xml +++ b/library/ui-strings/src/main/res/values-it/strings.xml @@ -2610,4 +2610,23 @@ Esplora le stanze Crea una stanza Inizia una chat - + Non verificata · Ultima attività %1$s + Verificata · Ultima attività %1$s + Vedi tutte (%1$d) + Sessione attuale + Vedi dettagli + Verifica la sessione + Verifica la tua sessione attuale per messaggi più sicuri. + La tua sessione attuale è pronta per i messaggi sicuri. + Sessione non verificata + Sessione verificata + Tipo di dispositivo sconosciuto + Desktop + Web + Mobile + Spiacenti, questa stanza non è stata trovata. +\nRiprova più tardi.%s + Inviti + Riduci contenuto dello spazio + Espandi contenuto dello spazio + \ No newline at end of file From a147d8623bd83c7d69f02d8317d615ac89a15a9d Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Sat, 3 Sep 2022 02:05:48 +0000 Subject: [PATCH 029/485] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- .../src/main/res/values-pt-rBR/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-pt-rBR/strings.xml b/library/ui-strings/src/main/res/values-pt-rBR/strings.xml index 23dd6ae75f..c52a2da3b9 100644 --- a/library/ui-strings/src/main/res/values-pt-rBR/strings.xml +++ b/library/ui-strings/src/main/res/values-pt-rBR/strings.xml @@ -2619,4 +2619,23 @@ Explorar Salas Criar Sala Começar Chat - + Não-verificada · Última atividade %1$s + Verificada · Última atividade %1$s + Ver Todas (%1$d) + Sessão Atual + Visualizar Detalhes + Verificar Sessão + Verifique sua sessão atual para mensageria segura melhorada. + Sua sessão atual está pronta para mensageria segura. + Sessão não-verificada + Sessão verificada + Tipo de dispositivo desconhecido + Desktop + Mobile + Web + Desculpe, esta sala não tem sido encontrada. +\nPor favor retente mais tarde.%s + Convites + Colapsar filhos de espaço + Expandir filhos de espaço + \ No newline at end of file From 511c6a2ae11b1115c0576408e89cc06e60d8e61e Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Fri, 2 Sep 2022 18:26:03 +0000 Subject: [PATCH 030/485] Translated using Weblate (Slovak) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/sk/ --- .../src/main/res/values-sk/strings.xml | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values-sk/strings.xml b/library/ui-strings/src/main/res/values-sk/strings.xml index 68663b3b9c..6e46af13de 100644 --- a/library/ui-strings/src/main/res/values-sk/strings.xml +++ b/library/ui-strings/src/main/res/values-sk/strings.xml @@ -2669,4 +2669,23 @@ Preskúmať miestnosti Vytvoriť miestnosť Začať konverzáciu - + Neoverené - Posledná aktivita %1$s + Overené - Posledná aktivita %1$s + Zobraziť všetky (%1$d) + Aktuálna relácia + Zobraziť podrobnosti + Overiť reláciu + Overte svoju aktuálnu reláciu pre vylepšené bezpečné zasielanie správ. + Vaša aktuálna relácia je pripravená na bezpečné zasielanie správ. + Neoverená relácia + Overená relácia + Neznámy typ zariadenia + Stolný počítač + Web + Mobil + Je nám ľúto, táto miestnosť nebola nájdená. +\nProsím, skúste to neskôr.%s + Pozvánky + Zbaliť podpriestory + Rozbaliť podpriestory + \ No newline at end of file From bb6cb597d118ca8fbf7aeb9f7805dd81982403b2 Mon Sep 17 00:00:00 2001 From: Vri Date: Fri, 2 Sep 2022 15:03:17 +0000 Subject: [PATCH 031/485] Translated using Weblate (German) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/de/ --- fastlane/metadata/android/de-DE/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/de-DE/changelogs/40104340.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/40104340.txt b/fastlane/metadata/android/de-DE/changelogs/40104340.txt new file mode 100644 index 0000000000..50b5647608 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Die wichtigsten Änderungen in dieser Version: Verschiedene Fehlerbehebungen und Stabilitätsverbesserungen. +Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases From 87279120524951f4e92af3702023804aea98523d Mon Sep 17 00:00:00 2001 From: Glandos Date: Fri, 2 Sep 2022 20:58:35 +0000 Subject: [PATCH 032/485] Translated using Weblate (French) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/fr/ --- fastlane/metadata/android/fr-FR/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/fr-FR/changelogs/40104340.txt diff --git a/fastlane/metadata/android/fr-FR/changelogs/40104340.txt b/fastlane/metadata/android/fr-FR/changelogs/40104340.txt new file mode 100644 index 0000000000..fe61fd021c --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Principaux changements pour cette version : Plusieurs corrections de bogues et d’améliorations de stabilité. +Intégralité des changements : https://github.com/vector-im/element-android/releases From e4a1495f36c35bc58a2f834e6d419ef0f1ca3726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emese=20T=C3=B3th?= Date: Sat, 3 Sep 2022 11:16:34 +0000 Subject: [PATCH 033/485] Translated using Weblate (Hungarian) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/hu/ --- fastlane/metadata/android/hu-HU/changelogs/40104100.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104110.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104120.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104130.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104140.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104160.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104180.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104190.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104200.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104220.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104230.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104240.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104250.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104260.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104270.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104280.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104300.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104310.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104320.txt | 2 ++ fastlane/metadata/android/hu-HU/changelogs/40104340.txt | 2 ++ 20 files changed, 40 insertions(+) create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104100.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104110.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104120.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104130.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104140.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104160.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104180.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104190.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104200.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104220.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104230.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104240.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104250.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104260.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104270.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104280.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104300.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104310.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104320.txt create mode 100644 fastlane/metadata/android/hu-HU/changelogs/40104340.txt diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104100.txt b/fastlane/metadata/android/hu-HU/changelogs/40104100.txt new file mode 100644 index 0000000000..97746bdcc6 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104100.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Görgetés a hangüzenetben. Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104110.txt b/fastlane/metadata/android/hu-HU/changelogs/40104110.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104110.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104120.txt b/fastlane/metadata/android/hu-HU/changelogs/40104120.txt new file mode 100644 index 0000000000..79df59cf5e --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104120.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Lehetővé teszi a felhasználók számára, hogy offline jelenjenek meg, és audio lejátszót ad hozzá a hangmellékletekhez. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104130.txt b/fastlane/metadata/android/hu-HU/changelogs/40104130.txt new file mode 100644 index 0000000000..79df59cf5e --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104130.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Lehetővé teszi a felhasználók számára, hogy offline jelenjenek meg, és audio lejátszót ad hozzá a hangmellékletekhez. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104140.txt b/fastlane/metadata/android/hu-HU/changelogs/40104140.txt new file mode 100644 index 0000000000..2ea8acda97 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104140.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: A figyelmen kívül hagyott felhasználók kezelésének javítása. Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104160.txt b/fastlane/metadata/android/hu-HU/changelogs/40104160.txt new file mode 100644 index 0000000000..d92018adb0 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104160.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: A titkosított üzenetek jobb kezelése. Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104180.txt b/fastlane/metadata/android/hu-HU/changelogs/40104180.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104180.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104190.txt b/fastlane/metadata/android/hu-HU/changelogs/40104190.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104190.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104200.txt b/fastlane/metadata/android/hu-HU/changelogs/40104200.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104200.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104220.txt b/fastlane/metadata/android/hu-HU/changelogs/40104220.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104220.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104230.txt b/fastlane/metadata/android/hu-HU/changelogs/40104230.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104230.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104240.txt b/fastlane/metadata/android/hu-HU/changelogs/40104240.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104240.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104250.txt b/fastlane/metadata/android/hu-HU/changelogs/40104250.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104250.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104260.txt b/fastlane/metadata/android/hu-HU/changelogs/40104260.txt new file mode 100644 index 0000000000..54d881323f --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104260.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: UnifiedPush használata, és lehetővé teszi a felhasználó számára, hogy FCM nélkül tolja. +Teljes változásnapló: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104270.txt b/fastlane/metadata/android/hu-HU/changelogs/40104270.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104270.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104280.txt b/fastlane/metadata/android/hu-HU/changelogs/40104280.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104280.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104300.txt b/fastlane/metadata/android/hu-HU/changelogs/40104300.txt new file mode 100644 index 0000000000..9882e09368 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104300.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Lehetővé teszi a továbbfejlesztett bejelentkezési és regisztrációs utakat. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104310.txt b/fastlane/metadata/android/hu-HU/changelogs/40104310.txt new file mode 100644 index 0000000000..9882e09368 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104310.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Lehetővé teszi a továbbfejlesztett bejelentkezési és regisztrációs utakat. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104320.txt b/fastlane/metadata/android/hu-HU/changelogs/40104320.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104320.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40104340.txt b/fastlane/metadata/android/hu-HU/changelogs/40104340.txt new file mode 100644 index 0000000000..25772a8ea1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Főbb változások ebben a verzióban: Különböző hibajavítások és stabilitásjavítások. +Teljes változásjegyzék: https://github.com/vector-im/element-android/releases From abca70f6f9251f4f8959aa828cc91b0bfdd47a0e Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Sat, 3 Sep 2022 02:00:47 +0000 Subject: [PATCH 034/485] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/pt_BR/ --- fastlane/metadata/android/pt-BR/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/pt-BR/changelogs/40104340.txt diff --git a/fastlane/metadata/android/pt-BR/changelogs/40104340.txt b/fastlane/metadata/android/pt-BR/changelogs/40104340.txt new file mode 100644 index 0000000000..6e11e92579 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Principais mudanças nesta versão: Vários consertos de bugs e melhorias de estabilidade. +Changelog completo: https://github.com/vector-im/element-android/releases From 0973a20fe46c1dafe03c5d8d99b9224f48f55889 Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Fri, 2 Sep 2022 17:47:34 +0000 Subject: [PATCH 035/485] Translated using Weblate (Slovak) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/sk/ --- fastlane/metadata/android/sk/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/sk/changelogs/40104340.txt diff --git a/fastlane/metadata/android/sk/changelogs/40104340.txt b/fastlane/metadata/android/sk/changelogs/40104340.txt new file mode 100644 index 0000000000..50670f18c2 --- /dev/null +++ b/fastlane/metadata/android/sk/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Hlavné zmeny v tejto verzii: Rôzne opravy chýb a vylepšenia stability. +Úplný zoznam zmien: https://github.com/vector-im/element-android/releases From df25b1a41911d60ea2d98de9bab639b663d5ae87 Mon Sep 17 00:00:00 2001 From: random Date: Fri, 2 Sep 2022 12:33:13 +0000 Subject: [PATCH 036/485] Translated using Weblate (Italian) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/it/ --- fastlane/metadata/android/it-IT/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/it-IT/changelogs/40104340.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/40104340.txt b/fastlane/metadata/android/it-IT/changelogs/40104340.txt new file mode 100644 index 0000000000..556a6fc7ea --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Modifiche principali in questa versione: varie correzioni di errori e miglioramenti della stabilità. +Cronologia completa: https://github.com/vector-im/element-android/releases From 82868dd6b74afeee99837726242972febd89fcb9 Mon Sep 17 00:00:00 2001 From: Danial Behzadi Date: Fri, 2 Sep 2022 16:25:01 +0000 Subject: [PATCH 037/485] Translated using Weblate (Persian) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/fa/ --- fastlane/metadata/android/fa/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/fa/changelogs/40104340.txt diff --git a/fastlane/metadata/android/fa/changelogs/40104340.txt b/fastlane/metadata/android/fa/changelogs/40104340.txt new file mode 100644 index 0000000000..29efb95925 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/40104340.txt @@ -0,0 +1,2 @@ +تغییرات عمده در این نگارش: رفع اشکال‌های مختلف و بهبودهای پایداری. +گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases From 00f1c065048f17a716f08bfd3ce98fa8bce5319b Mon Sep 17 00:00:00 2001 From: Linerly Date: Sat, 3 Sep 2022 14:27:57 +0000 Subject: [PATCH 038/485] Translated using Weblate (Indonesian) Currently translated at 100.0% (75 of 75 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/id/ --- fastlane/metadata/android/id/changelogs/40104340.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/id/changelogs/40104340.txt diff --git a/fastlane/metadata/android/id/changelogs/40104340.txt b/fastlane/metadata/android/id/changelogs/40104340.txt new file mode 100644 index 0000000000..1017951d47 --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/40104340.txt @@ -0,0 +1,2 @@ +Perubahan utama dalam versi ini: Banyak perbaikan kutu dan perbaikan stabilitas. +Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases From 0f4deb70670a0417d5039a567ed27161f2ab16bb Mon Sep 17 00:00:00 2001 From: bmarty Date: Mon, 5 Sep 2022 00:03:36 +0000 Subject: [PATCH 039/485] Sync analytics plan --- .../features/analytics/plan/Interaction.kt | 51 +++++++++++++++++++ .../features/analytics/plan/MobileScreen.kt | 15 ++++++ .../features/analytics/plan/UserProperties.kt | 28 ++++++++++ .../app/features/analytics/plan/ViewRoom.kt | 5 ++ 4 files changed, 99 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt index 6336faa74c..1df1b35439 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt @@ -40,6 +40,46 @@ data class Interaction( ) : VectorAnalyticsEvent { enum class Name { + /** + * User tapped the All filter in the All Chats filter tab. + */ + MobileAllChatsFilterAll, + + /** + * User tapped the Favourites filter in the All Chats filter tab. + */ + MobileAllChatsFilterFavourites, + + /** + * User tapped the People filter in the All Chats filter tab. + */ + MobileAllChatsFilterPeople, + + /** + * User tapped the Unreads filter in the All Chats filter tab. + */ + MobileAllChatsFilterUnreads, + + /** + * User disabled filters from the all chats layout settings. + */ + MobileAllChatsFiltersDisabled, + + /** + * User enabled filters from the all chats layout settings. + */ + MobileAllChatsFiltersEnabled, + + /** + * User disabled recents from the all chats layout settings. + */ + MobileAllChatsRecentsDisabled, + + /** + * User enabled recents from the all chats layout settings. + */ + MobileAllChatsRecentsEnabled, + /** * User tapped on Add to Home button on Room Details screen. */ @@ -60,6 +100,11 @@ data class Interaction( */ MobileRoomThreadSummaryItem, + /** + * User validated the creation of a new space. + */ + MobileSpaceCreationValidated, + /** * User tapped on the filter button on ThreadList screen. */ @@ -81,6 +126,12 @@ data class Interaction( */ SpacePanelSwitchSpace, + /** + * User tapped an unselected sub space from the space list -> space + * switching should occur. + */ + SpacePanelSwitchSubSpace, + /** * User clicked the create room button in the add existing room to space * dialog in Element Web/Desktop. diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt index 3ce3dfb578..7ea41e2d78 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt @@ -43,6 +43,11 @@ data class MobileScreen( */ CreateRoom, + /** + * The screen shown to create a new space. + */ + CreateSpace, + /** * The confirmation screen shown before deactivating an account. */ @@ -78,6 +83,11 @@ data class MobileScreen( */ InviteFriends, + /** + * Room accessed via space bottom sheet list. + */ + Invites, + /** * The screen that displays the login flow (when the user already has an * account). @@ -261,6 +271,11 @@ data class MobileScreen( */ Sidebar, + /** + * Room accessed via space bottom sheet list. + */ + SpaceBottomSheet, + /** * Screen that displays the list of rooms and spaces of a space. */ diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt index 77be2456cd..d6fa918b8e 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt @@ -44,6 +44,10 @@ data class UserProperties( * Whether the user has the people space enabled. */ val webMetaSpacePeopleEnabled: Boolean? = null, + /** + * The active filter in the All Chats screen + */ + val allChatsActiveFilter: AllChatsActiveFilter? = null, /** * The selected messaging use case during the onboarding flow. */ @@ -80,6 +84,29 @@ data class UserProperties( WorkMessaging, } + enum class AllChatsActiveFilter { + + /** + * Filters are activated and All is selected + */ + All, + + /** + * Filters are activated and Favourites is selected + */ + Favourites, + + /** + * Filters are activated and People is selected + */ + People, + + /** + * Filters are activated and Unreads is selected + */ + Unreads, + } + fun getProperties(): Map? { return mutableMapOf().apply { webMetaSpaceFavouritesEnabled?.let { put("WebMetaSpaceFavouritesEnabled", it) } @@ -87,6 +114,7 @@ data class UserProperties( webMetaSpaceHomeEnabled?.let { put("WebMetaSpaceHomeEnabled", it) } webMetaSpaceOrphansEnabled?.let { put("WebMetaSpaceOrphansEnabled", it) } webMetaSpacePeopleEnabled?.let { put("WebMetaSpacePeopleEnabled", it) } + allChatsActiveFilter?.let { put("allChatsActiveFilter", it.name) } ftueUseCaseSelection?.let { put("ftueUseCaseSelection", it.name) } numFavouriteRooms?.let { put("numFavouriteRooms", it) } numSpaces?.let { put("numSpaces", it) } diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt index f6a724304b..366979025a 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt @@ -110,6 +110,11 @@ data class ViewRoom( */ MobileSearchContactDetail, + /** + * Room accessed via space bottom sheet list. + */ + MobileSpaceBottomSheet, + /** * Room accessed via interacting with direct chat item in the space * contact detail screen. From 90fedfea93754c9186dba09478a693b1aad5617c Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 29 Aug 2022 17:23:07 +0200 Subject: [PATCH 040/485] Adding changelog entry --- changelog.d/6961.wip | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6961.wip diff --git a/changelog.d/6961.wip b/changelog.d/6961.wip new file mode 100644 index 0000000000..2d271da8c1 --- /dev/null +++ b/changelog.d/6961.wip @@ -0,0 +1 @@ +[Devices Management] Session overview screen From ed3bd871ea9c3bb7de600444baa62bba06944ddb Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 29 Aug 2022 17:30:59 +0200 Subject: [PATCH 041/485] Renaming header list view to be consistent --- .../stylable_devices_list_header_view.xml | 2 +- ...eaderView.kt => SessionsListHeaderView.kt} | 20 +++++++++---------- .../res/layout/fragment_settings_devices.xml | 6 +++--- ...ader.xml => view_sessions_list_header.xml} | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) rename vector/src/main/java/im/vector/app/features/settings/devices/v2/list/{DevicesListHeaderView.kt => SessionsListHeaderView.kt} (74%) rename vector/src/main/res/layout/{view_devices_list_header.xml => view_sessions_list_header.xml} (83%) diff --git a/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml b/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml index f0807f89c6..97e0290815 100644 --- a/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml +++ b/library/ui-styles/src/main/res/values/stylable_devices_list_header_view.xml @@ -1,7 +1,7 @@ - + diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/DevicesListHeaderView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionsListHeaderView.kt similarity index 74% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/list/DevicesListHeaderView.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionsListHeaderView.kt index d6c7dbe273..547ed93f24 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/DevicesListHeaderView.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionsListHeaderView.kt @@ -25,15 +25,15 @@ import androidx.core.content.res.use import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.extensions.setTextWithColoredPart -import im.vector.app.databinding.ViewDevicesListHeaderBinding +import im.vector.app.databinding.ViewSessionsListHeaderBinding -class DevicesListHeaderView @JvmOverloads constructor( +class SessionsListHeaderView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { - private val binding = ViewDevicesListHeaderBinding.inflate( + private val binding = ViewSessionsListHeaderBinding.inflate( LayoutInflater.from(context), this ) @@ -43,7 +43,7 @@ class DevicesListHeaderView @JvmOverloads constructor( init { context.obtainStyledAttributes( attrs, - R.styleable.DevicesListHeaderView, + R.styleable.SessionsListHeaderView, 0, 0 ).use { @@ -53,14 +53,14 @@ class DevicesListHeaderView @JvmOverloads constructor( } private fun setTitle(typedArray: TypedArray) { - val title = typedArray.getString(R.styleable.DevicesListHeaderView_devicesListHeaderTitle) - binding.devicesListHeaderTitle.text = title + val title = typedArray.getString(R.styleable.SessionsListHeaderView_devicesListHeaderTitle) + binding.sessionsListHeaderTitle.text = title } private fun setDescription(typedArray: TypedArray) { - val description = typedArray.getString(R.styleable.DevicesListHeaderView_devicesListHeaderDescription) + val description = typedArray.getString(R.styleable.SessionsListHeaderView_devicesListHeaderDescription) if (description.isNullOrEmpty()) { - binding.devicesListHeaderDescription.isVisible = false + binding.sessionsListHeaderDescription.isVisible = false return } @@ -70,8 +70,8 @@ class DevicesListHeaderView @JvmOverloads constructor( stringBuilder.append(" ") stringBuilder.append(learnMore) - binding.devicesListHeaderDescription.isVisible = true - binding.devicesListHeaderDescription.setTextWithColoredPart( + binding.sessionsListHeaderDescription.isVisible = true + binding.sessionsListHeaderDescription.setTextWithColoredPart( fullText = stringBuilder.toString(), coloredPart = learnMore, underline = false diff --git a/vector/src/main/res/layout/fragment_settings_devices.xml b/vector/src/main/res/layout/fragment_settings_devices.xml index 6710f345ce..a289bda735 100644 --- a/vector/src/main/res/layout/fragment_settings_devices.xml +++ b/vector/src/main/res/layout/fragment_settings_devices.xml @@ -56,7 +56,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/deviceListInactiveSessionsRecommendation" /> - - - From ba1549048d29d9f72ccdec99a19bfec981d42a0f Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 29 Aug 2022 18:29:12 +0200 Subject: [PATCH 042/485] Navigation from current session --- .../src/main/res/values/strings.xml | 2 + vector/src/main/AndroidManifest.xml | 1 + .../app/core/di/MavericksViewModelModule.kt | 6 +++ .../v2/VectorSettingsDevicesFragment.kt | 26 ++++++++- .../v2/VectorSettingsDevicesViewNavigator.kt | 29 ++++++++++ .../devices/v2/list/CurrentSessionView.kt | 2 + .../v2/overview/SessionOverviewAction.kt | 21 ++++++++ .../v2/overview/SessionOverviewActivity.kt | 52 ++++++++++++++++++ .../v2/overview/SessionOverviewArgs.kt | 25 +++++++++ .../v2/overview/SessionOverviewFragment.kt | 52 ++++++++++++++++++ .../v2/overview/SessionOverviewState.kt | 28 ++++++++++ .../v2/overview/SessionOverviewViewModel.kt | 53 +++++++++++++++++++ .../res/layout/fragment_settings_devices.xml | 2 +- .../fragment_settings_session_overview.xml | 6 +++ 14 files changed, 302 insertions(+), 3 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewActivity.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewArgs.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewState.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt create mode 100644 vector/src/main/res/layout/fragment_settings_session_overview.xml diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index df0e10627a..2b8501a249 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3239,5 +3239,7 @@ Consider signing out from old sessions (%1$d day or more) that you don’t use anymore. Consider signing out from old sessions (%1$d days or more) that you don’t use anymore. + Current Session + Session diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index e87bbad77a..7ab9e85edc 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -338,6 +338,7 @@ + diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index b21b4778e3..bd105436f3 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -87,6 +87,7 @@ import im.vector.app.features.settings.account.deactivation.DeactivateAccountVie import im.vector.app.features.settings.crosssigning.CrossSigningSettingsViewModel import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheetViewModel import im.vector.app.features.settings.devices.DevicesViewModel +import im.vector.app.features.settings.devices.v2.overview.SessionOverviewViewModel import im.vector.app.features.settings.devtools.AccountDataViewModel import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailViewModel import im.vector.app.features.settings.devtools.KeyRequestListViewModel @@ -624,4 +625,9 @@ interface MavericksViewModelModule { @IntoMap @MavericksViewModelKey(InvitesViewModel::class) fun invitesViewModel(factory: InvitesViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + + @Binds + @IntoMap + @MavericksViewModelKey(SessionOverviewViewModel::class) + fun sessionOverviewViewModelFactory(factory: SessionOverviewViewModel.Factory): MavericksAssistedViewModelFactory<*, *> } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 78b8c66f9c..2adf7969bf 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -42,6 +42,7 @@ import im.vector.app.features.settings.devices.DevicesViewEvents import im.vector.app.features.settings.devices.DevicesViewModel import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationViewState +import javax.inject.Inject /** * Display the list of the user's devices and sessions. @@ -50,6 +51,8 @@ import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationVie class VectorSettingsDevicesFragment : VectorBaseFragment() { + @Inject lateinit var viewNavigator: VectorSettingsDevicesViewNavigator + private val viewModel: DevicesViewModel by fragmentViewModel() override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSettingsDevicesBinding { @@ -72,10 +75,10 @@ class VectorSettingsDevicesFragment : initLearnMoreButtons() initWaitingView() - observerViewEvents() + observeViewEvents() } - private fun observerViewEvents() { + private fun observeViewEvents() { viewModel.observeViewEvents { when (it) { is DevicesViewEvents.Loading -> showLoading(it.message) @@ -197,15 +200,34 @@ class VectorSettingsDevicesFragment : views.deviceListHeaderCurrentSession.isVisible = true views.deviceListCurrentSession.isVisible = true views.deviceListCurrentSession.render(it) + views.deviceListCurrentSession.debouncedClicks { + currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) } + } + views.deviceListCurrentSession.viewDetailsButton.debouncedClicks { + currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) } + } } ?: run { hideCurrentSessionView() } } + private fun navigateToSessionOverview(sessionId: String) { + viewNavigator.navigateToSessionOverview( + context = requireActivity(), + sessionId = sessionId + ) + } + private fun hideCurrentSessionView() { views.deviceListHeaderCurrentSession.isVisible = false views.deviceListCurrentSession.isVisible = false views.deviceListDividerCurrentSession.isVisible = false + views.deviceListCurrentSession.debouncedClicks { + // do nothing + } + views.deviceListCurrentSession.viewDetailsButton.debouncedClicks { + // do nothing + } } private fun handleRequestStatus(unIgnoreRequest: Async) { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt new file mode 100644 index 0000000000..0e5cb87d7b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 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.devices.v2 + +import android.content.Context +import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity +import javax.inject.Inject + +// TODO add unit tests +class VectorSettingsDevicesViewNavigator @Inject constructor() { + + fun navigateToSessionOverview(context: Context, sessionId: String) { + context.startActivity(SessionOverviewActivity.newIntent(context, sessionId)) + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/CurrentSessionView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/CurrentSessionView.kt index d6f81f4f79..1ce035931f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/CurrentSessionView.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/CurrentSessionView.kt @@ -39,6 +39,8 @@ class CurrentSessionView @JvmOverloads constructor( views = ViewCurrentSessionBinding.bind(this) } + val viewDetailsButton = views.currentSessionViewDetailsButton + fun render(currentDeviceInfo: DeviceFullInfo) { renderDeviceInfo(currentDeviceInfo.deviceInfo.displayName.orEmpty()) renderVerificationStatus(currentDeviceInfo.trustLevelForShield) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt new file mode 100644 index 0000000000..c028c08ec4 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt @@ -0,0 +1,21 @@ +/* + * 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.devices.v2.overview + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class SessionOverviewAction : VectorViewModelAction diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewActivity.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewActivity.kt new file mode 100644 index 0000000000..a663c0ff2a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewActivity.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2022 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.devices.v2.overview + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.airbnb.mvrx.Mavericks +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.extensions.addFragment +import im.vector.app.core.platform.SimpleFragmentActivity + +/** + * Display the overview info about a Session. + */ +@AndroidEntryPoint +class SessionOverviewActivity : SimpleFragmentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (isFirstCreation()) { + addFragment( + container = views.container, + fragmentClass = SessionOverviewFragment::class.java, + params = intent.getParcelableExtra(Mavericks.KEY_ARG) + ) + } + } + + companion object { + fun newIntent(context: Context, sessionId: String): Intent { + return Intent(context, SessionOverviewActivity::class.java).apply { + putExtra(Mavericks.KEY_ARG, SessionOverviewArgs(sessionId)) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewArgs.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewArgs.kt new file mode 100644 index 0000000000..87ea883362 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewArgs.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 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.devices.v2.overview + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class SessionOverviewArgs( + val sessionId: String +) : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt new file mode 100644 index 0000000000..1b8b231a5c --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 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.devices.v2.overview + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.R +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentSettingsSessionOverviewBinding + +/** + * Display the overview info about a Session. + */ +@AndroidEntryPoint +class SessionOverviewFragment : + VectorBaseFragment() { + + private val viewModel: SessionOverviewViewModel by fragmentViewModel() + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSettingsSessionOverviewBinding { + return FragmentSettingsSessionOverviewBinding.inflate(inflater, container, false) + } + + override fun invalidate() = withState(viewModel) { state -> + updateToolbar(state.isCurrentSession) + } + + private fun updateToolbar(isCurrentSession: Boolean) { + val titleResId = if (isCurrentSession) R.string.device_manager_current_session_title else R.string.device_manager_session_title + (activity as? AppCompatActivity) + ?.supportActionBar + ?.setTitle(titleResId) + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewState.kt new file mode 100644 index 0000000000..d91d6a82ce --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewState.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 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.devices.v2.overview + +import com.airbnb.mvrx.MavericksState + +data class SessionOverviewState( + val sessionId: String, + val isCurrentSession: Boolean = false, +) : MavericksState { + constructor(args: SessionOverviewArgs) : this( + sessionId = args.sessionId + ) +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt new file mode 100644 index 0000000000..a95cc1a49b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022 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.devices.v2.overview + +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.EmptyViewEvents +import im.vector.app.core.platform.VectorViewModel +import org.matrix.android.sdk.api.session.Session + +class SessionOverviewViewModel @AssistedInject constructor( + @Assisted val initialState: SessionOverviewState, + session: Session, +) : VectorViewModel(initialState) { + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: SessionOverviewState): SessionOverviewViewModel + } + + init { + val currentSessionId = session.sessionParams.deviceId.orEmpty() + setState { + copy( + isCurrentSession = sessionId.isNotEmpty() && sessionId == currentSessionId + ) + } + } + + override fun handle(action: SessionOverviewAction) { + TODO("Implement when adding the first action") + } +} diff --git a/vector/src/main/res/layout/fragment_settings_devices.xml b/vector/src/main/res/layout/fragment_settings_devices.xml index a289bda735..b4f47302e1 100644 --- a/vector/src/main/res/layout/fragment_settings_devices.xml +++ b/vector/src/main/res/layout/fragment_settings_devices.xml @@ -61,7 +61,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" app:devicesListHeaderDescription="" - app:devicesListHeaderTitle="@string/device_manager_header_section_current_session" + app:devicesListHeaderTitle="@string/device_manager_current_session_title" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/deviceListSecurityRecommendationsDivider" /> diff --git a/vector/src/main/res/layout/fragment_settings_session_overview.xml b/vector/src/main/res/layout/fragment_settings_session_overview.xml new file mode 100644 index 0000000000..1354408486 --- /dev/null +++ b/vector/src/main/res/layout/fragment_settings_session_overview.xml @@ -0,0 +1,6 @@ + + + + From a1102738d0616cbf5a4febc90803ade7049616ee Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 30 Aug 2022 15:03:07 +0200 Subject: [PATCH 043/485] Unit tests for navigator --- .../v2/VectorSettingsDevicesViewNavigator.kt | 1 - .../VectorSettingsDevicesViewNavigatorTest.kt | 65 +++++++++++++++++++ .../im/vector/app/test/fakes/FakeContext.kt | 7 ++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt index 0e5cb87d7b..25c971aacb 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt @@ -20,7 +20,6 @@ import android.content.Context import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity import javax.inject.Inject -// TODO add unit tests class VectorSettingsDevicesViewNavigator @Inject constructor() { fun navigateToSessionOverview(context: Context, sessionId: String) { diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt new file mode 100644 index 0000000000..2a4c53f34f --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 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.devices.v2 + +import android.content.Intent +import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity +import im.vector.app.test.fakes.FakeContext +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import io.mockk.unmockkAll +import io.mockk.verify +import org.junit.After +import org.junit.Before +import org.junit.Test + +private const val A_SESSION_ID = "session_id" + +class VectorSettingsDevicesViewNavigatorTest { + + private val context = FakeContext() + private val vectorSettingsDevicesViewNavigator = VectorSettingsDevicesViewNavigator() + + @Before + fun setUp() { + mockkObject(SessionOverviewActivity.Companion) + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given a session id when navigating to overview then it starts the correct activity`() { + val intent = givenIntentForSessionOverview(A_SESSION_ID) + context.givenStartActivity(intent) + + vectorSettingsDevicesViewNavigator.navigateToSessionOverview(context.instance, A_SESSION_ID) + + verify { + context.instance.startActivity(intent) + } + } + + private fun givenIntentForSessionOverview(sessionId: String): Intent { + val intent = mockk() + every { SessionOverviewActivity.newIntent(context.instance, sessionId) } returns intent + return intent + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeContext.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeContext.kt index 329ac1bdae..d74ebcb678 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeContext.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeContext.kt @@ -18,11 +18,14 @@ package im.vector.app.test.fakes import android.content.ContentResolver import android.content.Context +import android.content.Intent import android.net.ConnectivityManager import android.net.Uri import android.os.ParcelFileDescriptor import io.mockk.every +import io.mockk.just import io.mockk.mockk +import io.mockk.runs import java.io.OutputStream class FakeContext( @@ -67,4 +70,8 @@ class FakeContext( connectivityManager.givenHasActiveConnection() givenService(Context.CONNECTIVITY_SERVICE, ConnectivityManager::class.java, connectivityManager.instance) } + + fun givenStartActivity(intent: Intent) { + every { instance.startActivity(intent) } just runs + } } From 862edffceebc08d700a7755de928fc871d468207 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 30 Aug 2022 15:39:14 +0200 Subject: [PATCH 044/485] Renaming view state --- .../devices/v2/overview/SessionOverviewViewModel.kt | 10 +++++----- ...ionOverviewState.kt => SessionOverviewViewState.kt} | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) rename vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/{SessionOverviewState.kt => SessionOverviewViewState.kt} (96%) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index a95cc1a49b..f55da2819f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -27,15 +27,15 @@ import im.vector.app.core.platform.VectorViewModel import org.matrix.android.sdk.api.session.Session class SessionOverviewViewModel @AssistedInject constructor( - @Assisted val initialState: SessionOverviewState, + @Assisted val initialState: SessionOverviewViewState, session: Session, -) : VectorViewModel(initialState) { +) : VectorViewModel(initialState) { - companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() @AssistedFactory - interface Factory : MavericksAssistedViewModelFactory { - override fun create(initialState: SessionOverviewState): SessionOverviewViewModel + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: SessionOverviewViewState): SessionOverviewViewModel } init { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt similarity index 96% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewState.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt index d91d6a82ce..e839348800 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.settings.devices.v2.overview import com.airbnb.mvrx.MavericksState -data class SessionOverviewState( +data class SessionOverviewViewState( val sessionId: String, val isCurrentSession: Boolean = false, ) : MavericksState { From eb64b376f4d5a96ef241679319f84ba1558666a5 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 30 Aug 2022 16:09:03 +0200 Subject: [PATCH 045/485] Small renamings/reorganization in CryptoService --- .../matrix/android/sdk/flow/FlowSession.kt | 2 +- .../sdk/internal/crypto/E2eeSanityTests.kt | 4 ++-- .../crypto/crosssigning/XSigningTest.kt | 2 +- .../internal/crypto/verification/SASTest.kt | 4 ++-- .../sdk/api/session/crypto/CryptoService.kt | 24 +++++++++---------- .../internal/crypto/DefaultCryptoService.kt | 22 ++++++++--------- .../helper/MessageInformationDataFactory.kt | 2 +- .../VectorSettingsSecurityPrivacyFragment.kt | 2 +- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt index f22cfa369a..80ed311901 100644 --- a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt @@ -72,7 +72,7 @@ class FlowSession(private val session: Session) { } fun liveMyDevicesInfo(): Flow> { - return session.cryptoService().getLiveMyDevicesInfo().asFlow() + return session.cryptoService().getMyDevicesInfoLive().asFlow() .startWith(session.coroutineDispatchers.io) { session.cryptoService().getMyDevicesInfo() } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt index 251c13ccbf..f883295495 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt @@ -676,8 +676,8 @@ class E2eeSanityTests : InstrumentedTest { assertEquals("Decimal code should have matched", oldCode, newCode) // Assert that devices are verified - val newDeviceFromOldPov: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceNewSession.sessionParams.deviceId) - val oldDeviceFromNewPov: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.sessionParams.deviceId) + val newDeviceFromOldPov: CryptoDeviceInfo? = aliceSession.cryptoService().getCryptoDeviceInfo(aliceSession.myUserId, aliceNewSession.sessionParams.deviceId) + val oldDeviceFromNewPov: CryptoDeviceInfo? = aliceSession.cryptoService().getCryptoDeviceInfo(aliceSession.myUserId, aliceSession.sessionParams.deviceId) Assert.assertTrue("new device should be verified from old point of view", newDeviceFromOldPov!!.isVerified) Assert.assertTrue("old device should be verified from new point of view", oldDeviceFromNewPov!!.isVerified) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt index 8cb38ddc87..ef3fdfeeda 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt @@ -193,7 +193,7 @@ class XSigningTest : InstrumentedTest { fail("Bob should see the new device") } - val bobSecondDevicePOVFirstDevice = bobSession.cryptoService().getDeviceInfo(bobUserId, bobSecondDeviceId) + val bobSecondDevicePOVFirstDevice = bobSession.cryptoService().getCryptoDeviceInfo(bobUserId, bobSecondDeviceId) assertNotNull("Bob Second device should be known and persisted from first", bobSecondDevicePOVFirstDevice) // Manually mark it as trusted from first session diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt index c2e74abc59..1bffbeeeaa 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt @@ -521,9 +521,9 @@ class SASTest : InstrumentedTest { testHelper.await(bobSASLatch) // Assert that devices are verified - val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(bobUserId, bobDeviceId) + val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getCryptoDeviceInfo(bobUserId, bobDeviceId) val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? = - bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId) + bobSession.cryptoService().getCryptoDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId) assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified) assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index a5e05f69e0..ee5fe20d07 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -113,7 +113,17 @@ interface CryptoService { fun setRoomBlacklistUnverifiedDevices(roomId: String) - fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? + fun getCryptoDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? + + fun getCryptoDeviceInfo(deviceId: String, callback: MatrixCallback) + + fun getCryptoDeviceInfo(userId: String): List + + fun getLiveCryptoDeviceInfo(): LiveData> + + fun getLiveCryptoDeviceInfo(userId: String): LiveData> + + fun getLiveCryptoDeviceInfo(userIds: List): LiveData> fun requestRoomKeyForEvent(event: Event) @@ -127,9 +137,7 @@ interface CryptoService { fun getMyDevicesInfo(): List - fun getLiveMyDevicesInfo(): LiveData> - - fun getDeviceInfo(deviceId: String, callback: MatrixCallback) + fun getMyDevicesInfoLive(): LiveData> fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int @@ -156,14 +164,6 @@ interface CryptoService { fun downloadKeys(userIds: List, forceDownload: Boolean, callback: MatrixCallback>) - fun getCryptoDeviceInfo(userId: String): List - - fun getLiveCryptoDeviceInfo(): LiveData> - - fun getLiveCryptoDeviceInfo(userId: String): LiveData> - - fun getLiveCryptoDeviceInfo(userIds: List): LiveData> - fun addNewSessionListener(newSessionListener: NewSessionListener) fun removeSessionListener(listener: NewSessionListener) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 35c066dea8..739f86e659 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -273,7 +273,7 @@ internal class DefaultCryptoService @Inject constructor( .executeBy(taskExecutor) } - override fun getLiveMyDevicesInfo(): LiveData> { + override fun getMyDevicesInfoLive(): LiveData> { return cryptoStore.getLiveMyDevicesInfo() } @@ -281,15 +281,6 @@ internal class DefaultCryptoService @Inject constructor( return cryptoStore.getMyDevicesInfo() } - override fun getDeviceInfo(deviceId: String, callback: MatrixCallback) { - getDeviceInfoTask - .configureWith(GetDeviceInfoTask.Params(deviceId)) { - this.executionThread = TaskThread.CRYPTO - this.callback = callback - } - .executeBy(taskExecutor) - } - override fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int { return cryptoStore.inboundGroupSessionsCount(onlyBackedUp) } @@ -513,7 +504,7 @@ internal class DefaultCryptoService @Inject constructor( * @param userId the user id * @param deviceId the device id */ - override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { + override fun getCryptoDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { return if (userId.isNotEmpty() && !deviceId.isNullOrEmpty()) { cryptoStore.getUserDevice(userId, deviceId) } else { @@ -521,6 +512,15 @@ internal class DefaultCryptoService @Inject constructor( } } + override fun getCryptoDeviceInfo(deviceId: String, callback: MatrixCallback) { + getDeviceInfoTask + .configureWith(GetDeviceInfoTask.Params(deviceId)) { + this.executionThread = TaskThread.CRYPTO + this.callback = callback + } + .executeBy(taskExecutor) + } + override fun getCryptoDeviceInfo(userId: String): List { return cryptoStore.getUserDeviceList(userId).orEmpty() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 6d94837f88..b711bf37bd 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -162,7 +162,7 @@ class MessageInformationDataFactory @Inject constructor( .toModel() ?.deviceId ?.let { deviceId -> - session.cryptoService().getDeviceInfo(event.root.senderId ?: "", deviceId) + session.cryptoService().getCryptoDeviceInfo(event.root.senderId ?: "", deviceId) } when { sendingDevice == null -> { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 2b4d376f55..ecb1779a4a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -585,7 +585,7 @@ class VectorSettingsSecurityPrivacyFragment : } // crypto section: device key (fingerprint) - val deviceInfo = session.cryptoService().getDeviceInfo(userId, deviceId) + val deviceInfo = session.cryptoService().getCryptoDeviceInfo(userId, deviceId) val fingerprint = deviceInfo?.fingerprint() if (fingerprint?.isNotEmpty() == true) { From c690a8cd81ac8eb02f5ce961e1e9f95fcadfaf8d Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 30 Aug 2022 16:32:32 +0200 Subject: [PATCH 046/485] Adding a method to retrieve livedata of device info for a given device id --- .../sdk/api/session/crypto/CryptoService.kt | 3 ++ .../internal/crypto/DefaultCryptoService.kt | 5 +++ .../internal/crypto/store/IMXCryptoStore.kt | 2 ++ .../crypto/store/db/RealmCryptoStore.kt | 26 +++++++++----- .../MyDeviceLastSeenInfoEntityMapper.kt | 34 +++++++++++++++++++ 5 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index ee5fe20d07..4f6a1fa02f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent +import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.crypto.model.SessionInfo interface CryptoService { @@ -139,6 +140,8 @@ interface CryptoService { fun getMyDevicesInfoLive(): LiveData> + fun getMyDevicesInfoLive(deviceId: String): LiveData> + fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int fun isRoomEncrypted(roomId: String): Boolean diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 739f86e659..39866163ce 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -73,6 +73,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityConten import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.shouldShareHistory import org.matrix.android.sdk.api.session.sync.model.SyncResponse +import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting @@ -277,6 +278,10 @@ internal class DefaultCryptoService @Inject constructor( return cryptoStore.getLiveMyDevicesInfo() } + override fun getMyDevicesInfoLive(deviceId: String): LiveData> { + return cryptoStore.getLiveMyDevicesInfo(deviceId) + } + override fun getMyDevicesInfo(): List { return cryptoStore.getMyDevicesInfo() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt index 0413fc730c..3aa4e2f764 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt @@ -242,6 +242,8 @@ internal interface IMXCryptoStore { fun getLiveMyDevicesInfo(): LiveData> + fun getLiveMyDevicesInfo(deviceId: String): LiveData> + fun saveMyDevicesInfo(info: List) /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index f5468634cb..736d4d495c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -55,6 +55,7 @@ import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper +import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailMapper @@ -68,6 +69,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity +import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity @@ -112,6 +114,7 @@ internal class RealmCryptoStore @Inject constructor( @UserId private val userId: String, @DeviceId private val deviceId: String?, private val clock: Clock, + private val myDeviceLastSeenInfoEntityMapper: MyDeviceLastSeenInfoEntityMapper, ) : IMXCryptoStore { /* ========================================================================================== @@ -596,17 +599,24 @@ internal class RealmCryptoStore @Inject constructor( { realm: Realm -> realm.where() }, - { entity -> - DeviceInfo( - deviceId = entity.deviceId, - lastSeenIp = entity.lastSeenIp, - lastSeenTs = entity.lastSeenTs, - displayName = entity.displayName - ) - } + { entity -> myDeviceLastSeenInfoEntityMapper.map(entity) } ) } + override fun getLiveMyDevicesInfo(deviceId: String): LiveData> { + val liveData = monarchy.findAllMappedWithChanges( + { realm: Realm -> + realm.where() + .equalTo(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, deviceId) + }, + { entity -> myDeviceLastSeenInfoEntityMapper.map(entity) } + ) + + return Transformations.map(liveData) { + it.firstOrNull().toOptional() + } + } + override fun saveMyDevicesInfo(info: List) { val entities = info.map { MyDeviceLastSeenInfoEntity( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt new file mode 100644 index 0000000000..ed44b0765a --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 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 org.matrix.android.sdk.internal.crypto.store.db.mapper + +import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo +import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity +import javax.inject.Inject + +// TODO add unit tests +internal class MyDeviceLastSeenInfoEntityMapper @Inject constructor() { + + fun map(entity: MyDeviceLastSeenInfoEntity): DeviceInfo { + return DeviceInfo( + deviceId = entity.deviceId, + lastSeenIp = entity.lastSeenIp, + lastSeenTs = entity.lastSeenTs, + displayName = entity.displayName + ) + } +} From cc36f40a8d4cd95cac6ea1184e0021d10db3ec5b Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 30 Aug 2022 16:47:34 +0200 Subject: [PATCH 047/485] Adding a method to retrieve livedata of crypto device info for a given device id --- .../matrix/android/sdk/api/session/crypto/CryptoService.kt | 2 ++ .../android/sdk/internal/crypto/DefaultCryptoService.kt | 4 ++++ .../android/sdk/internal/crypto/store/IMXCryptoStore.kt | 2 ++ .../sdk/internal/crypto/store/db/RealmCryptoStore.kt | 6 ++++++ 4 files changed, 14 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index 4f6a1fa02f..e0e662c789 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -122,6 +122,8 @@ interface CryptoService { fun getLiveCryptoDeviceInfo(): LiveData> + fun getLiveCryptoDeviceInfoWithId(deviceId: String): LiveData> + fun getLiveCryptoDeviceInfo(userId: String): LiveData> fun getLiveCryptoDeviceInfo(userIds: List): LiveData> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 39866163ce..8dd7c309c6 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -534,6 +534,10 @@ internal class DefaultCryptoService @Inject constructor( return cryptoStore.getLiveDeviceList() } + override fun getLiveCryptoDeviceInfoWithId(deviceId: String): LiveData> { + return cryptoStore.getLiveDeviceWithId(deviceId) + } + override fun getLiveCryptoDeviceInfo(userId: String): LiveData> { return cryptoStore.getLiveDeviceList(userId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt index 3aa4e2f764..56eba25249 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt @@ -238,6 +238,8 @@ internal interface IMXCryptoStore { // TODO temp fun getLiveDeviceList(): LiveData> + fun getLiveDeviceWithId(deviceId: String): LiveData> + fun getMyDevicesInfo(): List fun getLiveMyDevicesInfo(): LiveData> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 736d4d495c..3b8fa4cacd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -581,6 +581,12 @@ internal class RealmCryptoStore @Inject constructor( } } + override fun getLiveDeviceWithId(deviceId: String): LiveData> { + return Transformations.map(getLiveDeviceList()) { devices -> + devices.firstOrNull { it.deviceId == deviceId }.toOptional() + } + } + override fun getMyDevicesInfo(): List { return monarchy.fetchAllCopiedSync { it.where() From 13626a161aaf06c7348021fbeabf04cfe1f700eb Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 31 Aug 2022 10:09:40 +0200 Subject: [PATCH 048/485] Adding use case to get full device info for a given device id --- .../v2/overview/GetDeviceFullInfoUseCase.kt | 54 +++++++++++++++++++ .../v2/overview/SessionOverviewViewModel.kt | 21 ++++++-- 2 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt new file mode 100644 index 0000000000..b7d8efb59a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 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.devices.v2.overview + +import androidx.lifecycle.asFlow +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.features.settings.devices.DeviceFullInfo +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.emptyFlow +import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.api.util.toOptional +import javax.inject.Inject + +// TODO add unit tests +class GetDeviceFullInfoUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, +) { + + fun execute(deviceId: String): Flow> { + return activeSessionHolder.getSafeActiveSession()?.let { session -> + combine( + session.cryptoService().getMyDevicesInfoLive(deviceId).asFlow(), + session.cryptoService().getLiveCryptoDeviceInfoWithId(deviceId).asFlow() + ) { deviceInfo, cryptoDeviceInfo -> + val info = deviceInfo.getOrNull() + val cryptoInfo = cryptoDeviceInfo.getOrNull() + val fullInfo = if (info != null && cryptoInfo != null) { + DeviceFullInfo( + deviceInfo = info, + cryptoDeviceInfo = cryptoInfo + ) + } else { + null + } + fullInfo.toOptional() + } + } ?: emptyFlow() + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index f55da2819f..84c15301aa 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -17,6 +17,7 @@ package im.vector.app.features.settings.devices.v2.overview import com.airbnb.mvrx.MavericksViewModelFactory +import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -24,11 +25,16 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.Session +// TODO add unit tests class SessionOverviewViewModel @AssistedInject constructor( @Assisted val initialState: SessionOverviewViewState, session: Session, + private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, ) : VectorViewModel(initialState) { companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() @@ -39,12 +45,19 @@ class SessionOverviewViewModel @AssistedInject constructor( } init { - val currentSessionId = session.sessionParams.deviceId.orEmpty() + val currentDeviceId = session.sessionParams.deviceId.orEmpty() setState { - copy( - isCurrentSession = sessionId.isNotEmpty() && sessionId == currentSessionId - ) + copy(isCurrentSession = sessionId.isNotEmpty() && sessionId == currentDeviceId) } + + observeSessionInfo(currentDeviceId) + } + + private fun observeSessionInfo(deviceId: String) { + getDeviceFullInfoUseCase.execute(deviceId) + .mapNotNull { it.getOrNull() } + .onEach { setState { copy(deviceInfo = Success(it)) } } + .launchIn(viewModelScope) } override fun handle(action: SessionOverviewAction) { From 40d716d0999d2ed135b9088d7196d832e8ea633c Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 31 Aug 2022 11:55:58 +0200 Subject: [PATCH 049/485] Adding unit tests for the new use case --- .../v2/overview/GetDeviceFullInfoUseCase.kt | 1 - .../GetLiveLocationShareSummaryUseCaseTest.kt | 7 +- .../GetListOfUserLiveLocationUseCaseTest.kt | 4 +- .../overview/GetDeviceFullInfoUseCaseTest.kt | 99 +++++++++++++++++++ .../app/test/TestCoroutineDispatchers.kt | 2 +- .../app/test/fakes/FakeActiveSessionHolder.kt | 4 + .../app/test/fakes/FakeCryptoService.kt | 8 ++ .../test/fakes/FakeFlowLiveDataConversions.kt | 4 +- 8 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt index b7d8efb59a..d20ca17471 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt @@ -26,7 +26,6 @@ import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional import javax.inject.Inject -// TODO add unit tests class GetDeviceFullInfoUseCase @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, ) { diff --git a/vector/src/test/java/im/vector/app/features/location/live/GetLiveLocationShareSummaryUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/location/live/GetLiveLocationShareSummaryUseCaseTest.kt index ed1bcebf16..89966b5317 100644 --- a/vector/src/test/java/im/vector/app/features/location/live/GetLiveLocationShareSummaryUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/location/live/GetLiveLocationShareSummaryUseCaseTest.kt @@ -18,7 +18,7 @@ package im.vector.app.features.location.live import im.vector.app.test.fakes.FakeFlowLiveDataConversions import im.vector.app.test.fakes.FakeSession -import im.vector.app.test.fakes.givenAsFlowReturns +import im.vector.app.test.fakes.givenAsFlow import io.mockk.unmockkAll import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest @@ -28,7 +28,6 @@ import org.junit.Before import org.junit.Test import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent -import org.matrix.android.sdk.api.util.Optional private const val A_ROOM_ID = "room_id" private const val AN_EVENT_ID = "event_id" @@ -64,7 +63,7 @@ class GetLiveLocationShareSummaryUseCaseTest { .getRoom(A_ROOM_ID) .locationSharingService() .givenLiveLocationShareSummaryReturns(AN_EVENT_ID, summary) - .givenAsFlowReturns(Optional(summary)) + .givenAsFlow() val result = getLiveLocationShareSummaryUseCase.execute(A_ROOM_ID, AN_EVENT_ID).first() @@ -77,7 +76,7 @@ class GetLiveLocationShareSummaryUseCaseTest { .getRoom(A_ROOM_ID) .locationSharingService() .givenLiveLocationShareSummaryReturns(AN_EVENT_ID, null) - .givenAsFlowReturns(Optional(null)) + .givenAsFlow() val result = getLiveLocationShareSummaryUseCase.execute(A_ROOM_ID, AN_EVENT_ID).first() diff --git a/vector/src/test/java/im/vector/app/features/location/live/map/GetListOfUserLiveLocationUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/location/live/map/GetListOfUserLiveLocationUseCaseTest.kt index 420b8e6a06..6d24858915 100644 --- a/vector/src/test/java/im/vector/app/features/location/live/map/GetListOfUserLiveLocationUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/location/live/map/GetListOfUserLiveLocationUseCaseTest.kt @@ -19,7 +19,7 @@ package im.vector.app.features.location.live.map import im.vector.app.features.location.LocationData import im.vector.app.test.fakes.FakeFlowLiveDataConversions import im.vector.app.test.fakes.FakeSession -import im.vector.app.test.fakes.givenAsFlowReturns +import im.vector.app.test.fakes.givenAsFlow import io.mockk.coEvery import io.mockk.mockk import io.mockk.unmockkAll @@ -81,7 +81,7 @@ class GetListOfUserLiveLocationUseCaseTest { .getRoom(A_ROOM_ID) .locationSharingService() .givenRunningLiveLocationShareSummariesReturns(summaries) - .givenAsFlowReturns(summaries) + .givenAsFlow() val viewState1 = UserLiveLocationViewState( matrixItem = MatrixItem.UserItem(id = "@userId1:matrix.org", displayName = "User 1", avatarUrl = ""), diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt new file mode 100644 index 0000000000..32d7b6edfe --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 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.devices.v2.overview + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.asFlow +import im.vector.app.features.settings.devices.DeviceFullInfo +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeFlowLiveDataConversions +import im.vector.app.test.fakes.givenAsFlow +import io.mockk.unmockkAll +import io.mockk.verify +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.test.runTest +import org.amshove.kluent.shouldBeEqualTo +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo +import org.matrix.android.sdk.api.util.Optional + +private const val A_DEVICE_ID = "device-id" + +class GetDeviceFullInfoUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions() + + private val getDeviceFullInfoUseCase = GetDeviceFullInfoUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance + ) + + @Before + fun setUp() { + fakeFlowLiveDataConversions.setup() + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given an active session and info for device when getting device info then the result is correct`() = runTest { + val deviceInfo = DeviceInfo() + fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData = MutableLiveData(Optional(deviceInfo)) + fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData.givenAsFlow() + val cryptoDeviceInfo = CryptoDeviceInfo(deviceId = A_DEVICE_ID, userId = "") + fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData = MutableLiveData(Optional(cryptoDeviceInfo)) + fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData.givenAsFlow() + + val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull() + + deviceFullInfo shouldBeEqualTo Optional(DeviceFullInfo(deviceInfo = deviceInfo, cryptoDeviceInfo = cryptoDeviceInfo)) + verify { fakeActiveSessionHolder.instance.getSafeActiveSession() } + verify { fakeActiveSessionHolder.fakeSession.fakeCryptoService.getMyDevicesInfoLive(A_DEVICE_ID).asFlow() } + verify { fakeActiveSessionHolder.fakeSession.fakeCryptoService.getLiveCryptoDeviceInfoWithId(A_DEVICE_ID).asFlow() } + } + + @Test + fun `given an active session and no info for device when getting device info then the result is null`() = runTest { + fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData = MutableLiveData(Optional(null)) + fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData.givenAsFlow() + fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData = MutableLiveData(Optional(null)) + fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData.givenAsFlow() + + val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull() + + deviceFullInfo shouldBeEqualTo Optional(null) + verify { fakeActiveSessionHolder.instance.getSafeActiveSession() } + verify { fakeActiveSessionHolder.fakeSession.fakeCryptoService.getMyDevicesInfoLive(A_DEVICE_ID).asFlow() } + verify { fakeActiveSessionHolder.fakeSession.fakeCryptoService.getLiveCryptoDeviceInfoWithId(A_DEVICE_ID).asFlow() } + } + + @Test + fun `given no active session when getting device info then the result is empty`() = runTest { + fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null) + + val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull() + + deviceFullInfo shouldBeEqualTo null + verify { fakeActiveSessionHolder.instance.getSafeActiveSession() } + } +} diff --git a/vector/src/test/java/im/vector/app/test/TestCoroutineDispatchers.kt b/vector/src/test/java/im/vector/app/test/TestCoroutineDispatchers.kt index fb3c1bb70a..c4f4c2a19a 100644 --- a/vector/src/test/java/im/vector/app/test/TestCoroutineDispatchers.kt +++ b/vector/src/test/java/im/vector/app/test/TestCoroutineDispatchers.kt @@ -19,7 +19,7 @@ package im.vector.app.test import kotlinx.coroutines.test.UnconfinedTestDispatcher import org.matrix.android.sdk.api.MatrixCoroutineDispatchers -private val testDispatcher = UnconfinedTestDispatcher() +internal val testDispatcher = UnconfinedTestDispatcher() internal val testCoroutineDispatchers = MatrixCoroutineDispatchers( io = testDispatcher, diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeActiveSessionHolder.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeActiveSessionHolder.kt index 3065c18c30..bfc36ef06d 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeActiveSessionHolder.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeActiveSessionHolder.kt @@ -33,4 +33,8 @@ class FakeActiveSessionHolder( fun expectSetsActiveSession(session: Session) { justRun { instance.setActiveSession(session) } } + + fun givenGetSafeActiveSessionReturns(session: Session?) { + every { instance.getSafeActiveSession() } returns session + } } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeCryptoService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeCryptoService.kt index ed571fc2f2..2c31933464 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeCryptoService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeCryptoService.kt @@ -20,11 +20,15 @@ import androidx.lifecycle.MutableLiveData import io.mockk.mockk import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo +import org.matrix.android.sdk.api.util.Optional class FakeCryptoService : CryptoService by mockk() { var roomKeysExport = ByteArray(size = 1) var cryptoDeviceInfos = mutableMapOf() + var cryptoDeviceInfoWithIdLiveData: MutableLiveData> = MutableLiveData() + var myDevicesInfoWithIdLiveData: MutableLiveData> = MutableLiveData() override suspend fun exportRoomKeys(password: String) = roomKeysExport @@ -35,4 +39,8 @@ class FakeCryptoService : CryptoService by mockk() { override fun getLiveCryptoDeviceInfo(userIds: List) = MutableLiveData( cryptoDeviceInfos.filterKeys { userIds.contains(it) }.values.toList() ) + + override fun getLiveCryptoDeviceInfoWithId(deviceId: String) = cryptoDeviceInfoWithIdLiveData + + override fun getMyDevicesInfoLive(deviceId: String) = myDevicesInfoWithIdLiveData } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeFlowLiveDataConversions.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeFlowLiveDataConversions.kt index 9abbcc174d..956a86f32e 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeFlowLiveDataConversions.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeFlowLiveDataConversions.kt @@ -28,6 +28,6 @@ class FakeFlowLiveDataConversions { } } -fun LiveData.givenAsFlowReturns(value: T) { - every { asFlow() } returns flowOf(value) +fun LiveData.givenAsFlow() { + every { asFlow() } returns flowOf(value!!) } From 295ae55142e6c09256172d40509dfb37289d7235 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 31 Aug 2022 14:12:16 +0200 Subject: [PATCH 050/485] Adding unit tests for mapper --- .../MyDeviceLastSeenInfoEntityMapper.kt | 1 - .../MyDeviceLastSeenInfoEntityMapperTest.kt | 52 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapperTest.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt index ed44b0765a..76e3171f4d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapper.kt @@ -20,7 +20,6 @@ import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity import javax.inject.Inject -// TODO add unit tests internal class MyDeviceLastSeenInfoEntityMapper @Inject constructor() { fun map(entity: MyDeviceLastSeenInfoEntity): DeviceInfo { diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapperTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapperTest.kt new file mode 100644 index 0000000000..e706fd6622 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/MyDeviceLastSeenInfoEntityMapperTest.kt @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 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 org.matrix.android.sdk.internal.crypto.store.db.mapper + +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Test +import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo +import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity + +private const val A_DEVICE_ID = "device-id" +private const val AN_IP_ADDRESS = "ip-address" +private const val A_TIMESTAMP = 123L +private const val A_DISPLAY_NAME = "display-name" + +class MyDeviceLastSeenInfoEntityMapperTest { + + private val myDeviceLastSeenInfoEntityMapper = MyDeviceLastSeenInfoEntityMapper() + + @Test + fun `given an entity when mapping to model then all fields are correctly mapped`() { + val entity = MyDeviceLastSeenInfoEntity( + deviceId = A_DEVICE_ID, + lastSeenIp = AN_IP_ADDRESS, + lastSeenTs = A_TIMESTAMP, + displayName = A_DISPLAY_NAME + ) + val expectedDeviceInfo = DeviceInfo( + deviceId = A_DEVICE_ID, + lastSeenIp = AN_IP_ADDRESS, + lastSeenTs = A_TIMESTAMP, + displayName = A_DISPLAY_NAME + ) + + val deviceInfo = myDeviceLastSeenInfoEntityMapper.map(entity) + + deviceInfo shouldBeEqualTo expectedDeviceInfo + } +} From 412fda27af501914c7a76c120a75e820dd084502 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 31 Aug 2022 14:44:01 +0200 Subject: [PATCH 051/485] Adding unit tests for viewModel --- .../v2/overview/SessionOverviewViewModel.kt | 1 - .../v2/overview/SessionOverviewViewState.kt | 4 + .../overview/SessionOverviewViewModelTest.kt | 80 +++++++++++++++++++ .../im/vector/app/test/fakes/FakeSession.kt | 5 ++ 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 84c15301aa..9c40480270 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -30,7 +30,6 @@ import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.Session -// TODO add unit tests class SessionOverviewViewModel @AssistedInject constructor( @Assisted val initialState: SessionOverviewViewState, session: Session, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt index e839348800..8fa19a6eee 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt @@ -16,11 +16,15 @@ package im.vector.app.features.settings.devices.v2.overview +import com.airbnb.mvrx.Async import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.Uninitialized +import im.vector.app.features.settings.devices.DeviceFullInfo data class SessionOverviewViewState( val sessionId: String, val isCurrentSession: Boolean = false, + val deviceInfo: Async = Uninitialized, ) : MavericksState { constructor(args: SessionOverviewArgs) : this( sessionId = args.sessionId diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt new file mode 100644 index 0000000000..f15bc0860c --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022 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.devices.v2.overview + +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.test.MvRxTestRule +import im.vector.app.features.settings.devices.DeviceFullInfo +import im.vector.app.test.fakes.FakeSession +import im.vector.app.test.test +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test +import org.matrix.android.sdk.api.auth.data.SessionParams +import org.matrix.android.sdk.api.util.Optional + +private const val A_SESSION_ID = "session-id" + +class SessionOverviewViewModelTest { + + @get:Rule + val mvRxTestRule = MvRxTestRule(testDispatcher = UnconfinedTestDispatcher()) + + private val args = SessionOverviewArgs( + sessionId = A_SESSION_ID + ) + private val fakeSession = FakeSession() + private val getDeviceFullInfoUseCase = mockk() + + private fun createViewModel() = SessionOverviewViewModel( + initialState = SessionOverviewViewState(args), + session = fakeSession, + getDeviceFullInfoUseCase = getDeviceFullInfoUseCase + ) + + @Test + fun `given the viewModel has been initialized then viewState is updated with session info`() = runTest { + val sessionParams = givenIdForSession(A_SESSION_ID) + val deviceFullInfo = mockk() + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(Optional(deviceFullInfo)) + val expectedState = SessionOverviewViewState( + sessionId = A_SESSION_ID, + isCurrentSession = true, + deviceInfo = Success(deviceFullInfo) + ) + + val viewModel = createViewModel() + + viewModel.test() + .assertLatestState { state -> state == expectedState } + .finish() + verify { sessionParams.deviceId } + verify { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } + } + + private fun givenIdForSession(deviceId: String): SessionParams { + val sessionParams = mockk() + every { sessionParams.deviceId } returns deviceId + fakeSession.givenSessionParams(sessionParams) + return sessionParams + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt index ee016ecae3..71bcde5807 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt @@ -26,6 +26,7 @@ import io.mockk.coJustRun import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic +import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService @@ -71,6 +72,10 @@ class FakeSession( } } + fun givenSessionParams(sessionParams: SessionParams) { + every { this@FakeSession.sessionParams } returns sessionParams + } + companion object { fun withRoomSummary(roomSummary: RoomSummary) = FakeSession().apply { From ca70eddaf5b1b0a68ed18478e4fb65eb4b3a4bb7 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 1 Sep 2022 09:25:11 +0200 Subject: [PATCH 052/485] Introducing some reusable usecases --- .../devices/CurrentSessionCrossSigningInfo.kt | 26 ++++++++++ .../settings/devices/DevicesViewModel.kt | 28 +++-------- ...etCurrentSessionCrossSigningInfoUseCase.kt | 37 ++++++++++++++ ...yptionTrustLevelForCurrentDeviceUseCase.kt | 38 ++++++++++++++ ...GetEncryptionTrustLevelForDeviceUseCase.kt | 40 +++++++++++++++ ...cryptionTrustLevelForOtherDeviceUseCase.kt | 49 +++++++++++++++++++ .../features/settings/devices/TrustUtils.kt | 1 + .../v2/overview/GetDeviceFullInfoUseCase.kt | 10 +++- 8 files changed, 206 insertions(+), 23 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/CurrentSessionCrossSigningInfo.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCase.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForDeviceUseCase.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForOtherDeviceUseCase.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/CurrentSessionCrossSigningInfo.kt b/vector/src/main/java/im/vector/app/features/settings/devices/CurrentSessionCrossSigningInfo.kt new file mode 100644 index 0000000000..790de08823 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/CurrentSessionCrossSigningInfo.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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.devices + +/** + * Used to hold some info about the cross signing of the current Session. + */ +data class CurrentSessionCrossSigningInfo( + val deviceId: String?, + val isCrossSigningInitialized: Boolean, + val isCrossSigningVerified: Boolean, +) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 3b5bcb61d9..82c346b09c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -101,6 +101,8 @@ class DevicesViewModel @AssistedInject constructor( private val stringProvider: StringProvider, private val matrix: Matrix, private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase, + getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase, + private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase, ) : VectorViewModel(initialState), VerificationService.Listener { var uiaContinuation: Continuation? = null @@ -116,8 +118,9 @@ class DevicesViewModel @AssistedInject constructor( private val refreshSource = PublishDataSource() init { - val hasAccountCrossSigning = session.cryptoService().crossSigningService().isCrossSigningInitialized() - val accountCrossSigningIsTrusted = session.cryptoService().crossSigningService().isCrossSigningVerified() + val currentSessionCrossSigningInfo = getCurrentSessionCrossSigningInfoUseCase.execute() + val hasAccountCrossSigning = currentSessionCrossSigningInfo.isCrossSigningInitialized + val accountCrossSigningIsTrusted = currentSessionCrossSigningInfo.isCrossSigningVerified setState { copy( @@ -143,12 +146,7 @@ class DevicesViewModel @AssistedInject constructor( .sortedByDescending { it.lastSeenTs } .map { deviceInfo -> val cryptoDeviceInfo = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId } - val trustLevelForShield = computeTrustLevelForShield( - currentSessionCrossTrusted = accountCrossSigningIsTrusted, - legacyMode = !hasAccountCrossSigning, - deviceTrustLevel = cryptoDeviceInfo?.trustLevel, - isCurrentDevice = deviceInfo.deviceId == session.sessionParams.deviceId - ) + val trustLevelForShield = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo) val isInactive = checkIfSessionIsInactiveUseCase.execute(deviceInfo.lastSeenTs ?: 0) DeviceFullInfo(deviceInfo, cryptoDeviceInfo, trustLevelForShield, isInactive) } @@ -268,20 +266,6 @@ class DevicesViewModel @AssistedInject constructor( } } - private fun computeTrustLevelForShield( - currentSessionCrossTrusted: Boolean, - legacyMode: Boolean, - deviceTrustLevel: DeviceTrustLevel?, - isCurrentDevice: Boolean, - ): RoomEncryptionTrustLevel { - return TrustUtils.shieldForTrust( - currentDevice = isCurrentDevice, - trustMSK = currentSessionCrossTrusted, - legacyMode = legacyMode, - deviceTrustLevel = deviceTrustLevel - ) - } - private fun handleInteractiveVerification(action: DevicesAction.VerifyMyDevice) { val txID = session.cryptoService() .verificationService() diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCase.kt new file mode 100644 index 0000000000..aa0de9ddf1 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCase.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 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.devices + +import im.vector.app.core.di.ActiveSessionHolder +import javax.inject.Inject + +// TODO add unit tests +class GetCurrentSessionCrossSigningInfoUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, +) { + + fun execute(): CurrentSessionCrossSigningInfo { + val session = activeSessionHolder.getActiveSession() + val isCrossSigningInitialized = session.cryptoService().crossSigningService().isCrossSigningInitialized() + val isCrossSigningVerified = session.cryptoService().crossSigningService().isCrossSigningVerified() + return CurrentSessionCrossSigningInfo( + deviceId = session.sessionParams.deviceId, + isCrossSigningInitialized = isCrossSigningInitialized, + isCrossSigningVerified = isCrossSigningVerified + ) + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt new file mode 100644 index 0000000000..eaa72b424a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 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.devices + +import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel +import javax.inject.Inject + +// TODO add unit tests +class GetEncryptionTrustLevelForCurrentDeviceUseCase @Inject constructor() { + + fun execute(trustMSK: Boolean, legacyMode: Boolean): RoomEncryptionTrustLevel { + return if (legacyMode) { + // In legacy, current session is always trusted + RoomEncryptionTrustLevel.Trusted + } else { + // If current session doesn't trust MSK, show red shield for current device + if (trustMSK) { + RoomEncryptionTrustLevel.Trusted + } else { + RoomEncryptionTrustLevel.Warning + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForDeviceUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForDeviceUseCase.kt new file mode 100644 index 0000000000..d988f728ae --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForDeviceUseCase.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 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.devices + +import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel +import javax.inject.Inject + +// TODO add unit tests +class GetEncryptionTrustLevelForDeviceUseCase @Inject constructor( + private val getEncryptionTrustLevelForCurrentDeviceUseCase: GetEncryptionTrustLevelForCurrentDeviceUseCase, + private val getEncryptionTrustLevelForOtherDeviceUseCase: GetEncryptionTrustLevelForOtherDeviceUseCase, +) { + + fun execute(currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo, cryptoDeviceInfo: CryptoDeviceInfo?): RoomEncryptionTrustLevel { + val legacyMode = !currentSessionCrossSigningInfo.isCrossSigningInitialized + val trustMSK = currentSessionCrossSigningInfo.isCrossSigningVerified + val isCurrentDevice = !cryptoDeviceInfo?.deviceId.isNullOrEmpty() && cryptoDeviceInfo?.deviceId == currentSessionCrossSigningInfo.deviceId + val deviceTrustLevel = cryptoDeviceInfo?.trustLevel + + return when { + isCurrentDevice -> getEncryptionTrustLevelForCurrentDeviceUseCase.execute(trustMSK, legacyMode) + else -> getEncryptionTrustLevelForOtherDeviceUseCase.execute(trustMSK, legacyMode, deviceTrustLevel) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForOtherDeviceUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForOtherDeviceUseCase.kt new file mode 100644 index 0000000000..41cdae23a4 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/GetEncryptionTrustLevelForOtherDeviceUseCase.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 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.devices + +import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel +import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel +import javax.inject.Inject + +// TODO add unit tests +class GetEncryptionTrustLevelForOtherDeviceUseCase @Inject constructor() { + + fun execute(trustMSK: Boolean, legacyMode: Boolean, deviceTrustLevel: DeviceTrustLevel?): RoomEncryptionTrustLevel { + return if (legacyMode) { + // use local trust + if (deviceTrustLevel?.locallyVerified == true) { + RoomEncryptionTrustLevel.Trusted + } else { + RoomEncryptionTrustLevel.Warning + } + } else { + if (trustMSK) { + // use cross sign trust, put locally trusted in black + when { + deviceTrustLevel?.crossSigningVerified == true -> RoomEncryptionTrustLevel.Trusted + deviceTrustLevel?.locallyVerified == true -> RoomEncryptionTrustLevel.Default + else -> RoomEncryptionTrustLevel.Warning + } + } else { + // The current session is untrusted, so displays others in black + // as we can't know the cross-signing state + RoomEncryptionTrustLevel.Default + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/TrustUtils.kt b/vector/src/main/java/im/vector/app/features/settings/devices/TrustUtils.kt index da18154ea1..7709a63344 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/TrustUtils.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/TrustUtils.kt @@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel +// TODO Replace usage by the use case GetEncryptionTrustLevelForDeviceUseCase object TrustUtils { fun shieldForTrust( diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt index d20ca17471..51252de34a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt @@ -19,6 +19,8 @@ package im.vector.app.features.settings.devices.v2.overview import androidx.lifecycle.asFlow import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.features.settings.devices.DeviceFullInfo +import im.vector.app.features.settings.devices.GetCurrentSessionCrossSigningInfoUseCase +import im.vector.app.features.settings.devices.GetEncryptionTrustLevelForDeviceUseCase import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.emptyFlow @@ -26,12 +28,16 @@ import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional import javax.inject.Inject +// TODO update unit test class GetDeviceFullInfoUseCase @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, + private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase, + private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase, ) { fun execute(deviceId: String): Flow> { return activeSessionHolder.getSafeActiveSession()?.let { session -> + val currentSessionCrossSigningInfo = getCurrentSessionCrossSigningInfoUseCase.execute() combine( session.cryptoService().getMyDevicesInfoLive(deviceId).asFlow(), session.cryptoService().getLiveCryptoDeviceInfoWithId(deviceId).asFlow() @@ -39,9 +45,11 @@ class GetDeviceFullInfoUseCase @Inject constructor( val info = deviceInfo.getOrNull() val cryptoInfo = cryptoDeviceInfo.getOrNull() val fullInfo = if (info != null && cryptoInfo != null) { + val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoInfo) DeviceFullInfo( deviceInfo = info, - cryptoDeviceInfo = cryptoInfo + cryptoDeviceInfo = cryptoInfo, + trustLevelForShield = roomEncryptionTrustLevel ) } else { null From 7c32884df541c03ac9d523334e182bb5f5690049 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 1 Sep 2022 09:32:14 +0200 Subject: [PATCH 053/485] Renaming CurrentSessionView into SessionInfoView to be more generic --- .../devices/v2/list/CurrentSessionView.kt | 78 ------------------- .../devices/v2/list/SessionInfoView.kt | 78 +++++++++++++++++++ ...rent_session.xml => view_session_info.xml} | 26 +++---- 3 files changed, 91 insertions(+), 91 deletions(-) delete mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/list/CurrentSessionView.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt rename vector/src/main/res/layout/{view_current_session.xml => view_session_info.xml} (78%) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/CurrentSessionView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/CurrentSessionView.kt deleted file mode 100644 index 1ce035931f..0000000000 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/CurrentSessionView.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2022 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.devices.v2.list - -import android.content.Context -import android.util.AttributeSet -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.view.isVisible -import im.vector.app.R -import im.vector.app.databinding.ViewCurrentSessionBinding -import im.vector.app.features.settings.devices.DeviceFullInfo -import im.vector.app.features.themes.ThemeUtils -import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel - -class CurrentSessionView @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : ConstraintLayout(context, attrs, defStyleAttr) { - - private val views: ViewCurrentSessionBinding - - init { - inflate(context, R.layout.view_current_session, this) - views = ViewCurrentSessionBinding.bind(this) - } - - val viewDetailsButton = views.currentSessionViewDetailsButton - - fun render(currentDeviceInfo: DeviceFullInfo) { - renderDeviceInfo(currentDeviceInfo.deviceInfo.displayName.orEmpty()) - renderVerificationStatus(currentDeviceInfo.trustLevelForShield) - } - - private fun renderVerificationStatus(trustLevelForShield: RoomEncryptionTrustLevel) { - views.currentSessionVerificationStatusImageView.render(trustLevelForShield) - if (trustLevelForShield == RoomEncryptionTrustLevel.Trusted) { - renderCrossSigningVerified() - } else { - renderCrossSigningUnverified() - } - } - - private fun renderCrossSigningVerified() { - views.currentSessionVerificationStatusTextView.text = context.getString(R.string.device_manager_verification_status_verified) - views.currentSessionVerificationStatusTextView.setTextColor(ThemeUtils.getColor(context, R.attr.colorPrimary)) - views.currentSessionVerificationStatusDetailTextView.text = context.getString(R.string.device_manager_verification_status_detail_verified) - views.currentSessionVerifySessionButton.isVisible = false - } - - private fun renderCrossSigningUnverified() { - views.currentSessionVerificationStatusTextView.text = context.getString(R.string.device_manager_verification_status_unverified) - views.currentSessionVerificationStatusTextView.setTextColor(ThemeUtils.getColor(context, R.attr.colorError)) - views.currentSessionVerificationStatusDetailTextView.text = context.getString(R.string.device_manager_verification_status_detail_unverified) - views.currentSessionVerifySessionButton.isVisible = true - } - - // TODO. We don't have this info yet. Update later accordingly. - private fun renderDeviceInfo(sessionName: String) { - views.currentSessionDeviceTypeImageView.setImageResource(R.drawable.ic_device_type_mobile) - views.currentSessionDeviceTypeImageView.contentDescription = context.getString(R.string.a11y_device_manager_device_type_mobile) - views.currentSessionNameTextView.text = sessionName - } -} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt new file mode 100644 index 0000000000..b79adfb2d4 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 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.devices.v2.list + +import android.content.Context +import android.util.AttributeSet +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isVisible +import im.vector.app.R +import im.vector.app.databinding.ViewSessionInfoBinding +import im.vector.app.features.settings.devices.DeviceFullInfo +import im.vector.app.features.themes.ThemeUtils +import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel + +class SessionInfoView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : ConstraintLayout(context, attrs, defStyleAttr) { + + private val views: ViewSessionInfoBinding + + init { + inflate(context, R.layout.view_session_info, this) + views = ViewSessionInfoBinding.bind(this) + } + + val viewDetailsButton = views.sessionInfoViewDetailsButton + + fun render(deviceInfo: DeviceFullInfo) { + renderDeviceInfo(deviceInfo.deviceInfo.displayName.orEmpty()) + renderVerificationStatus(deviceInfo.trustLevelForShield) + } + + private fun renderVerificationStatus(trustLevelForShield: RoomEncryptionTrustLevel) { + views.sessionInfoVerificationStatusImageView.render(trustLevelForShield) + if (trustLevelForShield == RoomEncryptionTrustLevel.Trusted) { + renderCrossSigningVerified() + } else { + renderCrossSigningUnverified() + } + } + + private fun renderCrossSigningVerified() { + views.sessionInfoVerificationStatusTextView.text = context.getString(R.string.device_manager_verification_status_verified) + views.sessionInfoVerificationStatusTextView.setTextColor(ThemeUtils.getColor(context, R.attr.colorPrimary)) + views.sessionInfoVerificationStatusDetailTextView.text = context.getString(R.string.device_manager_verification_status_detail_verified) + views.sessionInfoVerifySessionButton.isVisible = false + } + + private fun renderCrossSigningUnverified() { + views.sessionInfoVerificationStatusTextView.text = context.getString(R.string.device_manager_verification_status_unverified) + views.sessionInfoVerificationStatusTextView.setTextColor(ThemeUtils.getColor(context, R.attr.colorError)) + views.sessionInfoVerificationStatusDetailTextView.text = context.getString(R.string.device_manager_verification_status_detail_unverified) + views.sessionInfoVerifySessionButton.isVisible = true + } + + // TODO. We don't have this info yet. Update later accordingly. + private fun renderDeviceInfo(sessionName: String) { + views.sessionInfoDeviceTypeImageView.setImageResource(R.drawable.ic_device_type_mobile) + views.sessionInfoDeviceTypeImageView.contentDescription = context.getString(R.string.a11y_device_manager_device_type_mobile) + views.sessionInfoNameTextView.text = sessionName + } +} diff --git a/vector/src/main/res/layout/view_current_session.xml b/vector/src/main/res/layout/view_session_info.xml similarity index 78% rename from vector/src/main/res/layout/view_current_session.xml rename to vector/src/main/res/layout/view_session_info.xml index 91977eba40..015f4961c9 100644 --- a/vector/src/main/res/layout/view_current_session.xml +++ b/vector/src/main/res/layout/view_session_info.xml @@ -8,7 +8,7 @@ android:paddingBottom="16dp"> + app:layout_constraintTop_toBottomOf="@id/sessionInfoNameTextView">