fix: repair Android startup and improve mobile web layouts
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m17s
ci / ts / ts (packages + web) (push) Successful in 2m22s
release / android (APK в релиз) (push) Successful in 4m15s
release / release (версия и заметки) (push) Successful in 6s

This commit is contained in:
mrleo1nid committed 2026-10-21 17:14:05 +03:00
1 parent 4c2286e70d
commit b0cbd0f149
30 files changed
+609 -140

No files matched your search

+22 -15
View File
@@ -1,6 +1,6 @@
import { createI18n, pickLocale, SUPPORTED_LOCALES, type Locale } from '@pipu/i18n';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Stack, useRouter, useSegments } from 'expo-router';
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import type { i18n as I18n } from 'i18next';
import { useEffect, useState } from 'react';
@@ -54,8 +54,6 @@ const isLocale = (l: string): l is Locale => (SUPPORTED_LOCALES as readonly stri
function Gate() {
const { server, session, ready } = useSessionCtx();
const auth = useAuthState();
const segments = useSegments();
const router = useRouter();
const { i18n } = useTranslation();
const user = auth.status === 'signed_in' ? auth.user : null;
const system = useColorScheme();
@@ -79,17 +77,6 @@ function Gate() {
return () => sub.remove();
}, []);
useEffect(() => {
if (!ready) return;
const first = segments[0] as string | undefined;
let target: string | null = null;
if (!server) target = first === 'connect' ? null : '/connect';
else if (!user) target = first === 'login' || first === 'connect' ? null : '/login';
else if (user.must_change_credentials || user.must_change_password) target = first === 'setup' ? null : '/setup';
else if (first === 'connect' || first === 'login' || first === 'setup') target = '/';
if (target) router.replace(target as never);
}, [ready, server, user?.id, user?.must_change_credentials, user?.must_change_password, segments]);
if (!ready) return <Splash />;
return (
<ThemeContext.Provider value={theme}>
@@ -101,9 +88,29 @@ function Gate() {
function Screens() {
const colors = useColors();
const { server, session } = useSessionCtx();
const auth = useAuthState();
const connected = !!server && !!session;
const user = connected && auth.status === 'signed_in' ? auth.user : null;
const needsSetup = !!user && (user.must_change_credentials || user.must_change_password);
return (
<Stack screenOptions={{ headerShown: false, contentStyle: { backgroundColor: colors.bg } }}>
<Stack.Screen name="player" options={{ presentation: 'modal', animation: 'slide_from_bottom' }} />
{/* Guards exclude screens before render: an effect redirect runs after useSession/useUser throw. */}
<Stack.Protected guard={!connected}>
<Stack.Screen name="connect" />
</Stack.Protected>
<Stack.Protected guard={connected && !user}>
<Stack.Screen name="login" />
</Stack.Protected>
<Stack.Protected guard={needsSetup}>
<Stack.Screen name="setup" />
</Stack.Protected>
<Stack.Protected guard={!!user && !needsSetup}>
<Stack.Screen name="(tabs)" />
<Stack.Screen name="album/[id]" />
<Stack.Screen name="artist/[id]" />
<Stack.Screen name="player" options={{ presentation: 'modal', animation: 'slide_from_bottom' }} />
</Stack.Protected>
</Stack>
);
}