diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt index e2cc328c31..59f699f862 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt @@ -78,7 +78,13 @@ class AccountSettingsFragment : ComposeFragment() { onAuthenticationFailed = { viewModel.onEvent(AccountSettingsEvent.AuthenticationFailed) } ) - CollectActions(viewModel.actions) { action -> handleAction(action, removalBiometrics, signalLoginBiometrics) } + val deleteAccountBiometrics = rememberBiometricsAuthentication( + promptTitle = stringResource(AppSettingsR.string.AccountSettingsFragment__unlock_to_confirm_its_you), + educationSheetMessage = stringResource(AppSettingsR.string.AccountSettingsFragment__to_delete_your_account_confirm_its_you), + onAuthenticationFailed = { viewModel.onEvent(AccountSettingsEvent.AuthenticationFailed) } + ) + + CollectActions(viewModel.actions) { action -> handleAction(action, removalBiometrics, signalLoginBiometrics, deleteAccountBiometrics) } AccountSettingsScreen( state = state, @@ -86,7 +92,12 @@ class AccountSettingsFragment : ComposeFragment() { ) } - private fun handleAction(action: AccountSettingsAction, removalBiometrics: BiometricsAuthentication, signalLoginBiometrics: BiometricsAuthentication) { + private fun handleAction( + action: AccountSettingsAction, + removalBiometrics: BiometricsAuthentication, + signalLoginBiometrics: BiometricsAuthentication, + deleteAccountBiometrics: BiometricsAuthentication + ) { when (action) { AccountSettingsAction.NavigateBack -> requireActivity().onBackPressedDispatcher.onBackPressed() AccountSettingsAction.LaunchCreatePinFlow -> pinFlowLauncher.launch(CreateSvrPinActivity.getIntentForPinCreate(requireContext())) @@ -118,6 +129,11 @@ class AccountSettingsFragment : ComposeFragment() { AccountSettingsAction.NavigateToChangePhoneNumber -> findNavController().safeNavigate(R.id.action_accountSettingsFragment_to_changePhoneNumberFragment) AccountSettingsAction.NavigateToDeviceTransfer -> findNavController().safeNavigate(R.id.action_accountSettingsFragment_to_oldDeviceTransferActivity) AccountSettingsAction.NavigateToExportAccountData -> findNavController().safeNavigate(R.id.action_accountSettingsFragment_to_exportAccountFragment) + AccountSettingsAction.AuthenticateToDeleteAccount -> { + deleteAccountBiometrics.withBiometricsAuthentication { + viewModel.onEvent(AccountSettingsEvent.DeleteAccountAuthenticated) + } + } AccountSettingsAction.NavigateToDeleteAccount -> findNavController().safeNavigate(R.id.action_accountSettingsFragment_to_deleteAccountFragment) AccountSettingsAction.OpenPlayStore -> PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext()) AccountSettingsAction.LaunchReRegistration -> startActivity(RegistrationActivity.newIntentForReRegistration(requireContext())) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt index 2c846fa09d..ea5f6c5a3f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt @@ -138,6 +138,9 @@ class AccountSettingsViewModel( _actions.send(AccountSettingsAction.ShowDataWipeFailed) } AccountSettingsEvent.DeleteAccountClicked -> { + _actions.send(AccountSettingsAction.AuthenticateToDeleteAccount) + } + AccountSettingsEvent.DeleteAccountAuthenticated -> { _actions.send(AccountSettingsAction.NavigateToDeleteAccount) } AccountSettingsEvent.DialogDismissed -> { diff --git a/app/src/test/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModelTest.kt b/app/src/test/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModelTest.kt index 309b727f3e..5863f985bf 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModelTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModelTest.kt @@ -591,6 +591,26 @@ class AccountSettingsViewModelTest { assertThat(actions.last()).isEqualTo(AccountSettingsAction.NavigateToSignalLoginDetails) } + @Test + fun `DeleteAccountClicked asks for the screen lock first`() = runTest(testDispatcher) { + val viewModel = createViewModel() + val actions = collectActions(viewModel.actions) + + viewModel.onEvent(AccountSettingsEvent.DeleteAccountClicked) + + assertThat(actions.last()).isEqualTo(AccountSettingsAction.AuthenticateToDeleteAccount) + } + + @Test + fun `DeleteAccountAuthenticated opens the delete account screen`() = runTest(testDispatcher) { + val viewModel = createViewModel() + val actions = collectActions(viewModel.actions) + + viewModel.onEvent(AccountSettingsEvent.DeleteAccountAuthenticated) + + assertThat(actions.last()).isEqualTo(AccountSettingsAction.NavigateToDeleteAccount) + } + private fun methods(vararg methods: TwoFactorMethod) = AccountSettingsRepository.TwoFactorMethodsResult.Success(methods.toList()) private fun createViewModel(): AccountSettingsViewModel = AccountSettingsViewModel(repository) diff --git a/feature/app-settings/src/main/java/org/signal/appsettings/account/AccountSettingsAction.kt b/feature/app-settings/src/main/java/org/signal/appsettings/account/AccountSettingsAction.kt index 8195654e74..7a0f419aca 100644 --- a/feature/app-settings/src/main/java/org/signal/appsettings/account/AccountSettingsAction.kt +++ b/feature/app-settings/src/main/java/org/signal/appsettings/account/AccountSettingsAction.kt @@ -72,6 +72,9 @@ sealed interface AccountSettingsAction { /** Open registration so the user can re-register. */ data object LaunchReRegistration : AccountSettingsAction + /** Ask the user to get past their screen lock before we send them into the delete account flow. */ + data object AuthenticateToDeleteAccount : AccountSettingsAction + /** Open the delete account flow. */ data object NavigateToDeleteAccount : AccountSettingsAction diff --git a/feature/app-settings/src/main/java/org/signal/appsettings/account/AccountSettingsEvent.kt b/feature/app-settings/src/main/java/org/signal/appsettings/account/AccountSettingsEvent.kt index 8b8d96d8a6..c903344010 100644 --- a/feature/app-settings/src/main/java/org/signal/appsettings/account/AccountSettingsEvent.kt +++ b/feature/app-settings/src/main/java/org/signal/appsettings/account/AccountSettingsEvent.kt @@ -96,9 +96,12 @@ sealed interface AccountSettingsEvent { /** The fragment reported that clearing application data failed. */ data object DataWipeFailed : AccountSettingsEvent - /** The user tapped the delete account row. */ + /** The user tapped the delete account row, which asks for the screen lock first. */ data object DeleteAccountClicked : AccountSettingsEvent + /** The user got past their screen lock, so we can send them into the delete account flow. */ + data object DeleteAccountAuthenticated : AccountSettingsEvent + /** Dismisses whatever is in [AccountSettingsState.dialog]. */ data object DialogDismissed : AccountSettingsEvent } diff --git a/feature/app-settings/src/main/res/values/strings.xml b/feature/app-settings/src/main/res/values/strings.xml index d4cdce166e..931625014d 100644 --- a/feature/app-settings/src/main/res/values/strings.xml +++ b/feature/app-settings/src/main/res/values/strings.xml @@ -80,6 +80,10 @@ Unlock to view Signal Login To view your Signal Login, confirm it\'s you + + Unlock to confirm it\'s you + + To delete your account, confirm it\'s you Authentication required