diff --git a/apps/mobile/app/(app)/_layout.tsx b/apps/mobile/app/(app)/_layout.tsx
index 6c6aa74..b76be80 100755
--- a/apps/mobile/app/(app)/_layout.tsx
+++ b/apps/mobile/app/(app)/_layout.tsx
@@ -17,17 +17,14 @@ type Message = Database["public"]["Tables"]["messages"]["Row"];
function TabBarBackground() {
if (Platform.OS === 'ios') {
return (
-
-
-
-
+
);
}
- return ;
+ return ;
}
interface PlayTabButtonProps {
@@ -78,11 +75,14 @@ export default function AppLayout() {
const messageToastAnim = useRef(new Animated.Value(-100)).current;
const messageTimeoutRef = useRef(null);
const [isLocked, setIsLocked] = useState(false);
- const appStateRef = useRef(AppState.currentState);
const hasCheckedInitialBiometric = useRef(false);
+ const wentToBackgroundAt = useRef(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 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
useEffect(() => {
@@ -136,18 +136,25 @@ export default function AppLayout() {
}
const subscription = AppState.addEventListener('change', async (nextAppState) => {
- const previousState = appStateRef.current;
- appStateRef.current = nextAppState;
+ // Track when app goes to background (not just inactive)
+ if (nextAppState === 'background') {
+ wentToBackgroundAt.current = Date.now();
+ }
- // When app comes to foreground from background
- if (
- previousState.match(/inactive|background/) &&
- nextAppState === 'active' &&
- isAuthenticated
- ) {
- const enabled = await isBiometricEnabled();
- if (enabled) {
- setIsLocked(true);
+ // When app becomes active, check if we should lock
+ if (nextAppState === 'active' && isAuthenticated && !isLocked) {
+ // Only lock if we actually went to background (not just inactive from modal/control center)
+ // and we were in background for at least 1 second
+ if (wentToBackgroundAt.current) {
+ const timeInBackground = Date.now() - wentToBackgroundAt.current;
+ wentToBackgroundAt.current = null;
+
+ if (timeInBackground > 1000) {
+ const enabled = await isBiometricEnabled();
+ if (enabled) {
+ setIsLocked(true);
+ }
+ }
}
}
});
@@ -155,7 +162,7 @@ export default function AppLayout() {
return () => {
subscription.remove();
};
- }, [isAuthenticated, isLoading]);
+ }, [isAuthenticated, isLoading, isLocked]);
const handleBiometricUnlock = useCallback(() => {
setIsLocked(false);
@@ -355,7 +362,7 @@ export default function AppLayout() {
screenOptions={{
headerShown: false,
tabBarBackground: () => ,
- tabBarStyle: {
+ tabBarStyle: shouldHideTabBar ? { display: 'none' } : {
position: 'absolute',
backgroundColor: 'transparent',
borderTopColor: colors.glass.border,
@@ -366,7 +373,7 @@ export default function AppLayout() {
elevation: 0,
},
tabBarActiveTintColor: colors.primary,
- tabBarInactiveTintColor: colors.textTertiary,
+ tabBarInactiveTintColor: '#fff',
tabBarLabelStyle: {
fontSize: 11,
fontWeight: "600",
@@ -426,21 +433,18 @@ export default function AppLayout() {
name="pairing"
options={{
href: null, // Hide from tab bar
- tabBarStyle: { display: 'none' }, // Hide tab bar on pairing screen
}}
/>
diff --git a/apps/mobile/src/components/BiometricLockScreen.tsx b/apps/mobile/src/components/BiometricLockScreen.tsx
index 4aa5943..4c4d2b1 100644
--- a/apps/mobile/src/components/BiometricLockScreen.tsx
+++ b/apps/mobile/src/components/BiometricLockScreen.tsx
@@ -30,13 +30,6 @@ export function BiometricLockScreen({ visible, onUnlock }: BiometricLockScreenPr
loadBiometricType();
}, []);
- useEffect(() => {
- if (visible) {
- // Auto-trigger authentication when the lock screen appears
- handleAuthenticate();
- }
- }, [visible]);
-
const handleAuthenticate = async () => {
if (isAuthenticating) return;