diff --git a/app/src/main/java/com/rosetta/messenger/ui/auth/UnlockScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/auth/UnlockScreen.kt index 697635b..f6ed0dc 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/auth/UnlockScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/auth/UnlockScreen.kt @@ -189,6 +189,8 @@ fun UnlockScreen( // Биометрия var biometricAvailable by remember { mutableStateOf(BiometricAvailability.NotAvailable("Проверка...")) } var isBiometricEnabled by remember { mutableStateOf(false) } + var savedPasswordsMap by remember { mutableStateOf>(emptyMap()) } + var dataLoaded by remember { mutableStateOf(false) } // Account selection state var accounts by remember { mutableStateOf>(emptyList()) } @@ -228,17 +230,46 @@ fun UnlockScreen( biometricAvailable = biometricManager.isBiometricAvailable() isBiometricEnabled = biometricPrefs.isBiometricEnabled.first() + // Загружаем сохранённые пароли для всех аккаунтов + val passwords = mutableMapOf() + accounts.forEach { account -> + val encryptedPwd = biometricPrefs.getEncryptedPassword(account.publicKey) + if (encryptedPwd != null) { + passwords[account.publicKey] = encryptedPwd + } + } + savedPasswordsMap = passwords + android.util.Log.d("UnlockScreen", "🔐 Biometric available: $biometricAvailable") android.util.Log.d("UnlockScreen", "🔐 Biometric enabled: $isBiometricEnabled") android.util.Log.d("UnlockScreen", "🔐 Activity: $activity") + android.util.Log.d("UnlockScreen", "🔐 Selected account: ${selectedAccount?.publicKey}") + android.util.Log.d("UnlockScreen", "🔐 Saved passwords count: ${passwords.size}") + android.util.Log.d("UnlockScreen", "🔐 Has password for selected: ${selectedAccount?.let { passwords.containsKey(it.publicKey) }}") + + dataLoaded = true } // Автоматически пытаемся разблокировать через биометрию при выборе аккаунта - LaunchedEffect(selectedAccount, isBiometricEnabled) { + LaunchedEffect(selectedAccount, isBiometricEnabled, savedPasswordsMap, dataLoaded) { + android.util.Log.d("UnlockScreen", "🚀 LaunchedEffect triggered") + android.util.Log.d("UnlockScreen", "🚀 dataLoaded: $dataLoaded") + android.util.Log.d("UnlockScreen", "🚀 selectedAccount: ${selectedAccount?.publicKey}") + android.util.Log.d("UnlockScreen", "🚀 isBiometricEnabled: $isBiometricEnabled") + android.util.Log.d("UnlockScreen", "🚀 biometricAvailable: $biometricAvailable") + android.util.Log.d("UnlockScreen", "🚀 activity: $activity") + + if (!dataLoaded) { + android.util.Log.d("UnlockScreen", "⏸️ Data not loaded yet, waiting...") + return@LaunchedEffect + } + if (selectedAccount != null && isBiometricEnabled && activity != null && biometricAvailable is BiometricAvailability.Available) { - val encryptedPassword = biometricPrefs.getEncryptedPassword(selectedAccount!!.publicKey) + val encryptedPassword = savedPasswordsMap[selectedAccount!!.publicKey] + android.util.Log.d("UnlockScreen", "🔑 Encrypted password found: ${encryptedPassword != null}") + if (encryptedPassword != null) { // Небольшая задержка для анимации UI delay(500) @@ -705,79 +736,133 @@ fun UnlockScreen( enter = fadeIn(tween(400, delayMillis = 500)) ) { Column { - Button( - onClick = { - if (selectedAccount == null) { - error = "Please select an account" - return@Button - } - if (password.isEmpty()) { - error = "Please enter your password" - return@Button - } + // Check if biometric unlock is available for selected account + val canUseBiometric = remember(selectedAccount, isBiometricEnabled, biometricAvailable) { + selectedAccount != null && + isBiometricEnabled && + biometricAvailable is BiometricAvailability.Available && + activity != null + } + + val hasSavedPassword = remember(selectedAccount, savedPasswordsMap) { + selectedAccount?.let { savedPasswordsMap.containsKey(it.publicKey) } ?: false + } + + val showBiometricButton = canUseBiometric && hasSavedPassword + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + // Password Unlock Button + Button( + onClick = { + if (selectedAccount == null) { + error = "Please select an account" + return@Button + } + if (password.isEmpty()) { + error = "Please enter your password" + return@Button + } - scope.launch { - performUnlock( - selectedAccount = selectedAccount, - password = password, - accountManager = accountManager, - onUnlocking = { isUnlocking = it }, - onError = { error = it }, - onSuccess = { decryptedAccount -> - // If biometric is enabled and password not saved yet, save password - if (biometricAvailable is BiometricAvailability.Available && - isBiometricEnabled && activity != null) { - scope.launch { - // Check if password is already saved - val hasPassword = biometricPrefs.hasEncryptedPassword(decryptedAccount.publicKey) - if (!hasPassword) { - biometricManager.encryptPassword( - activity = activity, - password = password, - onSuccess = { encryptedPassword -> - scope.launch { - biometricPrefs.saveEncryptedPassword( - decryptedAccount.publicKey, - encryptedPassword - ) - } - }, - onError = { /* Ignore save errors */ }, - onCancel = { /* User cancelled */ } + scope.launch { + performUnlock( + selectedAccount = selectedAccount, + password = password, + accountManager = accountManager, + onUnlocking = { isUnlocking = it }, + onError = { error = it }, + onSuccess = { decryptedAccount -> + onUnlocked(decryptedAccount) + } + ) + } + }, + enabled = selectedAccount != null && password.isNotEmpty() && !isUnlocking, + modifier = Modifier + .weight(1f) + .height(56.dp), + colors = + ButtonDefaults.buttonColors( + containerColor = PrimaryBlue, + contentColor = Color.White, + disabledContainerColor = PrimaryBlue.copy(alpha = 0.5f), + disabledContentColor = Color.White.copy(alpha = 0.5f) + ), + shape = RoundedCornerShape(12.dp) + ) { + if (isUnlocking) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + color = Color.White, + strokeWidth = 2.dp + ) + } else { + Icon( + imageVector = TablerIcons.LockOpen, + contentDescription = null, + modifier = Modifier.size(20.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = "Unlock", fontSize = 16.sp, fontWeight = FontWeight.SemiBold) + } + } + + // Biometric Unlock Button + if (showBiometricButton) { + Button( + onClick = { + if (selectedAccount == null || activity == null) return@Button + + val encryptedPassword = savedPasswordsMap[selectedAccount!!.publicKey] + if (encryptedPassword != null) { + biometricManager.decryptPassword( + activity = activity, + encryptedData = encryptedPassword, + onSuccess = { decryptedPassword -> + scope.launch { + performUnlock( + selectedAccount = selectedAccount, + password = decryptedPassword, + accountManager = accountManager, + onUnlocking = { isUnlocking = it }, + onError = { error = it }, + onSuccess = { decryptedAccount -> + onUnlocked(decryptedAccount) + } ) } + }, + onError = { errorMessage -> + error = errorMessage + }, + onCancel = { + // User cancelled } - } - onUnlocked(decryptedAccount) + ) } - ) - } - }, - enabled = selectedAccount != null && password.isNotEmpty() && !isUnlocking, - modifier = Modifier.fillMaxWidth().height(56.dp), - colors = - ButtonDefaults.buttonColors( - containerColor = PrimaryBlue, - contentColor = Color.White, - disabledContainerColor = PrimaryBlue.copy(alpha = 0.5f), - disabledContentColor = Color.White.copy(alpha = 0.5f) - ), - shape = RoundedCornerShape(12.dp) - ) { - if (isUnlocking) { - CircularProgressIndicator( - modifier = Modifier.size(24.dp), - color = Color.White, - strokeWidth = 2.dp - ) - } else { - Icon( - imageVector = TablerIcons.LockOpen, - contentDescription = null, - modifier = Modifier.size(20.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - Text(text = "Unlock", fontSize = 16.sp, fontWeight = FontWeight.SemiBold) + }, + enabled = !isUnlocking, + modifier = Modifier + .width(56.dp) + .height(56.dp), + colors = + ButtonDefaults.buttonColors( + containerColor = PrimaryBlue, + contentColor = Color.White, + disabledContainerColor = PrimaryBlue.copy(alpha = 0.5f), + disabledContentColor = Color.White.copy(alpha = 0.5f) + ), + shape = RoundedCornerShape(12.dp), + contentPadding = PaddingValues(0.dp) + ) { + Icon( + imageVector = TablerIcons.Fingerprint, + contentDescription = "Unlock with biometric", + modifier = Modifier.size(28.dp) + ) + } } } }