Fix Live Activity lock screen rendering and polish multi-account auth.

Flatten widget layouts and use system colors so banner and expanded regions render on vibrant lock screens; migrate auth sessions per account to prevent double sign-in; scope app lock PIN to accounts; default clock description to "Clock In"; add architecture docs and deferred form validation on auth screens.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-18 01:23:36 -04:00
parent e6ea3d7c5d
commit 32ffe782ea
35 changed files with 1659 additions and 442 deletions
+51 -19
View File
@@ -1,44 +1,76 @@
import * as SecureStore from "expo-secure-store";
const ENABLED_KEY = "beenvoice_app_lock_enabled";
const PIN_KEY = "beenvoice_app_lock_pin";
const BIOMETRIC_KEY = "beenvoice_app_lock_biometric";
import { normalizeSecureStoreKey } from "@/lib/secure-store-keys";
export async function getAppLockEnabled(): Promise<boolean> {
const value = await SecureStore.getItemAsync(ENABLED_KEY);
function lockKey(accountId: string, field: "enabled" | "pin" | "biometric") {
return normalizeSecureStoreKey(`beenvoice.app-lock.${accountId}.${field}`);
}
const LEGACY_ENABLED_KEY = "beenvoice_app_lock_enabled";
const LEGACY_PIN_KEY = "beenvoice_app_lock_pin";
const LEGACY_BIOMETRIC_KEY = "beenvoice_app_lock_biometric";
async function migrateLegacyLockIfNeeded(accountId: string): Promise<void> {
const [legacyEnabled, legacyPin, legacyBiometric, accountEnabled] = await Promise.all([
SecureStore.getItemAsync(LEGACY_ENABLED_KEY),
SecureStore.getItemAsync(LEGACY_PIN_KEY),
SecureStore.getItemAsync(LEGACY_BIOMETRIC_KEY),
SecureStore.getItemAsync(lockKey(accountId, "enabled")),
]);
if (accountEnabled != null || legacyEnabled !== "1") return;
if (legacyPin) {
await setStoredPin(accountId, legacyPin);
}
await setAppLockEnabled(accountId, true);
if (legacyBiometric === "1") {
await setBiometricEnabled(accountId, true);
}
await Promise.all([
SecureStore.deleteItemAsync(LEGACY_ENABLED_KEY),
SecureStore.deleteItemAsync(LEGACY_PIN_KEY),
SecureStore.deleteItemAsync(LEGACY_BIOMETRIC_KEY),
]);
}
export async function getAppLockEnabled(accountId: string): Promise<boolean> {
await migrateLegacyLockIfNeeded(accountId);
const value = await SecureStore.getItemAsync(lockKey(accountId, "enabled"));
return value === "1";
}
export async function setAppLockEnabled(enabled: boolean): Promise<void> {
export async function setAppLockEnabled(accountId: string, enabled: boolean): Promise<void> {
if (enabled) {
await SecureStore.setItemAsync(ENABLED_KEY, "1");
await SecureStore.setItemAsync(lockKey(accountId, "enabled"), "1");
} else {
await SecureStore.deleteItemAsync(ENABLED_KEY);
await SecureStore.deleteItemAsync(lockKey(accountId, "enabled"));
}
}
export async function getStoredPin(): Promise<string | null> {
return SecureStore.getItemAsync(PIN_KEY);
export async function getStoredPin(accountId: string): Promise<string | null> {
return SecureStore.getItemAsync(lockKey(accountId, "pin"));
}
export async function setStoredPin(pin: string): Promise<void> {
await SecureStore.setItemAsync(PIN_KEY, pin);
export async function setStoredPin(accountId: string, pin: string): Promise<void> {
await SecureStore.setItemAsync(lockKey(accountId, "pin"), pin);
}
export async function clearStoredPin(): Promise<void> {
await SecureStore.deleteItemAsync(PIN_KEY);
export async function clearStoredPin(accountId: string): Promise<void> {
await SecureStore.deleteItemAsync(lockKey(accountId, "pin"));
}
export async function getBiometricEnabled(): Promise<boolean> {
const value = await SecureStore.getItemAsync(BIOMETRIC_KEY);
export async function getBiometricEnabled(accountId: string): Promise<boolean> {
const value = await SecureStore.getItemAsync(lockKey(accountId, "biometric"));
return value === "1";
}
export async function setBiometricEnabled(enabled: boolean): Promise<void> {
export async function setBiometricEnabled(accountId: string, enabled: boolean): Promise<void> {
if (enabled) {
await SecureStore.setItemAsync(BIOMETRIC_KEY, "1");
await SecureStore.setItemAsync(lockKey(accountId, "biometric"), "1");
} else {
await SecureStore.deleteItemAsync(BIOMETRIC_KEY);
await SecureStore.deleteItemAsync(lockKey(accountId, "biometric"));
}
}