diff --git a/mobile/app/_layout.tsx b/mobile/app/_layout.tsx index a28d392..5c74ce4 100644 --- a/mobile/app/_layout.tsx +++ b/mobile/app/_layout.tsx @@ -27,9 +27,11 @@ function AuthGate() { return ( <> + + - {/* Toute route est protégée tant qu'aucun compte n'est connecté. */} + {/* Rediriger vers la connexion uniquement si l'utilisateur n'a pas de session ET n'est pas en mode local. */} {status === 'signedOut' ? : null} ); diff --git a/mobile/app/login.tsx b/mobile/app/login.tsx index 679e99f..d3e358a 100644 --- a/mobile/app/login.tsx +++ b/mobile/app/login.tsx @@ -7,7 +7,7 @@ import i18n from '../i18n'; export default function Login() { const router = useRouter(); - const { signIn, user } = useAuth(); + const { signIn, user, continueWithoutAccount } = useAuth(); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [submitting, setSubmitting] = useState(false); @@ -73,6 +73,15 @@ export default function Login() { {submitting ? i18n.t('login_submitting') : i18n.t('login_submit')} + { + continueWithoutAccount(); + router.replace('/'); + }} + > + {i18n.t('login_skip')} + ); } @@ -118,4 +127,14 @@ const styles = StyleSheet.create({ fontSize: 16, fontWeight: '600', }, + skipButton: { + alignItems: 'center', + paddingVertical: 10, + marginTop: 4, + }, + skipButtonText: { + color: '#1a73e8', + fontSize: 15, + fontWeight: '500', + }, }); \ No newline at end of file diff --git a/mobile/context/AuthContext.tsx b/mobile/context/AuthContext.tsx index ea209d7..b9544dd 100644 --- a/mobile/context/AuthContext.tsx +++ b/mobile/context/AuthContext.tsx @@ -87,9 +87,13 @@ export function AuthProvider({ children }: { children: ReactNode }) { setStatus('signedIn'); }; + const continueWithoutAccount = () => { + setStatus('local'); + }; + const value = useMemo( - () => ({ user, deviceUserId, status, signIn, signOut }), - [user, deviceUserId, status, signIn, signOut], + () => ({ user, deviceUserId, status, signIn, signOut, continueWithoutAccount }), + [user, deviceUserId, status, signIn, signOut, continueWithoutAccount], ); return {children}; diff --git a/mobile/context/AuthContext.types.ts b/mobile/context/AuthContext.types.ts index cf2b2f1..e9fb868 100644 --- a/mobile/context/AuthContext.types.ts +++ b/mobile/context/AuthContext.types.ts @@ -2,7 +2,7 @@ import type { User } from '../api/types'; export type { User }; -export type AuthStatus = 'loading' | 'signedOut' | 'signedIn'; +export type AuthStatus = 'loading' | 'signedOut' | 'local' | 'signedIn'; export type AuthContextValue = { user: User | null; @@ -10,4 +10,5 @@ export type AuthContextValue = { status: AuthStatus; signIn: (username: string, password: string) => Promise; signOut: () => Promise; + continueWithoutAccount: () => void; }; \ No newline at end of file diff --git a/mobile/i18n/en.json b/mobile/i18n/en.json index 9daca6e..b55db50 100644 --- a/mobile/i18n/en.json +++ b/mobile/i18n/en.json @@ -20,5 +20,7 @@ "login_switch_title": "Account already signed in", "login_switch_message": "This sign-in will replace the active account on this device. Continue?", "login_switch_confirm": "Replace", - "login_switch_cancel": "Cancel" + "login_switch_cancel": "Cancel", + "login_skip": "Continue without account", + "skip_message": "Local mode — your folders stay on this device and are not synced." } diff --git a/mobile/i18n/fr.json b/mobile/i18n/fr.json index 0b25472..6185e8b 100644 --- a/mobile/i18n/fr.json +++ b/mobile/i18n/fr.json @@ -20,5 +20,7 @@ "login_switch_title": "Compte déjà connecté", "login_switch_message": "Cette connexion remplacera le compte actif sur cet appareil. Continuer ?", "login_switch_confirm": "Remplacer", - "login_switch_cancel": "Annuler" + "login_switch_cancel": "Annuler", + "login_skip": "Continuer sans compte", + "skip_message": "Mode local — tes dossiers restent sur cet appareil et ne sont pas synchronisés." }