From 4a8d30f754a5e7d5d411fdfb5b638dc8de435ad9 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Wed, 9 Oct 2024 15:28:35 +1100 Subject: [PATCH] Making the change to "hidden recovery" reactive so it can be dynamically updated in the settings page. This can be simplified once we make SharedPreferences widely accessible as Flows --- .../securesms/preferences/SettingsActivity.kt | 24 +++++++++++++++---- .../preferences/SettingsViewModel.kt | 11 +++++++++ .../RecoveryPasswordActivity.kt | 11 +++++++-- .../RecoveryPasswordViewModel.kt | 4 ---- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt index bbf075ca7c..eaebcb57f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt @@ -134,6 +134,16 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { cropImage(inputFile, outputFile) } + private val hideRecoveryLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult + + if(result.data?.getBooleanExtra(RecoveryPasswordActivity.RESULT_RECOVERY_HIDDEN, false) == true){ + viewModel.permanentlyHidePassword() + } + } + private val avatarSelection = AvatarSelection(this, onAvatarCropped, onPickImage) private var showAvatarDialog: Boolean by mutableStateOf(false) @@ -183,7 +193,8 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { } binding.composeView.setThemedContent { - Buttons() + val recoveryHidden by viewModel.recoveryHidden.collectAsState() + Buttons(recoveryHidden = recoveryHidden) } lifecycleScope.launch { @@ -390,7 +401,9 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { } @Composable - fun Buttons() { + fun Buttons( + recoveryHidden: Boolean + ) { Column( modifier = Modifier .padding(horizontal = LocalDimensions.current.spacing) @@ -452,12 +465,15 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { Divider() // Only show the recovery password option if the user has not chosen to permanently hide it - if (!prefs.getHidePassword()) { + if (!recoveryHidden) { LargeItemButton( R.string.sessionRecoveryPassword, R.drawable.ic_shield_outline, Modifier.contentDescription(R.string.AccessibilityId_sessionRecoveryPasswordMenuItem) - ) { push() } + ) { + hideRecoveryLauncher.launch(Intent(baseContext, RecoveryPasswordActivity::class.java)) + overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left) + } Divider() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsViewModel.kt index bedc913109..5b6fa78d44 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsViewModel.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import network.loki.messenger.R @@ -65,6 +66,10 @@ class SettingsViewModel @Inject constructor( val showLoader: StateFlow get() = _showLoader + private val _recoveryHidden: MutableStateFlow = MutableStateFlow(prefs.getHidePassword()) + val recoveryHidden: StateFlow + get() = _recoveryHidden + /** * Refreshes the avatar on the main settings page */ @@ -230,6 +235,12 @@ class SettingsViewModel @Inject constructor( } } + fun permanentlyHidePassword() { + //todo we can simplify this once we expose all our sharedPrefs as flows + prefs.setHidePassword(true) + _recoveryHidden.update { true } + } + sealed class AvatarDialogState() { object NoAvatar : AvatarDialogState() data class UserAvatar(val address: Address) : AvatarDialogState() diff --git a/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt index a6d38c13a0..cc9630ef57 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt @@ -1,16 +1,21 @@ package org.thoughtcrime.securesms.recoverypassword +import android.content.Intent import android.os.Bundle import androidx.activity.viewModels import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import network.loki.messenger.R import org.thoughtcrime.securesms.BaseActionBarActivity -import org.thoughtcrime.securesms.showSessionDialog import org.thoughtcrime.securesms.ui.setComposeContent + class RecoveryPasswordActivity : BaseActionBarActivity() { + companion object { + const val RESULT_RECOVERY_HIDDEN = "recovery_hidden" + } + private val viewModel: RecoveryPasswordViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { @@ -25,7 +30,9 @@ class RecoveryPasswordActivity : BaseActionBarActivity() { mnemonic = mnemonic, seed = seed, confirmHideRecovery = { - viewModel.permanentlyHidePassword() + val returnIntent = Intent() + returnIntent.putExtra(RESULT_RECOVERY_HIDDEN, true) + setResult(RESULT_OK, returnIntent) finish() }, copyMnemonic = viewModel::copyMnemonic diff --git a/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordViewModel.kt index 0ad207cd23..b159accf23 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordViewModel.kt @@ -34,10 +34,6 @@ class RecoveryPasswordViewModel @Inject constructor( .map { MnemonicCodec { MnemonicUtilities.loadFileContents(application, it) }.encode(it, MnemonicCodec.Language.Configuration.english) } .stateIn(viewModelScope, SharingStarted.Eagerly, "") - fun permanentlyHidePassword() { - prefs.setHidePassword(true) - } - fun copyMnemonic() { prefs.setHasViewedSeed(true) ClipData.newPlainText("Seed", mnemonic.value)