diff --git a/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt b/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt index 44c30741e..a99b40f36 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt @@ -105,7 +105,7 @@ class SessionDialogBuilder(val context: Context) { fun destructiveButton( @StringRes text: Int, - @StringRes contentDescription: Int, + @StringRes contentDescription: Int = text, listener: () -> Unit = {} ) = button( text, diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/recoverypassword/RecoveryPasswordActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/recoverypassword/RecoveryPasswordActivity.kt index 1ad5a274f..d35e9722b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/recoverypassword/RecoveryPasswordActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/recoverypassword/RecoveryPasswordActivity.kt @@ -46,6 +46,7 @@ import androidx.compose.ui.unit.dp import network.loki.messenger.R import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.BaseActionBarActivity +import org.thoughtcrime.securesms.showSessionDialog import org.thoughtcrime.securesms.ui.AppTheme import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin import org.thoughtcrime.securesms.ui.LocalExtraColors @@ -68,7 +69,7 @@ class RecoveryPasswordActivity : BaseActionBarActivity() { ComposeView(this).apply { setContent { - RecoveryPassword(viewModel.seed, viewModel.qrBitmap) { copySeed() } + RecoveryPassword(viewModel.seed, viewModel.qrBitmap, { copySeed() }) { onHide() } } }.let(::setContentView) } @@ -84,6 +85,29 @@ class RecoveryPasswordActivity : BaseActionBarActivity() { clipboard.setPrimaryClip(clip) Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show() } + + private fun onHide() { + showSessionDialog { + title("Hide Recovery Password Permanently") + text("Without your recovery password, you cannot load your account on new devices.\n" + + "\n" + + "We strongly recommend you save your recovery password in a safe and secure place before continuing.") + destructiveButton(R.string.continue_2) { onHideConfirm() } + button(R.string.cancel) {} + } + } + + private fun onHideConfirm() { + showSessionDialog { + title("Hide Recovery Password Permanently") + text("Are you sure you want to permanently hide your recovery password on this device? This cannot be undone.") + button(R.string.cancel) {} + destructiveButton(R.string.yes) { + viewModel.permanentlyHidePassword() + finish() + } + } + } } @Preview @@ -97,7 +121,12 @@ fun PreviewMessageDetails( } @Composable -fun RecoveryPassword(seed: String = "", qrBitmap: Bitmap? = null, copySeed:() -> Unit = {}) { +fun RecoveryPassword( + seed: String = "", + qrBitmap: Bitmap? = null, + copySeed:() -> Unit = {}, + onHide:() -> Unit = {} +) { AppTheme { Column( verticalArrangement = Arrangement.spacedBy(16.dp), @@ -105,7 +134,7 @@ fun RecoveryPassword(seed: String = "", qrBitmap: Bitmap? = null, copySeed:() -> .padding(bottom = 16.dp) ) { RecoveryPasswordCell(seed, qrBitmap, copySeed) - HideRecoveryPasswordCell() + HideRecoveryPasswordCell(onHide) } } } @@ -194,7 +223,7 @@ fun RecoveryPasswordCell(seed: String = "", qrBitmap: Bitmap? = null, copySeed:( private fun MutableState.toggle() { value = !value } @Composable -fun HideRecoveryPasswordCell() { +fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) { CellWithPaddingAndMargin { Row { Column(Modifier.weight(1f)) { @@ -205,7 +234,7 @@ fun HideRecoveryPasswordCell() { "Hide", modifier = Modifier.align(Alignment.CenterVertically), color = colorDestructive - ) {} + ) { onHide() } } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/recoverypassword/RecoveryPasswordViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/recoverypassword/RecoveryPasswordViewModel.kt index 1898912b1..9b7ff3227 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/recoverypassword/RecoveryPasswordViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/recoverypassword/RecoveryPasswordViewModel.kt @@ -3,7 +3,9 @@ package org.thoughtcrime.securesms.onboarding.recoverypassword import android.app.Application import android.graphics.Bitmap import androidx.lifecycle.AndroidViewModel +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback import dagger.hilt.android.lifecycle.HiltViewModel +import org.session.libsession.utilities.AppTextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.crypto.MnemonicCodec import org.session.libsignal.utilities.hexEncodedPrivateKey @@ -18,6 +20,12 @@ class RecoveryPasswordViewModel @Inject constructor( private val application: Application ): AndroidViewModel(application) { + val prefs = AppTextSecurePreferences(application) + + fun permanentlyHidePassword() { + prefs.setHidePassword(true) + } + val seed by lazy { val hexEncodedSeed = IdentityKeyUtil.retrieve(application, IdentityKeyUtil.LOKI_SEED) ?: IdentityKeyUtil.getIdentityKeyPair(application).hexEncodedPrivateKey // Legacy account 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 f650502cd..eddf0ef53 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt @@ -19,6 +19,7 @@ import android.view.MenuItem import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.Toast +import androidx.core.view.isGone import androidx.core.view.isVisible import dagger.hilt.android.AndroidEntryPoint import network.loki.messenger.BuildConfig @@ -64,6 +65,10 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { @Inject lateinit var configFactory: ConfigFactory + @Inject + lateinit var prefs: TextSecurePreferences + + private lateinit var binding: ActivitySettingsBinding private var displayNameEditActionMode: ActionMode? = null @@ -86,13 +91,17 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { super.onCreate(savedInstanceState, isReady) binding = ActivitySettingsBinding.inflate(layoutInflater) setContentView(binding.root) - val displayName = getDisplayName() glide = GlideApp.with(this) - with(binding) { + } + + override fun onStart() { + super.onStart() + + binding.run { setupProfilePictureView(profilePictureView) profilePictureView.setOnClickListener { showEditProfilePictureUI() } ctnGroupNameSection.setOnClickListener { startActionMode(DisplayNameEditActionModeCallback()) } - btnGroupNameDisplay.text = displayName + btnGroupNameDisplay.text = getDisplayName() publicKeyTextView.text = hexEncodedPublicKey copyButton.setOnClickListener { copyPublicKey() } shareButton.setOnClickListener { sharePublicKey() } @@ -105,7 +114,8 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { appearanceButton.setOnClickListener { showAppearanceSettings() } inviteFriendButton.setOnClickListener { sendInvitation() } helpButton.setOnClickListener { showHelp() } - seedButton.setOnClickListener { showSeed() } + passwordButton.isGone = prefs.getHidePassword() + passwordButton.setOnClickListener { showPassword() } clearAllDataButton.setOnClickListener { clearAllData() } versionTextView.text = String.format(getString(R.string.version_s), "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})") } @@ -384,7 +394,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { show(intent) } - private fun showSeed() { + private fun showPassword() { startRecoveryPasswordActivity() } diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 42548235a..cba479b13 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -369,14 +369,14 @@ android:background="?colorDividerBackground" /> diff --git a/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt b/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt index 1b431d62b..ce5564fb0 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt @@ -18,6 +18,7 @@ import org.session.libsession.utilities.TextSecurePreferences.Companion.CALL_NOT import org.session.libsession.utilities.TextSecurePreferences.Companion.CLASSIC_DARK import org.session.libsession.utilities.TextSecurePreferences.Companion.CLASSIC_LIGHT import org.session.libsession.utilities.TextSecurePreferences.Companion.FOLLOW_SYSTEM_SETTINGS +import org.session.libsession.utilities.TextSecurePreferences.Companion.HIDE_PASSWORD import org.session.libsession.utilities.TextSecurePreferences.Companion.LAST_VACUUM_TIME import org.session.libsession.utilities.TextSecurePreferences.Companion.LEGACY_PREF_KEY_SELECTED_UI_MODE import org.session.libsession.utilities.TextSecurePreferences.Companion.OCEAN_DARK @@ -30,6 +31,7 @@ import java.io.IOException import java.util.Arrays import java.util.Date import javax.inject.Inject +import javax.inject.Singleton interface TextSecurePreferences { @@ -182,6 +184,8 @@ interface TextSecurePreferences { fun hasForcedNewConfig(): Boolean fun hasPreference(key: String): Boolean fun clearAll() + fun getHidePassword(): Boolean + fun setHidePassword(value: Boolean) companion object { val TAG = TextSecurePreferences::class.simpleName @@ -283,6 +287,7 @@ interface TextSecurePreferences { const val SELECTED_STYLE = "pref_selected_style" // classic_dark/light, ocean_dark/light const val FOLLOW_SYSTEM_SETTINGS = "pref_follow_system" // follow system day/night + const val HIDE_PASSWORD = "pref_hide_password" const val LEGACY_PREF_KEY_SELECTED_UI_MODE = "SELECTED_UI_MODE" // this will be cleared upon launching app, for users migrating to theming build const val CLASSIC_DARK = "classic.dark" @@ -1016,6 +1021,7 @@ interface TextSecurePreferences { } } +@Singleton class AppTextSecurePreferences @Inject constructor( @ApplicationContext private val context: Context ): TextSecurePreferences { @@ -1711,4 +1717,9 @@ class AppTextSecurePreferences @Inject constructor( getDefaultSharedPreferences(context).edit().clear().commit() } -} \ No newline at end of file + override fun getHidePassword() = getBooleanPreference(HIDE_PASSWORD, false) + + override fun setHidePassword(value: Boolean) { + setBooleanPreference(HIDE_PASSWORD, value) + } +}