Skip to content

Commit d0666e1

Browse files
authored
Merge pull request #1314 from vector-im/feature/bma/manageAccountAndDevice
Manage account and device
2 parents 0f73d83 + 7f39e17 commit d0666e1

File tree

16 files changed

+117
-27
lines changed

16 files changed

+117
-27
lines changed

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import dagger.assisted.AssistedInject
2929
import io.element.android.anvilannotations.ContributesNode
3030
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
3131
import io.element.android.libraries.di.SessionScope
32+
import io.element.android.libraries.theme.ElementTheme
3233
import timber.log.Timber
3334

3435
@ContributesNode(SessionScope::class)
@@ -67,9 +68,17 @@ class PreferencesRootNode @AssistedInject constructor(
6768
plugins<Callback>().forEach { it.onOpenAbout() }
6869
}
6970

70-
private fun onManageAccountClicked(activity: Activity, accountManagementUrl: String?) {
71-
accountManagementUrl?.let {
72-
activity.openUrlInChromeCustomTab(null, false, it)
71+
private fun onManageAccountClicked(
72+
activity: Activity,
73+
url: String?,
74+
isDark: Boolean,
75+
) {
76+
url?.let {
77+
activity.openUrlInChromeCustomTab(
78+
null,
79+
darkTheme = isDark,
80+
url = it
81+
)
7382
}
7483
}
7584

@@ -81,6 +90,7 @@ class PreferencesRootNode @AssistedInject constructor(
8190
override fun View(modifier: Modifier) {
8291
val state = presenter.present()
8392
val activity = LocalContext.current as Activity
93+
val isDark = ElementTheme.isLightTheme.not()
8494
PreferencesRootView(
8595
state = state,
8696
modifier = modifier,
@@ -91,7 +101,7 @@ class PreferencesRootNode @AssistedInject constructor(
91101
onVerifyClicked = this::onVerifyClicked,
92102
onOpenDeveloperSettings = this::onOpenDeveloperSettings,
93103
onSuccessLogout = { onSuccessLogout(activity, it) },
94-
onManageAccountClicked = { onManageAccountClicked(activity, state.accountManagementUrl) },
104+
onManageAccountClicked = { onManageAccountClicked(activity, it, isDark) },
95105
onOpenNotificationSettings = this::onOpenNotificationSettings
96106
)
97107
}

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import io.element.android.libraries.designsystem.utils.collectSnackbarMessageAsS
3232
import io.element.android.libraries.featureflag.api.FeatureFlagService
3333
import io.element.android.libraries.featureflag.api.FeatureFlags
3434
import io.element.android.libraries.matrix.api.MatrixClient
35+
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
3536
import io.element.android.libraries.matrix.api.user.MatrixUser
3637
import io.element.android.libraries.matrix.api.user.getCurrentUser
3738
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
@@ -74,9 +75,12 @@ class PreferencesRootPresenter @Inject constructor(
7475
val accountManagementUrl: MutableState<String?> = remember {
7576
mutableStateOf(null)
7677
}
78+
val devicesManagementUrl: MutableState<String?> = remember {
79+
mutableStateOf(null)
80+
}
7781

7882
LaunchedEffect(Unit) {
79-
initAccountManagementUrl(accountManagementUrl)
83+
initAccountManagementUrl(accountManagementUrl, devicesManagementUrl)
8084
}
8185

8286
val logoutState = logoutPresenter.present()
@@ -87,6 +91,7 @@ class PreferencesRootPresenter @Inject constructor(
8791
version = versionFormatter.get(),
8892
showCompleteVerification = showCompleteVerification,
8993
accountManagementUrl = accountManagementUrl.value,
94+
devicesManagementUrl = devicesManagementUrl.value,
9095
showAnalyticsSettings = hasAnalyticsProviders,
9196
showDeveloperSettings = showDeveloperSettings,
9297
showNotificationSettings = showNotificationSettings.value,
@@ -98,7 +103,11 @@ class PreferencesRootPresenter @Inject constructor(
98103
matrixUser.value = matrixClient.getCurrentUser()
99104
}
100105

101-
private fun CoroutineScope.initAccountManagementUrl(accountManagementUrl: MutableState<String?>) = launch {
102-
accountManagementUrl.value = matrixClient.getAccountManagementUrl().getOrNull()
106+
private fun CoroutineScope.initAccountManagementUrl(
107+
accountManagementUrl: MutableState<String?>,
108+
devicesManagementUrl: MutableState<String?>,
109+
) = launch {
110+
accountManagementUrl.value = matrixClient.getAccountManagementUrl(AccountManagementAction.Profile).getOrNull()
111+
devicesManagementUrl.value = matrixClient.getAccountManagementUrl(AccountManagementAction.SessionsList).getOrNull()
103112
}
104113
}

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootState.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ data class PreferencesRootState(
2626
val version: String,
2727
val showCompleteVerification: Boolean,
2828
val accountManagementUrl: String?,
29+
val devicesManagementUrl: String?,
2930
val showAnalyticsSettings: Boolean,
3031
val showDeveloperSettings: Boolean,
3132
val showNotificationSettings: Boolean,

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootStateProvider.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ fun aPreferencesRootState() = PreferencesRootState(
2626
version = "Version 1.1 (1)",
2727
showCompleteVerification = true,
2828
accountManagementUrl = "aUrl",
29+
devicesManagementUrl = "anOtherUrl",
2930
showAnalyticsSettings = true,
3031
showDeveloperSettings = true,
3132
showNotificationSettings = true,

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import androidx.compose.material.icons.outlined.BugReport
2323
import androidx.compose.material.icons.outlined.DeveloperMode
2424
import androidx.compose.material.icons.outlined.Help
2525
import androidx.compose.material.icons.outlined.InsertChart
26-
import androidx.compose.material.icons.outlined.ManageAccounts
2726
import androidx.compose.material.icons.outlined.Notifications
27+
import androidx.compose.material.icons.outlined.OpenInNew
2828
import androidx.compose.material.icons.outlined.VerifiedUser
2929
import androidx.compose.runtime.Composable
3030
import androidx.compose.ui.Modifier
@@ -53,7 +53,7 @@ fun PreferencesRootView(
5353
state: PreferencesRootState,
5454
onBackPressed: () -> Unit,
5555
onVerifyClicked: () -> Unit,
56-
onManageAccountClicked: () -> Unit,
56+
onManageAccountClicked: (url: String) -> Unit,
5757
onOpenAnalytics: () -> Unit,
5858
onOpenRageShake: () -> Unit,
5959
onOpenAbout: () -> Unit,
@@ -82,10 +82,11 @@ fun PreferencesRootView(
8282
}
8383
if (state.accountManagementUrl != null) {
8484
PreferenceText(
85-
title = stringResource(id = CommonStrings.screen_settings_oidc_account),
86-
icon = Icons.Outlined.ManageAccounts,
87-
onClick = onManageAccountClicked,
85+
title = stringResource(id = CommonStrings.action_manage_account),
86+
icon = Icons.Outlined.OpenInNew,
87+
onClick = { onManageAccountClicked(state.accountManagementUrl) },
8888
)
89+
HorizontalDivider()
8990
}
9091
if (state.showAnalyticsSettings) {
9192
PreferenceText(
@@ -94,7 +95,7 @@ fun PreferencesRootView(
9495
onClick = onOpenAnalytics,
9596
)
9697
}
97-
if(state.showNotificationSettings) {
98+
if (state.showNotificationSettings) {
9899
PreferenceText(
99100
title = stringResource(id = CommonStrings.screen_notification_settings_title),
100101
icon = Icons.Outlined.Notifications,
@@ -111,10 +112,19 @@ fun PreferencesRootView(
111112
icon = Icons.Outlined.Help,
112113
onClick = onOpenAbout,
113114
)
115+
HorizontalDivider()
116+
if (state.devicesManagementUrl != null) {
117+
PreferenceText(
118+
title = stringResource(id = CommonStrings.action_manage_devices),
119+
icon = Icons.Outlined.OpenInNew,
120+
onClick = { onManageAccountClicked(state.devicesManagementUrl) },
121+
)
122+
HorizontalDivider()
123+
}
114124
if (state.showDeveloperSettings) {
115125
DeveloperPreferencesView(onOpenDeveloperSettings)
126+
HorizontalDivider()
116127
}
117-
HorizontalDivider()
118128
LogoutPreferenceView(
119129
state = state.logoutState,
120130
onSuccessLogout = onSuccessLogout,

features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class PreferencesRootPresenterTest {
7373
assertThat(loadedState.showDeveloperSettings).isEqualTo(true)
7474
assertThat(loadedState.showAnalyticsSettings).isEqualTo(false)
7575
assertThat(loadedState.accountManagementUrl).isNull()
76+
assertThat(loadedState.devicesManagementUrl).isNull()
7677
}
7778
}
7879
}

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
149149
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
150150
molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" }
151151
timber = "com.jakewharton.timber:timber:5.0.1"
152-
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.51"
152+
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.52"
153153
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
154154
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
155155
sqldelight-driver-android = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" }

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
2424
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
2525
import io.element.android.libraries.matrix.api.notification.NotificationService
2626
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
27+
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
2728
import io.element.android.libraries.matrix.api.pusher.PushersService
2829
import io.element.android.libraries.matrix.api.room.MatrixRoom
2930
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
@@ -66,7 +67,7 @@ interface MatrixClient : Closeable {
6667
suspend fun logout(): String?
6768
suspend fun loadUserDisplayName(): Result<String>
6869
suspend fun loadUserAvatarURLString(): Result<String?>
69-
suspend fun getAccountManagementUrl(): Result<String?>
70+
suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?>
7071
suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String>
7172
fun roomMembershipObserver(): RoomMembershipObserver
7273

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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.libraries.matrix.api.oidc
18+
19+
sealed interface AccountManagementAction {
20+
data object Profile : AccountManagementAction
21+
data object SessionsList : AccountManagementAction
22+
data class SessionView(val deviceId: String) : AccountManagementAction
23+
data class SessionEnd(val deviceId: String) : AccountManagementAction
24+
}

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.createroom.RoomVisibility
3030
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
3131
import io.element.android.libraries.matrix.api.notification.NotificationService
3232
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
33+
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
3334
import io.element.android.libraries.matrix.api.pusher.PushersService
3435
import io.element.android.libraries.matrix.api.room.MatrixRoom
3536
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
@@ -44,6 +45,7 @@ import io.element.android.libraries.matrix.impl.mapper.toSessionData
4445
import io.element.android.libraries.matrix.impl.media.RustMediaLoader
4546
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
4647
import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService
48+
import io.element.android.libraries.matrix.impl.oidc.toRustAction
4749
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
4850
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
4951
import io.element.android.libraries.matrix.impl.room.RustMatrixRoom
@@ -326,9 +328,10 @@ class RustMatrixClient constructor(
326328
return result
327329
}
328330

329-
override suspend fun getAccountManagementUrl(): Result<String?> = withContext(sessionDispatcher) {
331+
override suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?> = withContext(sessionDispatcher) {
332+
val rustAction = action?.toRustAction()
330333
runCatching {
331-
client.accountUrl()
334+
client.accountUrl(rustAction)
332335
}
333336
}
334337

0 commit comments

Comments
 (0)