This commit is contained in:
Jamie Brunton committed 2025-12-29 22:27:18 +00:00
1 parent 118dadc69a
commit 358c2be0ee
2 files changed
+32 -35

No files matched your search

+32 -28
View File
@@ -17,17 +17,14 @@ type Message = Database["public"]["Tables"]["messages"]["Row"];
function TabBarBackground() { function TabBarBackground() {
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
return ( return (
<View style={StyleSheet.absoluteFill}> <BlurView
<BlurView intensity={80}
intensity={blur.heavy} tint="systemChromeMaterialDark"
tint="dark" style={StyleSheet.absoluteFill}
style={StyleSheet.absoluteFill} />
/>
<View style={[StyleSheet.absoluteFill, { backgroundColor: 'rgba(22, 33, 62, 0.7)' }]} />
</View>
); );
} }
return <View style={[StyleSheet.absoluteFill, { backgroundColor: 'rgba(22, 33, 62, 0.9)' }]} />; return <View style={[StyleSheet.absoluteFill, { backgroundColor: 'rgba(22, 33, 62, 0.95)' }]} />;
} }
interface PlayTabButtonProps { interface PlayTabButtonProps {
@@ -78,11 +75,14 @@ export default function AppLayout() {
const messageToastAnim = useRef(new Animated.Value(-100)).current; const messageToastAnim = useRef(new Animated.Value(-100)).current;
const messageTimeoutRef = useRef<NodeJS.Timeout | null>(null); const messageTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const [isLocked, setIsLocked] = useState(false); const [isLocked, setIsLocked] = useState(false);
const appStateRef = useRef<AppStateStatus>(AppState.currentState);
const hasCheckedInitialBiometric = useRef(false); const hasCheckedInitialBiometric = useRef(false);
const wentToBackgroundAt = useRef<number | null>(null);
// Check if we're currently on the onboarding screen // Check if we're on screens that should hide the tab bar
const isOnOnboarding = segments.includes("onboarding"); const isOnOnboarding = segments.includes("onboarding");
const isOnPairing = segments.includes("pairing");
const isOnChat = segments.includes("chat");
const shouldHideTabBar = isOnOnboarding || isOnPairing || isOnChat;
// Redirect to login when not authenticated, or to onboarding if not completed // Redirect to login when not authenticated, or to onboarding if not completed
useEffect(() => { useEffect(() => {
@@ -136,18 +136,25 @@ export default function AppLayout() {
} }
const subscription = AppState.addEventListener('change', async (nextAppState) => { const subscription = AppState.addEventListener('change', async (nextAppState) => {
const previousState = appStateRef.current; // Track when app goes to background (not just inactive)
appStateRef.current = nextAppState; if (nextAppState === 'background') {
wentToBackgroundAt.current = Date.now();
}
// When app comes to foreground from background // When app becomes active, check if we should lock
if ( if (nextAppState === 'active' && isAuthenticated && !isLocked) {
previousState.match(/inactive|background/) && // Only lock if we actually went to background (not just inactive from modal/control center)
nextAppState === 'active' && // and we were in background for at least 1 second
isAuthenticated if (wentToBackgroundAt.current) {
) { const timeInBackground = Date.now() - wentToBackgroundAt.current;
const enabled = await isBiometricEnabled(); wentToBackgroundAt.current = null;
if (enabled) {
setIsLocked(true); if (timeInBackground > 1000) {
const enabled = await isBiometricEnabled();
if (enabled) {
setIsLocked(true);
}
}
} }
} }
}); });
@@ -155,7 +162,7 @@ export default function AppLayout() {
return () => { return () => {
subscription.remove(); subscription.remove();
}; };
}, [isAuthenticated, isLoading]); }, [isAuthenticated, isLoading, isLocked]);
const handleBiometricUnlock = useCallback(() => { const handleBiometricUnlock = useCallback(() => {
setIsLocked(false); setIsLocked(false);
@@ -355,7 +362,7 @@ export default function AppLayout() {
screenOptions={{ screenOptions={{
headerShown: false, headerShown: false,
tabBarBackground: () => <TabBarBackground />, tabBarBackground: () => <TabBarBackground />,
tabBarStyle: { tabBarStyle: shouldHideTabBar ? { display: 'none' } : {
position: 'absolute', position: 'absolute',
backgroundColor: 'transparent', backgroundColor: 'transparent',
borderTopColor: colors.glass.border, borderTopColor: colors.glass.border,
@@ -366,7 +373,7 @@ export default function AppLayout() {
elevation: 0, elevation: 0,
}, },
tabBarActiveTintColor: colors.primary, tabBarActiveTintColor: colors.primary,
tabBarInactiveTintColor: colors.textTertiary, tabBarInactiveTintColor: '#fff',
tabBarLabelStyle: { tabBarLabelStyle: {
fontSize: 11, fontSize: 11,
fontWeight: "600", fontWeight: "600",
@@ -426,21 +433,18 @@ export default function AppLayout() {
name="pairing" name="pairing"
options={{ options={{
href: null, // Hide from tab bar href: null, // Hide from tab bar
tabBarStyle: { display: 'none' }, // Hide tab bar on pairing screen
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="chat/[id]" name="chat/[id]"
options={{ options={{
href: null, // Hide from tab bar href: null, // Hide from tab bar
tabBarStyle: { display: 'none' }, // Hide tab bar on chat screen
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="onboarding" name="onboarding"
options={{ options={{
href: null, // Hide from tab bar href: null, // Hide from tab bar
tabBarStyle: { display: 'none' }, // Hide tab bar on onboarding screen
}} }}
/> />
</Tabs> </Tabs>
@@ -30,13 +30,6 @@ export function BiometricLockScreen({ visible, onUnlock }: BiometricLockScreenPr
loadBiometricType(); loadBiometricType();
}, []); }, []);
useEffect(() => {
if (visible) {
// Auto-trigger authentication when the lock screen appears
handleAuthenticate();
}
}, [visible]);
const handleAuthenticate = async () => { const handleAuthenticate = async () => {
if (isAuthenticating) return; if (isAuthenticating) return;