Add "Complete verification" item in the root setting screen.
This commit is contained in:
parent
7b5d18aef4
commit
acec682dee
9 changed files with 46 additions and 9 deletions
|
|
@ -69,7 +69,6 @@ import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.debounce
|
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
@ -292,6 +291,10 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||||
override fun onOpenBugReport() {
|
override fun onOpenBugReport() {
|
||||||
plugins<Callback>().forEach { it.onOpenBugReport() }
|
plugins<Callback>().forEach { it.onOpenBugReport() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onVerifyClicked() {
|
||||||
|
backstack.push(NavTarget.VerifySession)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
preferencesEntryPoint.nodeBuilder(this, buildContext)
|
preferencesEntryPoint.nodeBuilder(this, buildContext)
|
||||||
.callback(callback)
|
.callback(callback)
|
||||||
|
|
|
||||||
|
|
@ -32,5 +32,6 @@ interface PreferencesEntryPoint : FeatureEntryPoint {
|
||||||
|
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun onOpenBugReport()
|
fun onOpenBugReport()
|
||||||
|
fun onVerifyClicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,10 @@ class PreferencesFlowNode @AssistedInject constructor(
|
||||||
plugins<PreferencesEntryPoint.Callback>().forEach { it.onOpenBugReport() }
|
plugins<PreferencesEntryPoint.Callback>().forEach { it.onOpenBugReport() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onVerifyClicked() {
|
||||||
|
plugins<PreferencesEntryPoint.Callback>().forEach { it.onVerifyClicked() }
|
||||||
|
}
|
||||||
|
|
||||||
override fun onOpenAnalytics() {
|
override fun onOpenAnalytics() {
|
||||||
backstack.push(NavTarget.AnalyticsSettings)
|
backstack.push(NavTarget.AnalyticsSettings)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ class PreferencesRootNode @AssistedInject constructor(
|
||||||
|
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun onOpenBugReport()
|
fun onOpenBugReport()
|
||||||
|
fun onVerifyClicked()
|
||||||
fun onOpenAnalytics()
|
fun onOpenAnalytics()
|
||||||
fun onOpenAbout()
|
fun onOpenAbout()
|
||||||
fun onOpenDeveloperSettings()
|
fun onOpenDeveloperSettings()
|
||||||
|
|
@ -45,6 +46,10 @@ class PreferencesRootNode @AssistedInject constructor(
|
||||||
plugins<Callback>().forEach { it.onOpenBugReport() }
|
plugins<Callback>().forEach { it.onOpenBugReport() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onVerifyClicked() {
|
||||||
|
plugins<Callback>().forEach { it.onVerifyClicked() }
|
||||||
|
}
|
||||||
|
|
||||||
private fun onOpenDeveloperSettings() {
|
private fun onOpenDeveloperSettings() {
|
||||||
plugins<Callback>().forEach { it.onOpenDeveloperSettings() }
|
plugins<Callback>().forEach { it.onOpenDeveloperSettings() }
|
||||||
}
|
}
|
||||||
|
|
@ -67,6 +72,7 @@ class PreferencesRootNode @AssistedInject constructor(
|
||||||
onOpenRageShake = this::onOpenBugReport,
|
onOpenRageShake = this::onOpenBugReport,
|
||||||
onOpenAnalytics = this::onOpenAnalytics,
|
onOpenAnalytics = this::onOpenAnalytics,
|
||||||
onOpenAbout = this::onOpenAbout,
|
onOpenAbout = this::onOpenAbout,
|
||||||
|
onVerifyClicked = this::onVerifyClicked,
|
||||||
onOpenDeveloperSettings = this::onOpenDeveloperSettings
|
onOpenDeveloperSettings = this::onOpenDeveloperSettings
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,19 @@ package io.element.android.features.preferences.impl.root
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import io.element.android.features.logout.api.LogoutPreferencePresenter
|
import io.element.android.features.logout.api.LogoutPreferencePresenter
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.core.meta.BuildType
|
import io.element.android.libraries.core.meta.BuildType
|
||||||
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
|
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
|
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -33,6 +39,7 @@ import javax.inject.Inject
|
||||||
class PreferencesRootPresenter @Inject constructor(
|
class PreferencesRootPresenter @Inject constructor(
|
||||||
private val logoutPresenter: LogoutPreferencePresenter,
|
private val logoutPresenter: LogoutPreferencePresenter,
|
||||||
private val currentUserProvider: CurrentUserProvider,
|
private val currentUserProvider: CurrentUserProvider,
|
||||||
|
private val sessionVerificationService: SessionVerificationService,
|
||||||
private val buildType: BuildType,
|
private val buildType: BuildType,
|
||||||
) : Presenter<PreferencesRootState> {
|
) : Presenter<PreferencesRootState> {
|
||||||
|
|
||||||
|
|
@ -45,11 +52,18 @@ class PreferencesRootPresenter @Inject constructor(
|
||||||
initialLoad(matrixUser)
|
initialLoad(matrixUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Session verification status (unknown, not verified, verified)
|
||||||
|
val sessionVerifiedStatus by sessionVerificationService.sessionVerifiedStatus.collectAsState()
|
||||||
|
val sessionIsNotVerified by remember {
|
||||||
|
derivedStateOf { sessionVerifiedStatus == SessionVerifiedStatus.NotVerified }
|
||||||
|
}
|
||||||
|
|
||||||
val logoutState = logoutPresenter.present()
|
val logoutState = logoutPresenter.present()
|
||||||
val showDeveloperSettings = buildType != BuildType.RELEASE
|
val showDeveloperSettings = buildType != BuildType.RELEASE
|
||||||
return PreferencesRootState(
|
return PreferencesRootState(
|
||||||
logoutState = logoutState,
|
logoutState = logoutState,
|
||||||
myUser = matrixUser.value,
|
myUser = matrixUser.value,
|
||||||
|
showCompleteVerification = sessionIsNotVerified,
|
||||||
showDeveloperSettings = showDeveloperSettings
|
showDeveloperSettings = showDeveloperSettings
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,5 +22,6 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
data class PreferencesRootState(
|
data class PreferencesRootState(
|
||||||
val logoutState: LogoutPreferenceState,
|
val logoutState: LogoutPreferenceState,
|
||||||
val myUser: MatrixUser?,
|
val myUser: MatrixUser?,
|
||||||
|
val showCompleteVerification: Boolean,
|
||||||
val showDeveloperSettings: Boolean
|
val showDeveloperSettings: Boolean
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -21,5 +21,6 @@ import io.element.android.features.logout.api.aLogoutPreferenceState
|
||||||
fun aPreferencesRootState() = PreferencesRootState(
|
fun aPreferencesRootState() = PreferencesRootState(
|
||||||
logoutState = aLogoutPreferenceState(),
|
logoutState = aLogoutPreferenceState(),
|
||||||
myUser = null,
|
myUser = null,
|
||||||
|
showCompleteVerification = true,
|
||||||
showDeveloperSettings = true
|
showDeveloperSettings = true
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,10 @@ package io.element.android.features.preferences.impl.root
|
||||||
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.DeveloperMode
|
import androidx.compose.material.icons.filled.DeveloperMode
|
||||||
import androidx.compose.material.icons.filled.Help
|
|
||||||
import androidx.compose.material.icons.outlined.BugReport
|
import androidx.compose.material.icons.outlined.BugReport
|
||||||
|
import androidx.compose.material.icons.outlined.Help
|
||||||
import androidx.compose.material.icons.outlined.InsertChart
|
import androidx.compose.material.icons.outlined.InsertChart
|
||||||
|
import androidx.compose.material.icons.outlined.VerifiedUser
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -42,6 +43,7 @@ fun PreferencesRootView(
|
||||||
state: PreferencesRootState,
|
state: PreferencesRootState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onBackPressed: () -> Unit,
|
onBackPressed: () -> Unit,
|
||||||
|
onVerifyClicked: () -> Unit,
|
||||||
onOpenAnalytics: () -> Unit,
|
onOpenAnalytics: () -> Unit,
|
||||||
onOpenRageShake: () -> Unit,
|
onOpenRageShake: () -> Unit,
|
||||||
onOpenAbout: () -> Unit,
|
onOpenAbout: () -> Unit,
|
||||||
|
|
@ -54,7 +56,14 @@ fun PreferencesRootView(
|
||||||
title = stringResource(id = CommonStrings.common_settings)
|
title = stringResource(id = CommonStrings.common_settings)
|
||||||
) {
|
) {
|
||||||
UserPreferences(state.myUser)
|
UserPreferences(state.myUser)
|
||||||
// TODO Verification and eventually divider
|
if (state.showCompleteVerification) {
|
||||||
|
PreferenceText(
|
||||||
|
title = stringResource(id = CommonStrings.action_complete_verification),
|
||||||
|
icon = Icons.Outlined.VerifiedUser,
|
||||||
|
onClick = onVerifyClicked,
|
||||||
|
)
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
title = stringResource(id = CommonStrings.common_analytics),
|
title = stringResource(id = CommonStrings.common_analytics),
|
||||||
icon = Icons.Outlined.InsertChart,
|
icon = Icons.Outlined.InsertChart,
|
||||||
|
|
@ -67,7 +76,7 @@ fun PreferencesRootView(
|
||||||
)
|
)
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
title = stringResource(id = CommonStrings.common_about),
|
title = stringResource(id = CommonStrings.common_about),
|
||||||
icon = Icons.Filled.Help,
|
icon = Icons.Outlined.Help,
|
||||||
onClick = onOpenAbout,
|
onClick = onOpenAbout,
|
||||||
)
|
)
|
||||||
if (state.showDeveloperSettings) {
|
if (state.showDeveloperSettings) {
|
||||||
|
|
@ -108,5 +117,6 @@ private fun ContentToPreview(matrixUser: MatrixUser) {
|
||||||
onOpenRageShake = {},
|
onOpenRageShake = {},
|
||||||
onOpenDeveloperSettings = {},
|
onOpenDeveloperSettings = {},
|
||||||
onOpenAbout = {},
|
onOpenAbout = {},
|
||||||
|
onVerifyClicked = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,19 +20,15 @@ import app.cash.molecule.RecompositionClock
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.analytics.impl.preferences.DefaultAnalyticsPreferencesPresenter
|
|
||||||
import io.element.android.features.analytics.test.A_BUILD_META
|
import io.element.android.features.analytics.test.A_BUILD_META
|
||||||
import io.element.android.features.analytics.test.FakeAnalyticsService
|
|
||||||
import io.element.android.features.logout.impl.DefaultLogoutPreferencePresenter
|
import io.element.android.features.logout.impl.DefaultLogoutPreferencePresenter
|
||||||
import io.element.android.features.rageshake.impl.preferences.DefaultRageshakePreferencesPresenter
|
|
||||||
import io.element.android.features.rageshake.test.rageshake.FakeRageShake
|
|
||||||
import io.element.android.features.rageshake.test.rageshake.FakeRageshakeDataStore
|
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
|
import io.element.android.libraries.matrix.api.user.CurrentUserProvider
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||||
import io.element.android.libraries.matrix.test.A_USER_NAME
|
import io.element.android.libraries.matrix.test.A_USER_NAME
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
|
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
|
@ -44,6 +40,7 @@ class PreferencesRootPresenterTest {
|
||||||
val presenter = PreferencesRootPresenter(
|
val presenter = PreferencesRootPresenter(
|
||||||
logoutPresenter,
|
logoutPresenter,
|
||||||
CurrentUserProvider(matrixClient),
|
CurrentUserProvider(matrixClient),
|
||||||
|
FakeSessionVerificationService(),
|
||||||
A_BUILD_META.buildType
|
A_BUILD_META.buildType
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue