fix(ui): pasek zakladek naprawde plynie - zakladki jako stan, nie trasy
Zgloszenie: "zamiast slicznych animowanych przesuwajacych sie elementow mam
statyczna kropke". Dwie niezalezne przyczyny, obie konieczne do naprawy:
1. Animacja NIE MIALA FIZYCZNEJ MOZLIWOSCI sie wykonac. Kazda zakladka byla
osobnym ekranem native stacka, a przelaczenie robilo navigation.replace(t),
czyli wymienialo caly ekran razem z naglowkiem. LiquidTabs montowal sie od
nowa z kropla juz na docelowej pozycji (pierwsze ustawienie celowo bez
animacji). Fix: jeden HomeScreen, zakladka to stan lokalny, pasek przezywa
przelaczenie. key={tab} na tresci zachowuje dotychczasowy reset stanu.
2. Pasek byl NIEWIDZIALNY: wypelnienie theme.card na naglowku o tle theme.card.
Z calego "roztapiania" zostawala sama akcentowa kropka. Fix: naglowek na
theme.bg.
Do tego drobne: easing Easing.out(cubic) 260ms (wczesniej bez znaczenia, bo kod
nigdy nie dzialal); BugReportFAB czyta zakladke z params.tab (nazwa trasy to
teraz zawsze 'Scenes'); ikony naglowka ujednolicone na wszystkich zakladkach;
App.tsx: blad ladowania fontow przestaje wieszac boot na wiecznym spinnerze
(fail-open na system font) - obnazone przez rozjazd JS/natywki w dev buildzie.
Trasy Movies/Sites/JAV/Anime wyrejestrowane (nic poza paskiem do nich nie
nawigowalo); typy w RootStackParamList zostaja dla useNavigation.
Zweryfikowane nagraniem ekranu emulatora klatka po klatce: kropla plynie
Scenes->Sites i JAV->Anime z wedrujacym wglebieniem, pasek widoczny, tresc
i przycisk Performers/Tags zgodne z zakladka.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
f48fbbd4ad
commit
0949091f78
6 changed files with 120 additions and 137 deletions
|
|
@ -113,12 +113,16 @@ function applyDefaultFont() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [fontsLoaded] = useFonts({
|
const [fontsLoaded, fontsError] = useFonts({
|
||||||
'GeneralSans-Regular': require('./assets/fonts/GeneralSans-Regular.ttf'),
|
'GeneralSans-Regular': require('./assets/fonts/GeneralSans-Regular.ttf'),
|
||||||
'GeneralSans-Medium': require('./assets/fonts/GeneralSans-Medium.ttf'),
|
'GeneralSans-Medium': require('./assets/fonts/GeneralSans-Medium.ttf'),
|
||||||
'GeneralSans-Semibold': require('./assets/fonts/GeneralSans-Semibold.ttf'),
|
'GeneralSans-Semibold': require('./assets/fonts/GeneralSans-Semibold.ttf'),
|
||||||
'GeistMono-Regular': require('./assets/fonts/GeistMono-Regular.ttf'),
|
'GeistMono-Regular': require('./assets/fonts/GeistMono-Regular.ttf'),
|
||||||
});
|
});
|
||||||
|
// Fail-open: błąd ładowania fontów NIE MOŻE wieszać bootu. `fontsLoaded` zostaje
|
||||||
|
// false na zawsze przy odrzuconym loadAsync (np. rozjazd JS/natywki w dev build,
|
||||||
|
// 2026-08-18: 'AppDirectories not found' → wieczny spinner). System font < brak apki.
|
||||||
|
const fontsSettled = fontsLoaded || fontsError != null;
|
||||||
if (fontsLoaded) applyDefaultFont();
|
if (fontsLoaded) applyDefaultFont();
|
||||||
|
|
||||||
const [hydrated, setHydrated] = useState(false);
|
const [hydrated, setHydrated] = useState(false);
|
||||||
|
|
@ -323,7 +327,7 @@ export default function App() {
|
||||||
return () => sub.remove();
|
return () => sub.remove();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!fontsLoaded || !hydrated || !lockReady) {
|
if (!fontsSettled || !hydrated || !lockReady) {
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1, backgroundColor: theme.bg, justifyContent: 'center' }}>
|
<View style={{ flex: 1, backgroundColor: theme.bg, justifyContent: 'center' }}>
|
||||||
<ActivityIndicator color={theme.fg} />
|
<ActivityIndicator color={theme.fg} />
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,13 @@ export type ChangelogEntry = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CHANGELOG: ChangelogEntry[] = [
|
export const CHANGELOG: ChangelogEntry[] = [
|
||||||
|
{
|
||||||
|
id: '2026-08-18',
|
||||||
|
date: 'August 2026',
|
||||||
|
items: [
|
||||||
|
'The liquid tab bar now actually flows. The melt animation existed but could never run: switching tabs rebuilt the whole header, so the blob just teleported. The bar also drew in the same colour as the header behind it, which reduced the whole effect to a floating dot. Both fixed, the blob now slides and the bar melts around it.',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: '2026-08-14e',
|
id: '2026-08-14e',
|
||||||
date: 'August 2026',
|
date: 'August 2026',
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,10 @@ export function BugReportFAB({ client, appVersion, navRef }: Props) {
|
||||||
const route = navRef.isReady() ? navRef.getCurrentRoute() : null;
|
const route = navRef.isReady() ? navRef.getCurrentRoute() : null;
|
||||||
routeName = route?.name ?? null;
|
routeName = route?.name ?? null;
|
||||||
const params = (route?.params ?? {}) as Record<string, unknown>;
|
const params = (route?.params ?? {}) as Record<string, unknown>;
|
||||||
|
// Zakładki (Scenes/Movies/Sites/JAV/Anime) to JEDNA trasa ze stanem lokalnym
|
||||||
|
// (HomeScreen), więc nazwa trasy nie mówi, na której zakładce user był. HomeScreen
|
||||||
|
// odkłada ją w params.tab — bez tego triage zgłoszeń straciłby rozróżnienie.
|
||||||
|
if (typeof params.tab === 'string' && params.tab) routeName = params.tab;
|
||||||
rawSceneId =
|
rawSceneId =
|
||||||
(params['sceneId'] as string | undefined) ??
|
(params['sceneId'] as string | undefined) ??
|
||||||
(params['id'] as string | undefined);
|
(params['id'] as string | undefined);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* realna szerokość zależy od telefonu. Do pierwszego pomiaru rysujemy sam pasek.
|
* realna szerokość zależy od telefonu. Do pierwszego pomiaru rysujemy sam pasek.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
|
import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-native';
|
||||||
import Svg, { Path } from 'react-native-svg';
|
import Svg, { Path } from 'react-native-svg';
|
||||||
|
|
||||||
import { liquidTabPath, plainBar } from '../lib/liquidTabPath';
|
import { liquidTabPath, plainBar } from '../lib/liquidTabPath';
|
||||||
|
|
@ -65,7 +65,11 @@ export function LiquidTabs<T extends string>({ tabs, current, onSelect }: Props<
|
||||||
}
|
}
|
||||||
const a = Animated.timing(anim, {
|
const a = Animated.timing(anim, {
|
||||||
toValue: targetCx,
|
toValue: targetCx,
|
||||||
duration: 200,
|
// Szybki start i miękkie dojście: kropla „dopływa" zamiast stawać jak wagon.
|
||||||
|
// Do 2026-08-18 ten kod nigdy nie działał (pasek montował się od nowa przy każdym
|
||||||
|
// przełączeniu, patrz HomeScreen w navigation.tsx), więc easing nie miał znaczenia.
|
||||||
|
duration: 260,
|
||||||
|
easing: Easing.out(Easing.cubic),
|
||||||
useNativeDriver: false,
|
useNativeDriver: false,
|
||||||
});
|
});
|
||||||
a.start();
|
a.start();
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { GoonClient } from './api';
|
||||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Pressable, Text, View } from 'react-native';
|
import { Pressable, Text, View } from 'react-native';
|
||||||
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import { AppLockSettingsScreen } from './screens/AppLockSettingsScreen';
|
import { AppLockSettingsScreen } from './screens/AppLockSettingsScreen';
|
||||||
import { BlacklistScreen } from './screens/BlacklistScreen';
|
import { BlacklistScreen } from './screens/BlacklistScreen';
|
||||||
import { DiagnosticBrowserScreen } from './screens/DiagnosticBrowserScreen';
|
import { DiagnosticBrowserScreen } from './screens/DiagnosticBrowserScreen';
|
||||||
|
|
@ -31,7 +32,12 @@ import { TagsScreen } from './screens/TagsScreen';
|
||||||
import { fonts, theme } from './theme';
|
import { fonts, theme } from './theme';
|
||||||
|
|
||||||
export type RootStackParamList = {
|
export type RootStackParamList = {
|
||||||
Scenes: undefined;
|
// `tab` odkłada HomeScreen (setParams) wyłącznie po to, żeby BugReportFAB wiedział,
|
||||||
|
// na której zakładce user był: zakładki to stan lokalny, nie osobne trasy.
|
||||||
|
Scenes: { tab?: string } | undefined;
|
||||||
|
// UWAGA: Movies/Sites/JAV/Anime NIE sa zarejestrowane w navigatorze od 2026-08-18 —
|
||||||
|
// zakladki to stan lokalny HomeScreen (trasa 'Scenes'). Klucze zostaja, bo ekrany
|
||||||
|
// typuja useNavigation<...,'Movies'> itd.; nawigowanie do nich rzuciloby bledem.
|
||||||
Movies: undefined;
|
Movies: undefined;
|
||||||
Sites: undefined;
|
Sites: undefined;
|
||||||
// JAV: osobna sekcja, ScenesScreen z paramem jav → backend ?jav=true.
|
// JAV: osobna sekcja, ScenesScreen z paramem jav → backend ?jav=true.
|
||||||
|
|
@ -112,23 +118,85 @@ const Stack = createNativeStackNavigator<RootStackParamList>();
|
||||||
|
|
||||||
type TopTab = 'Scenes' | 'Movies' | 'Sites' | 'JAV' | 'Anime';
|
type TopTab = 'Scenes' | 'Movies' | 'Sites' | 'JAV' | 'Anime';
|
||||||
|
|
||||||
function TopTabs({
|
/**
|
||||||
current,
|
* Jeden ekran-gospodarz dla pięciu zakładek. Zakładka to STAN LOKALNY, nie trasa.
|
||||||
onNavigate,
|
*
|
||||||
|
* Poprzednio każda zakładka była osobnym ekranem native stacka, a przełączenie robiło
|
||||||
|
* `navigation.replace(t)` — czyli wymieniało cały ekran RAZEM z nagłówkiem. LiquidTabs
|
||||||
|
* montował się od nowa z kroplą już na docelowej pozycji (pierwsze ustawienie jest
|
||||||
|
* celowo bez animacji), więc animacja „przelewania" nie miała fizycznej możliwości się
|
||||||
|
* wykonać: user widział statyczną, teleportującą się kropkę (zgłoszenie 2026-08-18).
|
||||||
|
* Pasek musi przeżywać przełączenie, żeby się animować, stąd jeden ekran.
|
||||||
|
*
|
||||||
|
* `key={tab}` na treści wymusza czysty remount przy przełączeniu — to samo, co robiło
|
||||||
|
* `replace` (reset wyszukiwania/scrolla). Bez key przełączenie Scenes→JAV reużyłoby
|
||||||
|
* instancję ScenesScreen i zostawiło stary tekst wyszukiwania w nowej sekcji.
|
||||||
|
*/
|
||||||
|
function HomeScreen({
|
||||||
|
navigation,
|
||||||
|
onLogout,
|
||||||
}: {
|
}: {
|
||||||
current: TopTab;
|
navigation: { setParams: (p: { tab?: string }) => void; navigate: (r: 'Donate' | 'AppLockSettings') => void };
|
||||||
onNavigate: (tab: TopTab) => void;
|
onLogout: () => void;
|
||||||
}) {
|
}) {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
const tabs: TopTab[] = ['Scenes', 'Movies', 'Sites', 'JAV', 'Anime'];
|
const tabs: TopTab[] = ['Scenes', 'Movies', 'Sites', 'JAV', 'Anime'];
|
||||||
|
const [tab, setTab] = React.useState<TopTab>('Scenes');
|
||||||
|
|
||||||
|
// BugReportFAB czyta zakładkę z route.params.tab (nazwa trasy to zawsze 'Scenes').
|
||||||
|
React.useEffect(() => {
|
||||||
|
navigation.setParams({ tab });
|
||||||
|
}, [tab, navigation]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// Logo + separator zostają statyczne, przewija się (i „roztapia") tylko pasek.
|
<View style={{ flex: 1 }}>
|
||||||
// `flexShrink` trzyma całość w swojej połowie nagłówka: bez tego pasek rozpycha
|
{/* Własny nagłówek zamiast natywnego (headerShown:false): natywny należy do
|
||||||
// się na całą szerokość i nachodzi na ikony po prawej.
|
ekranu, a ten pasek musi przeżywać przełączanie zakładek. Ikony po prawej są
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, paddingLeft: 10, flexShrink: 1 }}>
|
teraz jednakowe na każdej zakładce (wcześniej ♥ i ⚙ miał tylko Scenes). */}
|
||||||
|
{/* Tło nagłówka MUSI różnić się od wypełnienia paska (theme.card), inaczej
|
||||||
|
roztopiony kształt jest niewidzialny i z całego efektu zostaje sama kropka —
|
||||||
|
to była druga połowa zgłoszenia „statyczna kropka" (2026-08-18). */}
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
backgroundColor: theme.bg,
|
||||||
|
paddingTop: insets.top,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 8,
|
||||||
|
paddingLeft: 10,
|
||||||
|
paddingRight: 14,
|
||||||
|
paddingBottom: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<GoonMark size={28} />
|
<GoonMark size={28} />
|
||||||
<View style={{ width: 1, height: 16, backgroundColor: theme.border }} />
|
<View style={{ width: 1, height: 16, backgroundColor: theme.border }} />
|
||||||
<View style={{ flex: 1, minWidth: 170 }}>
|
<View style={{ flex: 1, minWidth: 170 }}>
|
||||||
<LiquidTabs tabs={tabs} current={current} onSelect={onNavigate} />
|
<LiquidTabs tabs={tabs} current={tab} onSelect={setTab} />
|
||||||
|
</View>
|
||||||
|
<View style={{ flexDirection: 'row', gap: 14, alignItems: 'center', marginLeft: 6 }}>
|
||||||
|
<Pressable onPress={() => navigation.navigate('Donate')} hitSlop={12}>
|
||||||
|
<Text style={{ color: theme.accentText, fontSize: 18 }}>♥</Text>
|
||||||
|
</Pressable>
|
||||||
|
<Pressable onPress={() => navigation.navigate('AppLockSettings')} hitSlop={12}>
|
||||||
|
<Text style={{ color: theme.muted, fontSize: 18 }}>⚙</Text>
|
||||||
|
</Pressable>
|
||||||
|
<Pressable onPress={onLogout} hitSlop={12}>
|
||||||
|
<Text style={{ fontSize: 17 }}>🚪</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={{ flex: 1 }} key={tab}>
|
||||||
|
{tab === 'Movies' ? (
|
||||||
|
<MoviesScreen />
|
||||||
|
) : tab === 'Sites' ? (
|
||||||
|
<SitesScreen />
|
||||||
|
) : tab === 'JAV' ? (
|
||||||
|
<ScenesScreen jav />
|
||||||
|
) : tab === 'Anime' ? (
|
||||||
|
<ScenesScreen vertical="animation" />
|
||||||
|
) : (
|
||||||
|
<ScenesScreen />
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
@ -170,121 +238,9 @@ export function AppNavigator({ onLogout, client, appVersion }: AppNavigatorProps
|
||||||
contentStyle: { backgroundColor: theme.bg },
|
contentStyle: { backgroundColor: theme.bg },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack.Screen
|
<Stack.Screen name="Scenes" options={{ headerShown: false }}>
|
||||||
name="Scenes"
|
{({ navigation }) => <HomeScreen navigation={navigation} onLogout={onLogout} />}
|
||||||
component={ScenesScreen}
|
</Stack.Screen>
|
||||||
options={({ navigation }) => ({
|
|
||||||
title: '',
|
|
||||||
headerLeft: () => (
|
|
||||||
<TopTabs
|
|
||||||
current="Scenes"
|
|
||||||
onNavigate={(t) => navigation.replace(t)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
headerRight: () => (
|
|
||||||
<View style={{ flexDirection: 'row', gap: 14, alignItems: 'center' }}>
|
|
||||||
<Pressable onPress={() => navigation.navigate('Donate')} hitSlop={12}>
|
|
||||||
<Text style={{ color: theme.accentText, fontSize: 18 }}>♥</Text>
|
|
||||||
</Pressable>
|
|
||||||
<Pressable
|
|
||||||
onPress={() => navigation.navigate('AppLockSettings')}
|
|
||||||
hitSlop={12}
|
|
||||||
>
|
|
||||||
<Text style={{ color: theme.muted, fontSize: 18 }}>⚙</Text>
|
|
||||||
</Pressable>
|
|
||||||
<Pressable onPress={onLogout} hitSlop={12}>
|
|
||||||
<Text style={{ fontSize: 17 }}>🚪</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="Movies"
|
|
||||||
component={MoviesScreen}
|
|
||||||
options={({ navigation }) => ({
|
|
||||||
title: '',
|
|
||||||
headerBackVisible: false,
|
|
||||||
headerLeft: () => (
|
|
||||||
<TopTabs
|
|
||||||
current="Movies"
|
|
||||||
onNavigate={(t) => navigation.replace(t)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
headerRight: () => (
|
|
||||||
<View style={{ flexDirection: 'row', gap: 14, alignItems: 'center' }}>
|
|
||||||
<Pressable onPress={onLogout} hitSlop={12}>
|
|
||||||
<Text style={{ fontSize: 17 }}>🚪</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="Sites"
|
|
||||||
component={SitesScreen}
|
|
||||||
options={({ navigation }) => ({
|
|
||||||
title: '',
|
|
||||||
headerBackVisible: false,
|
|
||||||
headerLeft: () => (
|
|
||||||
<TopTabs
|
|
||||||
current="Sites"
|
|
||||||
onNavigate={(t) => navigation.replace(t)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
headerRight: () => (
|
|
||||||
<View style={{ flexDirection: 'row', gap: 14, alignItems: 'center' }}>
|
|
||||||
<Pressable onPress={onLogout} hitSlop={12}>
|
|
||||||
<Text style={{ fontSize: 17 }}>🚪</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="JAV"
|
|
||||||
component={ScenesScreen}
|
|
||||||
initialParams={{ jav: true }}
|
|
||||||
options={({ navigation }) => ({
|
|
||||||
title: '',
|
|
||||||
headerBackVisible: false,
|
|
||||||
headerLeft: () => (
|
|
||||||
<TopTabs
|
|
||||||
current="JAV"
|
|
||||||
onNavigate={(t) => navigation.replace(t)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
headerRight: () => (
|
|
||||||
<View style={{ flexDirection: 'row', gap: 14, alignItems: 'center' }}>
|
|
||||||
<Pressable onPress={onLogout} hitSlop={12}>
|
|
||||||
<Text style={{ fontSize: 17 }}>🚪</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="Anime"
|
|
||||||
component={ScenesScreen}
|
|
||||||
initialParams={{ vertical: 'animation' }}
|
|
||||||
options={({ navigation }) => ({
|
|
||||||
title: '',
|
|
||||||
headerBackVisible: false,
|
|
||||||
headerLeft: () => (
|
|
||||||
<TopTabs
|
|
||||||
current="Anime"
|
|
||||||
onNavigate={(t) => navigation.replace(t)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
headerRight: () => (
|
|
||||||
<View style={{ flexDirection: 'row', gap: 14, alignItems: 'center' }}>
|
|
||||||
<Pressable onPress={onLogout} hitSlop={12}>
|
|
||||||
<Text style={{ fontSize: 17 }}>🚪</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="SiteScenes"
|
name="SiteScenes"
|
||||||
component={SiteScenesScreen}
|
component={SiteScenesScreen}
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,24 @@ import type { RootStackParamList } from '../navigation';
|
||||||
import type { SceneOut } from '../types';
|
import type { SceneOut } from '../types';
|
||||||
import { DEFAULT_FILTER, FilterState, ScenesFilterModal } from './ScenesFilterModal';
|
import { DEFAULT_FILTER, FilterState, ScenesFilterModal } from './ScenesFilterModal';
|
||||||
|
|
||||||
export function ScenesScreen() {
|
export function ScenesScreen({
|
||||||
|
jav: javProp,
|
||||||
|
vertical: verticalProp,
|
||||||
|
}: {
|
||||||
|
/** Nadpisuje param trasy. HomeScreen renderuje ten ekran BEZ nawigacji (zakładki to
|
||||||
|
* stan lokalny, nie osobne trasy), więc wertykał przychodzi propsem, nie paramem. */
|
||||||
|
jav?: boolean;
|
||||||
|
vertical?: string;
|
||||||
|
} = {}) {
|
||||||
const client = useClient();
|
const client = useClient();
|
||||||
const { gridColumns } = usePreferences();
|
const { gridColumns } = usePreferences();
|
||||||
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList, 'Scenes'>>();
|
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList, 'Scenes'>>();
|
||||||
// Zakładki wertykałów reużywają ten ekran: JAV przez stary param `jav`, Anime przez
|
// Zakładki wertykałów reużywają ten ekran: JAV przez `jav`, Anime przez
|
||||||
// `vertical='animation'`. Brak obu → główny feed, z którego backend odcina wertykały.
|
// `vertical='animation'`. Brak obu → główny feed, z którego backend odcina wertykały.
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const params = route.params as { jav?: boolean; vertical?: string } | undefined;
|
const params = route.params as { jav?: boolean; vertical?: string } | undefined;
|
||||||
const jav = params?.jav === true;
|
const jav = javProp ?? (params?.jav === true);
|
||||||
const vertical = params?.vertical;
|
const vertical = verticalProp ?? params?.vertical;
|
||||||
// Wspólna nazwa wertykału do zapytań o tagi (stary `jav` też ma swój słownik).
|
// Wspólna nazwa wertykału do zapytań o tagi (stary `jav` też ma swój słownik).
|
||||||
const verticalKey = vertical ?? (jav ? 'jav' : undefined);
|
const verticalKey = vertical ?? (jav ? 'jav' : undefined);
|
||||||
// Animacja NIE MA obsady i to nie brak danych, tylko wlasciwosc tresci: dla postaci
|
// Animacja NIE MA obsady i to nie brak danych, tylko wlasciwosc tresci: dla postaci
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue