feat(settings): add Change password row to SecurityScreen (email/password accounts only)

This commit is contained in:
null 2026-07-01 02:19:18 -05:00
parent 30000e7150
commit a096ca15d1
1 changed files with 30 additions and 0 deletions

View File

@ -66,6 +66,8 @@ import app.closer.ui.components.CloserGlyphs
data class SecurityUiState(
val biometricLoginEnabled: Boolean = false,
// Only email/password accounts have a password to change (hidden for Google sign-in / not signed in).
val canChangePassword: Boolean = false,
val hasRecoveryPhrase: Boolean = false,
val recoveryPhrase: String? = null,
// The couple key IS on this device (encrypt/decrypt works) even when no phrase is stored — this is the
@ -92,6 +94,11 @@ class SecurityViewModel @Inject constructor(
// Whether the couple key itself is present on this device (set up), independent of the phrase.
private val _coupleKeyPresent = MutableStateFlow(false)
// Account type is fixed for the life of this screen: only an email/password account (signed in, not
// Google, not anonymous) has a password to change.
private val canChangePassword =
authRepository.isSignedIn && !authRepository.isGoogleAccount && !authRepository.isAnonymous
init {
viewModelScope.launch {
val uid = authRepository.currentUserId ?: return@launch
@ -109,6 +116,7 @@ class SecurityViewModel @Inject constructor(
) { settings, phrase, stored, keyPresent ->
SecurityUiState(
biometricLoginEnabled = settings.biometricLoginEnabled,
canChangePassword = canChangePassword,
hasRecoveryPhrase = stored != null,
recoveryPhrase = phrase,
coupleKeyPresent = keyPresent
@ -269,6 +277,28 @@ fun SecurityScreen(
Divider(modifier = Modifier.padding(horizontal = 16.dp), thickness = 0.5.dp)
// Change password — only for email/password accounts (Google users have no password).
if (state.canChangePassword) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onNavigate(AppRoute.CHANGE_PASSWORD) }
.padding(horizontal = 16.dp, vertical = 14.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
Icon(CloserGlyphs.Key, contentDescription = null, tint = SettingsMuted)
Text(
text = "Change password",
style = MaterialTheme.typography.bodyLarge,
color = SettingsInk,
modifier = Modifier.weight(1f)
)
Icon(CloserGlyphs.Forward, contentDescription = null, tint = SettingsMuted)
}
Divider(modifier = Modifier.padding(horizontal = 16.dp), thickness = 0.5.dp)
}
// Recovery phrase row — greyed out until a phrase is stored on-device
Row(
modifier = Modifier