fix: Resolve biometric prompt issues and screen rotation behavior

- Fixed an issue where the biometric prompt appeared twice when attempting to change the encryption password. The redundant prompt has been removed.
- Addressed an issue where the biometric prompt would reappear on screen rotation for locked notes, lists, and recipes. The unlock state now persists across configuration changes.
This commit is contained in:
2025-11-02 08:34:28 +01:00
parent 31d75abf48
commit f41dbbe4ae
4 changed files with 33 additions and 27 deletions

View File

@@ -476,22 +476,11 @@ fun AppShell(
}
}
val onSetEncryptionPassword: () -> Unit = {
if (hasEncryptionPassword) {
val activity = context.findActivity() as FragmentActivity
biometricAuthenticator.promptBiometricAuth(
title = context.getString(R.string.change_encryption_password),
subtitle = context.getString(R.string.confirm_to_change_password),
negativeButtonText = context.getString(R.string.cancel),
fragmentActivity = activity,
onSuccess = { _ -> showPasswordDialog = true },
onFailed = { },
onError = { _, _ -> }
)
} else {
val onSetEncryptionPassword: () -> Unit = {
showPasswordDialog = true
}
}
val onRemoveEncryption: () -> Unit = {
val activity = context.findActivity() as FragmentActivity
@@ -724,7 +713,7 @@ fun AppShell(
val lifecycleOwner = LocalLifecycleOwner.current
var secretKey by remember { mutableStateOf<SecretKey?>(null) }
var isDecryptionAttempted by remember { mutableStateOf(false) }
var isDecryptionAttempted by rememberSaveable { mutableStateOf(false) }
DisposableEffect(lifecycleOwner, context, scope) {
val observer = LifecycleEventObserver { _, event ->

View File

@@ -35,6 +35,8 @@ import de.lxtools.noteshop.security.FileEncryptor
import javax.crypto.SecretKey
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import de.lxtools.noteshop.findActivity
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -50,7 +52,7 @@ fun NoteDetailScreen(
val noteDetails by viewModel.noteDetails.collectAsState()
val scope = rememberCoroutineScope()
var wasLockedInitially by remember { mutableStateOf<Boolean?>(null) }
var wasLockedInitially by rememberSaveable { mutableStateOf<Boolean?>(null) }
LaunchedEffect(noteDetails) {
if (wasLockedInitially == null) { // This ensures we only set it once
@@ -58,10 +60,14 @@ fun NoteDetailScreen(
}
}
val context = LocalContext.current
DisposableEffect(noteId) {
onDispose {
if (wasLockedInitially == true) {
viewModel.toggleNoteLock(noteId ?: 0, secretKey, fileEncryptor)
val activity = context.findActivity()
if (!activity.isChangingConfigurations) {
if (wasLockedInitially == true) {
viewModel.toggleNoteLock(noteId ?: 0, secretKey, fileEncryptor)
}
}
}
}

View File

@@ -43,6 +43,8 @@ import androidx.compose.runtime.setValue
import de.lxtools.noteshop.security.FileEncryptor
import javax.crypto.SecretKey
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.saveable.rememberSaveable
import de.lxtools.noteshop.findActivity
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -59,7 +61,7 @@ fun RecipeDetailScreen(
var isEditMode by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
var wasLockedInitially by remember { mutableStateOf<Boolean?>(null) }
var wasLockedInitially by rememberSaveable { mutableStateOf<Boolean?>(null) }
LaunchedEffect(recipeDetails) {
if (wasLockedInitially == null) { // This ensures we only set it once
@@ -67,10 +69,14 @@ fun RecipeDetailScreen(
}
}
val context = LocalContext.current
DisposableEffect(recipeId) {
onDispose {
if (wasLockedInitially == true) {
viewModel.toggleRecipeLock(recipeId ?: 0, secretKey, fileEncryptor)
val activity = context.findActivity()
if (!activity.isChangingConfigurations) {
if (wasLockedInitially == true) {
viewModel.toggleRecipeLock(recipeId ?: 0, secretKey, fileEncryptor)
}
}
}
}

View File

@@ -56,7 +56,9 @@ import sh.calvin.reorderable.ReorderableItem
import sh.calvin.reorderable.rememberReorderableLazyListState
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.text.withStyle
import de.lxtools.noteshop.findActivity
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -83,7 +85,7 @@ fun ShoppingListDetailScreen(
val isDetailSearchActive by viewModel.isDetailSearchActive.collectAsState()
var wasLockedInitially by remember { mutableStateOf<Boolean?>(null) }
var wasLockedInitially by rememberSaveable { mutableStateOf<Boolean?>(null) }
// This effect runs when the screen is first displayed. It records the initial lock state.
LaunchedEffect(shoppingListWithItems) {
@@ -92,13 +94,16 @@ fun ShoppingListDetailScreen(
}
}
// This effect runs when the user navigates away from the screen.
val context = LocalContext.current
DisposableEffect(listId) {
onDispose {
// We only re-lock if the list was locked when we entered.
if (wasLockedInitially == true) {
// Calling toggleListLock will re-lock the list if it's currently unlocked.
viewModel.toggleListLock(listId ?: 0, secretKey, fileEncryptor)
val activity = context.findActivity()
if (!activity.isChangingConfigurations) {
// We only re-lock if the list was locked when we entered.
if (wasLockedInitially == true) {
// Calling toggleListLock will re-lock the list if it's currently unlocked.
viewModel.toggleListLock(listId ?: 0, secretKey, fileEncryptor)
}
}
}
}