Skip to content

Commit 5d4313a

Browse files
authored
Merge pull request #1832 from vector-im/renovate/org.matrix.rustcomponents-sdk-android-0.x
Update dependency org.matrix.rustcomponents:sdk-android to v0.1.68
2 parents e0a01e9 + e7c864c commit 5d4313a

File tree

26 files changed

+210
-33
lines changed

26 files changed

+210
-33
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.features.securebackup.impl.root
18+
19+
sealed interface SecureBackupRootEvents {
20+
data object RetryKeyBackupState : SecureBackupRootEvents
21+
}

features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootPresenter.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,24 @@
1717
package io.element.android.features.securebackup.impl.root
1818

1919
import androidx.compose.runtime.Composable
20+
import androidx.compose.runtime.LaunchedEffect
21+
import androidx.compose.runtime.MutableState
2022
import androidx.compose.runtime.collectAsState
2123
import androidx.compose.runtime.getValue
24+
import androidx.compose.runtime.mutableStateOf
25+
import androidx.compose.runtime.remember
26+
import androidx.compose.runtime.rememberCoroutineScope
2227
import io.element.android.features.securebackup.impl.loggerTagRoot
28+
import io.element.android.libraries.architecture.Async
2329
import io.element.android.libraries.architecture.Presenter
30+
import io.element.android.libraries.architecture.runCatchingUpdatingState
2431
import io.element.android.libraries.core.meta.BuildMeta
2532
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
2633
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
34+
import io.element.android.libraries.matrix.api.encryption.BackupState
2735
import io.element.android.libraries.matrix.api.encryption.EncryptionService
36+
import kotlinx.coroutines.CoroutineScope
37+
import kotlinx.coroutines.launch
2838
import timber.log.Timber
2939
import javax.inject.Inject
3040

@@ -36,6 +46,7 @@ class SecureBackupRootPresenter @Inject constructor(
3646

3747
@Composable
3848
override fun present(): SecureBackupRootState {
49+
val localCoroutineScope = rememberCoroutineScope()
3950
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
4051

4152
val backupState by encryptionService.backupStateStateFlow.collectAsState()
@@ -44,11 +55,33 @@ class SecureBackupRootPresenter @Inject constructor(
4455
Timber.tag(loggerTagRoot.value).d("backupState: $backupState")
4556
Timber.tag(loggerTagRoot.value).d("recoveryState: $recoveryState")
4657

58+
val doesBackupExistOnServerAction: MutableState<Async<Boolean>> = remember { mutableStateOf(Async.Uninitialized) }
59+
60+
LaunchedEffect(backupState) {
61+
if (backupState == BackupState.UNKNOWN) {
62+
getKeyBackupStatus(doesBackupExistOnServerAction)
63+
}
64+
}
65+
66+
fun handleEvents(event: SecureBackupRootEvents) {
67+
when (event) {
68+
SecureBackupRootEvents.RetryKeyBackupState -> localCoroutineScope.getKeyBackupStatus(doesBackupExistOnServerAction)
69+
}
70+
}
71+
4772
return SecureBackupRootState(
4873
backupState = backupState,
74+
doesBackupExistOnServer = doesBackupExistOnServerAction.value,
4975
recoveryState = recoveryState,
5076
appName = buildMeta.applicationName,
5177
snackbarMessage = snackbarMessage,
78+
eventSink = ::handleEvents,
5279
)
5380
}
81+
82+
private fun CoroutineScope.getKeyBackupStatus(action: MutableState<Async<Boolean>>) = launch {
83+
suspend {
84+
encryptionService.doesBackupExistOnServer().getOrThrow()
85+
}.runCatchingUpdatingState(action)
86+
}
5487
}

features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootState.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616

1717
package io.element.android.features.securebackup.impl.root
1818

19+
import io.element.android.libraries.architecture.Async
1920
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
2021
import io.element.android.libraries.matrix.api.encryption.BackupState
2122
import io.element.android.libraries.matrix.api.encryption.RecoveryState
2223

2324
data class SecureBackupRootState(
2425
val backupState: BackupState,
26+
val doesBackupExistOnServer: Async<Boolean>,
2527
val recoveryState: RecoveryState,
2628
val appName: String,
2729
val snackbarMessage: SnackbarMessage?,
30+
val eventSink: (SecureBackupRootEvents) -> Unit,
2831
)

features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootStateProvider.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@
1717
package io.element.android.features.securebackup.impl.root
1818

1919
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
20+
import io.element.android.libraries.architecture.Async
2021
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
2122
import io.element.android.libraries.matrix.api.encryption.BackupState
2223
import io.element.android.libraries.matrix.api.encryption.RecoveryState
2324

2425
open class SecureBackupRootStateProvider : PreviewParameterProvider<SecureBackupRootState> {
2526
override val values: Sequence<SecureBackupRootState>
2627
get() = sequenceOf(
27-
aSecureBackupRootState(backupState = BackupState.UNKNOWN),
28+
aSecureBackupRootState(backupState = BackupState.UNKNOWN, doesBackupExistOnServer = Async.Uninitialized),
29+
aSecureBackupRootState(backupState = BackupState.UNKNOWN, doesBackupExistOnServer = Async.Success(true)),
30+
aSecureBackupRootState(backupState = BackupState.UNKNOWN, doesBackupExistOnServer = Async.Success(false)),
31+
aSecureBackupRootState(backupState = BackupState.UNKNOWN, doesBackupExistOnServer = Async.Failure(Exception("An error"))),
2832
aSecureBackupRootState(backupState = BackupState.ENABLED),
29-
aSecureBackupRootState(backupState = BackupState.DISABLED),
3033
aSecureBackupRootState(recoveryState = RecoveryState.UNKNOWN),
3134
aSecureBackupRootState(recoveryState = RecoveryState.ENABLED),
3235
aSecureBackupRootState(recoveryState = RecoveryState.DISABLED),
@@ -37,11 +40,14 @@ open class SecureBackupRootStateProvider : PreviewParameterProvider<SecureBackup
3740

3841
fun aSecureBackupRootState(
3942
backupState: BackupState = BackupState.UNKNOWN,
43+
doesBackupExistOnServer: Async<Boolean> = Async.Uninitialized,
4044
recoveryState: RecoveryState = RecoveryState.UNKNOWN,
4145
snackbarMessage: SnackbarMessage? = null,
4246
) = SecureBackupRootState(
4347
backupState = backupState,
48+
doesBackupExistOnServer = doesBackupExistOnServer,
4449
recoveryState = recoveryState,
4550
appName = "Element",
4651
snackbarMessage = snackbarMessage,
52+
eventSink = {},
4753
)

features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootView.kt

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,27 @@
1616

1717
package io.element.android.features.securebackup.impl.root
1818

19+
import androidx.compose.foundation.layout.Arrangement
20+
import androidx.compose.foundation.layout.Row
21+
import androidx.compose.foundation.layout.fillMaxWidth
1922
import androidx.compose.runtime.Composable
2023
import androidx.compose.ui.Modifier
2124
import androidx.compose.ui.res.stringResource
2225
import androidx.compose.ui.tooling.preview.PreviewParameter
2326
import io.element.android.features.securebackup.impl.R
27+
import io.element.android.libraries.architecture.Async
2428
import io.element.android.libraries.designsystem.components.async.AsyncLoading
29+
import io.element.android.libraries.designsystem.components.list.ListItemContent
2530
import io.element.android.libraries.designsystem.components.preferences.PreferenceDivider
2631
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
2732
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
2833
import io.element.android.libraries.designsystem.preview.ElementPreview
2934
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
3035
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
36+
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
37+
import io.element.android.libraries.designsystem.theme.components.ListItem
38+
import io.element.android.libraries.designsystem.theme.components.Text
39+
import io.element.android.libraries.designsystem.theme.components.TextButton
3140
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
3241
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
3342
import io.element.android.libraries.matrix.api.encryption.BackupState
@@ -70,13 +79,58 @@ fun SecureBackupRootView(
7079

7180
// Disable / Enable backup
7281
when (state.backupState) {
73-
BackupState.WAITING_FOR_SYNC,
74-
BackupState.UNKNOWN -> Unit
75-
BackupState.DISABLED -> {
76-
PreferenceText(
77-
title = stringResource(id = R.string.screen_chat_backup_key_backup_action_enable),
78-
onClick = onEnableClicked,
79-
)
82+
BackupState.WAITING_FOR_SYNC -> Unit
83+
BackupState.UNKNOWN -> {
84+
when (state.doesBackupExistOnServer) {
85+
is Async.Success -> when (state.doesBackupExistOnServer.data) {
86+
true -> {
87+
PreferenceText(
88+
title = stringResource(id = R.string.screen_chat_backup_key_backup_action_disable),
89+
tintColor = ElementTheme.colors.textCriticalPrimary,
90+
onClick = onDisableClicked,
91+
)
92+
}
93+
false -> {
94+
PreferenceText(
95+
title = stringResource(id = R.string.screen_chat_backup_key_backup_action_enable),
96+
onClick = onEnableClicked,
97+
)
98+
}
99+
}
100+
is Async.Loading,
101+
Async.Uninitialized -> {
102+
ListItem(headlineContent = {
103+
Row(
104+
modifier = Modifier.fillMaxWidth(),
105+
horizontalArrangement = Arrangement.Center,
106+
) {
107+
CircularProgressIndicator()
108+
}
109+
})
110+
}
111+
is Async.Failure -> {
112+
ListItem(
113+
headlineContent = {
114+
Text(
115+
text = stringResource(id = CommonStrings.error_unknown),
116+
)
117+
},
118+
trailingContent = ListItemContent.Custom {
119+
TextButton(
120+
text = stringResource(
121+
id = CommonStrings.action_retry
122+
),
123+
onClick = { state.eventSink.invoke(SecureBackupRootEvents.RetryKeyBackupState) }
124+
)
125+
}
126+
)
127+
128+
PreferenceText(
129+
title = stringResource(id = R.string.screen_chat_backup_key_backup_action_enable),
130+
onClick = onEnableClicked,
131+
)
132+
}
133+
}
80134
}
81135
BackupState.CREATING,
82136
BackupState.ENABLING,

features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootPresenterTest.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ import app.cash.molecule.RecompositionMode
2020
import app.cash.molecule.moleculeFlow
2121
import app.cash.turbine.test
2222
import com.google.common.truth.Truth.assertThat
23+
import io.element.android.libraries.architecture.Async
2324
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
2425
import io.element.android.libraries.matrix.api.encryption.BackupState
2526
import io.element.android.libraries.matrix.api.encryption.EncryptionService
27+
import io.element.android.libraries.matrix.api.encryption.RecoveryState
28+
import io.element.android.libraries.matrix.test.AN_EXCEPTION
2629
import io.element.android.libraries.matrix.test.core.aBuildMeta
2730
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
2831
import io.element.android.tests.testutils.WarmUpRule
@@ -40,9 +43,39 @@ class SecureBackupRootPresenterTest {
4043
moleculeFlow(RecompositionMode.Immediate) {
4144
presenter.present()
4245
}.test {
46+
skipItems(2)
4347
val initialState = awaitItem()
4448
assertThat(initialState.backupState).isEqualTo(BackupState.UNKNOWN)
49+
assertThat(initialState.doesBackupExistOnServer.dataOrNull()).isTrue()
50+
assertThat(initialState.recoveryState).isEqualTo(RecoveryState.UNKNOWN)
4551
assertThat(initialState.appName).isEqualTo("Element")
52+
assertThat(initialState.snackbarMessage).isNull()
53+
}
54+
}
55+
56+
@Test
57+
fun `present - Unknown state`() = runTest {
58+
val encryptionService = FakeEncryptionService()
59+
val presenter = createSecureBackupRootPresenter(
60+
encryptionService = encryptionService,
61+
)
62+
moleculeFlow(RecompositionMode.Immediate) {
63+
presenter.present()
64+
}.test {
65+
val initialState = awaitItem()
66+
encryptionService.givenDoesBackupExistOnServerResult(Result.failure(AN_EXCEPTION))
67+
assertThat(initialState.backupState).isEqualTo(BackupState.UNKNOWN)
68+
assertThat(initialState.doesBackupExistOnServer).isEqualTo(Async.Uninitialized)
69+
val loadingState1 = awaitItem()
70+
assertThat(loadingState1.doesBackupExistOnServer).isInstanceOf(Async.Loading::class.java)
71+
val errorState = awaitItem()
72+
assertThat(errorState.doesBackupExistOnServer).isEqualTo(Async.Failure<Boolean>(AN_EXCEPTION))
73+
encryptionService.givenDoesBackupExistOnServerResult(Result.success(false))
74+
errorState.eventSink.invoke(SecureBackupRootEvents.RetryKeyBackupState)
75+
val loadingState2 = awaitItem()
76+
assertThat(loadingState2.doesBackupExistOnServer).isInstanceOf(Async.Loading::class.java)
77+
val finalState = awaitItem()
78+
assertThat(finalState.doesBackupExistOnServer.dataOrNull()).isFalse()
4679
}
4780
}
4881

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ jsoup = "org.jsoup:jsoup:1.16.2"
144144
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
145145
molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.0"
146146
timber = "com.jakewharton.timber:timber:5.0.1"
147-
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.67"
147+
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.68"
148148
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
149149
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
150150
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }

libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupState.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,5 @@ enum class BackupState {
3131
RESUMING,
3232
ENABLED,
3333
DOWNLOADING,
34-
DISABLING,
35-
DISABLED;
34+
DISABLING;
3635
}

libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ interface EncryptionService {
4040

4141
suspend fun disableRecovery(): Result<Unit>
4242

43+
suspend fun doesBackupExistOnServer(): Result<Boolean>
44+
4345
/**
4446
* Note: accept bot recoveryKey and passphrase.
4547
*/

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/BackupStateMapper.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ class BackupStateMapper {
2929
RustBackupState.ENABLED -> BackupState.ENABLED
3030
RustBackupState.DOWNLOADING -> BackupState.DOWNLOADING
3131
RustBackupState.DISABLING -> BackupState.DISABLING
32-
RustBackupState.DISABLED -> BackupState.DISABLED
3332
}
3433
}
3534
}

0 commit comments

Comments
 (0)