Account deactivation.
This commit is contained in:
parent
b94a5c9c51
commit
b87bec6228
29 changed files with 1071 additions and 9 deletions
|
|
@ -20,6 +20,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push
|
|||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.features.deactivation.api.AccountDeactivationEntryPoint
|
||||
import io.element.android.features.licenses.api.OpenSourceLicensesEntryPoint
|
||||
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
||||
import io.element.android.features.logout.api.LogoutEntryPoint
|
||||
|
|
@ -52,6 +53,7 @@ class PreferencesFlowNode @AssistedInject constructor(
|
|||
private val notificationTroubleShootEntryPoint: NotificationTroubleShootEntryPoint,
|
||||
private val logoutEntryPoint: LogoutEntryPoint,
|
||||
private val openSourceLicensesEntryPoint: OpenSourceLicensesEntryPoint,
|
||||
private val accountDeactivationEntryPoint: AccountDeactivationEntryPoint,
|
||||
) : BaseFlowNode<PreferencesFlowNode.NavTarget>(
|
||||
backstack = BackStack(
|
||||
initialElement = plugins.filterIsInstance<PreferencesEntryPoint.Params>().first().initialElement.toNavTarget(),
|
||||
|
|
@ -100,6 +102,9 @@ class PreferencesFlowNode @AssistedInject constructor(
|
|||
@Parcelize
|
||||
data object SignOut : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object AccountDeactivation : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data object OssLicenses : NavTarget
|
||||
}
|
||||
|
|
@ -151,6 +156,10 @@ class PreferencesFlowNode @AssistedInject constructor(
|
|||
override fun onSignOutClick() {
|
||||
backstack.push(NavTarget.SignOut)
|
||||
}
|
||||
|
||||
override fun onOpenAccountDeactivation() {
|
||||
backstack.push(NavTarget.AccountDeactivation)
|
||||
}
|
||||
}
|
||||
createNode<PreferencesRootNode>(buildContext, plugins = listOf(callback))
|
||||
}
|
||||
|
|
@ -236,6 +245,9 @@ class PreferencesFlowNode @AssistedInject constructor(
|
|||
is NavTarget.OssLicenses -> {
|
||||
openSourceLicensesEntryPoint.getNode(this, buildContext)
|
||||
}
|
||||
NavTarget.AccountDeactivation -> {
|
||||
accountDeactivationEntryPoint.createNode(this, buildContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class PreferencesRootNode @AssistedInject constructor(
|
|||
fun onOpenUserProfile(matrixUser: MatrixUser)
|
||||
fun onOpenBlockedUsers()
|
||||
fun onSignOutClick()
|
||||
fun onOpenAccountDeactivation()
|
||||
}
|
||||
|
||||
private fun onOpenBugReport() {
|
||||
|
|
@ -105,6 +106,10 @@ class PreferencesRootNode @AssistedInject constructor(
|
|||
plugins<Callback>().forEach { it.onSignOutClick() }
|
||||
}
|
||||
|
||||
private fun onOpenAccountDeactivation() {
|
||||
plugins<Callback>().forEach { it.onOpenAccountDeactivation() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
|
|
@ -132,6 +137,7 @@ class PreferencesRootNode @AssistedInject constructor(
|
|||
onSignOutClick()
|
||||
}
|
||||
},
|
||||
onDeactivateClick = this::onOpenAccountDeactivation
|
||||
)
|
||||
|
||||
directLogoutView.Render(
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import io.element.android.features.logout.api.direct.DirectLogoutPresenter
|
||||
import io.element.android.features.preferences.impl.utils.ShowDeveloperSettingsProvider
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
|
|
@ -75,6 +76,12 @@ class PreferencesRootPresenter @Inject constructor(
|
|||
val devicesManagementUrl: MutableState<String?> = remember {
|
||||
mutableStateOf(null)
|
||||
}
|
||||
var canDeactivateAccount by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
canDeactivateAccount = matrixClient.canDeactivateAccount()
|
||||
}
|
||||
|
||||
val showBlockedUsersItem by produceState(initialValue = false) {
|
||||
matrixClient.ignoredUsersFlow
|
||||
|
|
@ -108,6 +115,7 @@ class PreferencesRootPresenter @Inject constructor(
|
|||
devicesManagementUrl = devicesManagementUrl.value,
|
||||
showAnalyticsSettings = hasAnalyticsProviders,
|
||||
showDeveloperSettings = showDeveloperSettings,
|
||||
canDeactivateAccount = canDeactivateAccount,
|
||||
showNotificationSettings = showNotificationSettings.value,
|
||||
showLockScreenSettings = showLockScreenSettings.value,
|
||||
showBlockedUsersItem = showBlockedUsersItem,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ data class PreferencesRootState(
|
|||
val devicesManagementUrl: String?,
|
||||
val showAnalyticsSettings: Boolean,
|
||||
val showDeveloperSettings: Boolean,
|
||||
val canDeactivateAccount: Boolean,
|
||||
val showLockScreenSettings: Boolean,
|
||||
val showNotificationSettings: Boolean,
|
||||
val showBlockedUsersItem: Boolean,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ fun aPreferencesRootState(
|
|||
showNotificationSettings = true,
|
||||
showLockScreenSettings = true,
|
||||
showBlockedUsersItem = true,
|
||||
canDeactivateAccount = true,
|
||||
snackbarMessage = SnackbarMessage(CommonStrings.common_verification_complete),
|
||||
directLogoutState = aDirectLogoutState(),
|
||||
eventSink = eventSink,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ fun PreferencesRootView(
|
|||
onOpenUserProfile: (MatrixUser) -> Unit,
|
||||
onOpenBlockedUsers: () -> Unit,
|
||||
onSignOutClick: () -> Unit,
|
||||
onDeactivateClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage)
|
||||
|
|
@ -99,6 +100,7 @@ fun PreferencesRootView(
|
|||
onOpenAdvancedSettings = onOpenAdvancedSettings,
|
||||
onOpenDeveloperSettings = onOpenDeveloperSettings,
|
||||
onSignOutClick = onSignOutClick,
|
||||
onDeactivateClick = onDeactivateClick,
|
||||
)
|
||||
|
||||
Footer(
|
||||
|
|
@ -193,6 +195,7 @@ private fun ColumnScope.GeneralSection(
|
|||
onOpenAdvancedSettings: () -> Unit,
|
||||
onOpenDeveloperSettings: () -> Unit,
|
||||
onSignOutClick: () -> Unit,
|
||||
onDeactivateClick: () -> Unit,
|
||||
) {
|
||||
ListItem(
|
||||
headlineContent = { Text(stringResource(id = CommonStrings.common_about)) },
|
||||
|
|
@ -225,6 +228,14 @@ private fun ColumnScope.GeneralSection(
|
|||
style = ListItemStyle.Destructive,
|
||||
onClick = onSignOutClick,
|
||||
)
|
||||
if (state.canDeactivateAccount) {
|
||||
ListItem(
|
||||
headlineContent = { Text(stringResource(id = CommonStrings.action_deactivate_account)) },
|
||||
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Warning())),
|
||||
style = ListItemStyle.Destructive,
|
||||
onClick = onDeactivateClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -292,5 +303,6 @@ private fun ContentToPreview(matrixUser: MatrixUser) {
|
|||
onOpenUserProfile = {},
|
||||
onOpenBlockedUsers = {},
|
||||
onSignOutClick = {},
|
||||
onDeactivateClick = {},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package io.element.android.features.preferences.impl.root
|
|||
import androidx.compose.runtime.Composable
|
||||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.ReceiveTurbine
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.logout.api.direct.DirectLogoutPresenter
|
||||
|
|
@ -45,7 +46,7 @@ class PreferencesRootPresenterTest {
|
|||
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val matrixClient = FakeMatrixClient()
|
||||
val matrixClient = FakeMatrixClient(canDeactivateAccountResult = { true })
|
||||
val presenter = createPresenter(matrixClient = matrixClient)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
|
|
@ -76,11 +77,27 @@ class PreferencesRootPresenterTest {
|
|||
assertThat(loadedState.showDeveloperSettings).isTrue()
|
||||
assertThat(loadedState.showLockScreenSettings).isTrue()
|
||||
assertThat(loadedState.showNotificationSettings).isTrue()
|
||||
assertThat(loadedState.canDeactivateAccount).isTrue()
|
||||
assertThat(loadedState.directLogoutState).isEqualTo(aDirectLogoutState)
|
||||
assertThat(loadedState.snackbarMessage).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - can deactivate account is false if the Matrix client say so`() = runTest {
|
||||
val presenter = createPresenter(
|
||||
matrixClient = FakeMatrixClient(
|
||||
canDeactivateAccountResult = { false }
|
||||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val loadedState = awaitFirstItem()
|
||||
assertThat(loadedState.canDeactivateAccount).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - developer settings is hidden by default in release builds`() = runTest {
|
||||
val presenter = createPresenter(
|
||||
|
|
@ -89,8 +106,7 @@ class PreferencesRootPresenterTest {
|
|||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(1)
|
||||
val loadedState = awaitItem()
|
||||
val loadedState = awaitFirstItem()
|
||||
assertThat(loadedState.showDeveloperSettings).isFalse()
|
||||
}
|
||||
}
|
||||
|
|
@ -103,20 +119,22 @@ class PreferencesRootPresenterTest {
|
|||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(1)
|
||||
val loadedState = awaitItem()
|
||||
|
||||
val loadedState = awaitFirstItem()
|
||||
repeat(times = ShowDeveloperSettingsProvider.DEVELOPER_SETTINGS_COUNTER) {
|
||||
assertThat(loadedState.showDeveloperSettings).isFalse()
|
||||
loadedState.eventSink(PreferencesRootEvents.OnVersionInfoClick)
|
||||
}
|
||||
|
||||
assertThat(awaitItem().showDeveloperSettings).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun <T> ReceiveTurbine<T>.awaitFirstItem(): T {
|
||||
skipItems(1)
|
||||
return awaitItem()
|
||||
}
|
||||
|
||||
private fun createPresenter(
|
||||
matrixClient: FakeMatrixClient = FakeMatrixClient(),
|
||||
matrixClient: FakeMatrixClient = FakeMatrixClient(canDeactivateAccountResult = { true }),
|
||||
sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(),
|
||||
showDeveloperSettingsProvider: ShowDeveloperSettingsProvider = ShowDeveloperSettingsProvider(aBuildMeta(BuildType.DEBUG)),
|
||||
) = PreferencesRootPresenter(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue