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:
@@ -1,15 +1,13 @@
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Modal,
|
||||
Pressable,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
View,
|
||||
} from "react-native";
|
||||
|
||||
import { LogoMark } from "@/components/Logo";
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { Button } from "@/components/ui/Button";
|
||||
import { fonts, spacing } from "@/constants/theme";
|
||||
import { useAppLock } from "@/contexts/AppLockContext";
|
||||
@@ -28,11 +26,13 @@ export function AppLockOverlay() {
|
||||
} = useAppLock();
|
||||
const [pin, setPin] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const promptedRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLocked) {
|
||||
setPin("");
|
||||
setError("");
|
||||
promptedRef.current = false;
|
||||
}
|
||||
}, [isLocked]);
|
||||
|
||||
@@ -40,12 +40,18 @@ export function AppLockOverlay() {
|
||||
if (!enabled || !isLocked || !biometricEnabled || !biometricAvailable) {
|
||||
return;
|
||||
}
|
||||
if (promptedRef.current) return;
|
||||
|
||||
void unlockWithBiometric().then((success) => {
|
||||
if (!success) return;
|
||||
setPin("");
|
||||
setError("");
|
||||
});
|
||||
const timer = setTimeout(() => {
|
||||
promptedRef.current = true;
|
||||
void unlockWithBiometric().then((success) => {
|
||||
if (!success) return;
|
||||
setPin("");
|
||||
setError("");
|
||||
});
|
||||
}, 400);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [enabled, isLocked, biometricEnabled, biometricAvailable, unlockWithBiometric]);
|
||||
|
||||
if (!enabled || !isLocked) {
|
||||
@@ -64,6 +70,7 @@ export function AppLockOverlay() {
|
||||
}
|
||||
|
||||
async function tryBiometric() {
|
||||
promptedRef.current = true;
|
||||
const success = await unlockWithBiometric();
|
||||
if (!success) {
|
||||
setError(`Could not unlock with ${biometricLabel}`);
|
||||
@@ -74,8 +81,8 @@ export function AppLockOverlay() {
|
||||
<Modal visible animationType="fade" transparent={false}>
|
||||
<View style={[styles.screen, { backgroundColor: colors.background }]}>
|
||||
<View style={styles.content}>
|
||||
<LogoMark size={56} />
|
||||
<Text style={[styles.title, { color: colors.foreground }]}>beenvoice is locked</Text>
|
||||
<Logo size="md" />
|
||||
<Text style={[styles.title, { color: colors.foreground }]}>Locked</Text>
|
||||
<Text style={[styles.subtitle, { color: colors.mutedForeground }]}>
|
||||
Enter your PIN to continue
|
||||
</Text>
|
||||
@@ -104,20 +111,18 @@ export function AppLockOverlay() {
|
||||
|
||||
{error ? <Text style={[styles.error, { color: colors.destructive }]}>{error}</Text> : null}
|
||||
|
||||
<Button title="Unlock" onPress={() => void submitPin()} disabled={pin.length < 4} />
|
||||
<View style={styles.actions}>
|
||||
<Button title="Unlock" onPress={() => void submitPin()} disabled={pin.length < 4} />
|
||||
|
||||
{biometricEnabled && biometricAvailable ? (
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
onPress={() => void tryBiometric()}
|
||||
style={styles.biometricButton}
|
||||
>
|
||||
<Ionicons name="finger-print-outline" size={20} color={colors.primary} />
|
||||
<Text style={[styles.biometricLabel, { color: colors.primary }]}>
|
||||
Unlock with {biometricLabel}
|
||||
</Text>
|
||||
</Pressable>
|
||||
) : null}
|
||||
{biometricAvailable ? (
|
||||
<Button
|
||||
title={`Unlock with ${biometricLabel}`}
|
||||
variant="secondary"
|
||||
onPress={() => void tryBiometric()}
|
||||
style={styles.biometricButton}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
@@ -133,6 +138,9 @@ const styles = StyleSheet.create({
|
||||
content: {
|
||||
alignItems: "center",
|
||||
gap: spacing.md,
|
||||
width: "100%",
|
||||
maxWidth: 320,
|
||||
alignSelf: "center",
|
||||
},
|
||||
title: {
|
||||
fontSize: 22,
|
||||
@@ -147,28 +155,24 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
pinInput: {
|
||||
width: "100%",
|
||||
maxWidth: 280,
|
||||
borderWidth: 1,
|
||||
borderRadius: 12,
|
||||
minHeight: 52,
|
||||
paddingHorizontal: spacing.md,
|
||||
fontSize: 24,
|
||||
fontSize: 20,
|
||||
fontFamily: fonts.bodySemiBold,
|
||||
textAlign: "center",
|
||||
letterSpacing: 8,
|
||||
},
|
||||
error: {
|
||||
fontFamily: fonts.bodyMedium,
|
||||
fontSize: 13,
|
||||
textAlign: "center",
|
||||
},
|
||||
actions: {
|
||||
width: "100%",
|
||||
gap: spacing.sm,
|
||||
},
|
||||
biometricButton: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: spacing.xs,
|
||||
paddingVertical: spacing.sm,
|
||||
},
|
||||
biometricLabel: {
|
||||
fontSize: 14,
|
||||
fontFamily: fonts.bodyMedium,
|
||||
width: "100%",
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user