From 90724af8effc97554e1e844e01ea0edffae69044 Mon Sep 17 00:00:00 2001 From: goon-foss Date: Mon, 7 Sep 2026 11:37:12 +0200 Subject: [PATCH] feat(mobile): bez gornej belki, ikona filtra, darowizna i backend w ustawieniach - pasek dolny nizszy (62) i przyciety na krawedzi ekranu, zaokraglone tylko gorne rogi - IconButton (filter-variant z licznikiem) zamiast pigulki Filter, SettingsButton w wierszu narzedzi Scenes/Movies/Sites - ustawienia: sekcje Support the project i Backend (host + wylogowanie), tytul Settings - changelog 2026-09-07c, OTA 5c8895d6 na 1.3 --- mobile/src/api.ts | 2 +- mobile/src/changelog.ts | 8 ++ mobile/src/components/BottomTabsBar.tsx | 14 +++- mobile/src/navigation.tsx | 62 +++------------- mobile/src/screens/AppLockSettingsScreen.tsx | 36 ++++++++- mobile/src/screens/MoviesScreen.tsx | 9 ++- mobile/src/screens/ScenesScreen.tsx | 17 ++++- mobile/src/screens/SitesScreen.tsx | 3 +- mobile/src/ui.tsx | 77 ++++++++++++++++++++ 9 files changed, 162 insertions(+), 66 deletions(-) diff --git a/mobile/src/api.ts b/mobile/src/api.ts index d9f1169..95a221f 100644 --- a/mobile/src/api.ts +++ b/mobile/src/api.ts @@ -41,7 +41,7 @@ export class ApiError extends Error { } export class GoonClient { - constructor(private baseUrl: string, private apiKey: string) { + constructor(readonly baseUrl: string, private apiKey: string) { this.baseUrl = baseUrl.replace(/\/+$/, ''); } diff --git a/mobile/src/changelog.ts b/mobile/src/changelog.ts index cb6ef92..cb7d9f3 100644 --- a/mobile/src/changelog.ts +++ b/mobile/src/changelog.ts @@ -29,6 +29,14 @@ export type ChangelogEntry = { }; export const CHANGELOG: ChangelogEntry[] = [ + { + id: '2026-09-07c', + date: 'September 2026', + items: [ + 'The top bar is gone: the bottom bar names the section, the gear next to the search box opens Settings, and Donate plus switching backend now live inside Settings.', + 'Filter is an icon with a counter of active filters. The bottom bar is lower and grows out of the screen edge.', + ], + }, { id: '2026-09-07b', date: 'September 2026', diff --git a/mobile/src/components/BottomTabsBar.tsx b/mobile/src/components/BottomTabsBar.tsx index bce55b6..09ec037 100644 --- a/mobile/src/components/BottomTabsBar.tsx +++ b/mobile/src/components/BottomTabsBar.tsx @@ -13,6 +13,10 @@ * (theme.ts). Pierscien to `accentText` z miekka poswiata (druga, szersza obwodka o * niskiej przezroczystosci), jeden kolor na wszystkich zakladkach. * + * Ksztalt (uwaga Jana 2026-09-07): pigulka nie jest zamknieta polokregiem od dolu, + * tylko przycieta na krawedzi ekranu, jakby z niej wyrastala. Zaokraglone sa tylko + * gorne rogi, dolne siedza na insecie systemowego paska. + * * Pozycje ikon mierzymy `onLayout` (flex:1 daje rowne komorki, ale szerokosc paska * zalezy od ekranu). Do pierwszego pomiaru pierscienia nie rysujemy. */ @@ -35,14 +39,14 @@ interface Props { /** Promien pierscienia: kolo 40 px wokol ikony 22 px. */ const RING_R = 20; -const RING_TOP = 8; +const RING_TOP = 6; const ICON_SIZE = 22; /** O ile poswiata wystaje poza pierscien, z kazdej strony. */ const GLOW_PAD = 3; /** Wysokosc samej pigulki, bez marginesu i bez inset systemowego paska. */ -export const BOTTOM_BAR_HEIGHT = 74; +export const BOTTOM_BAR_HEIGHT = 62; /** Odstep pigulki od dolu (nad inset). Eksport, zeby FAB zglaszania mogl wisiec wyzej. */ -export const BOTTOM_BAR_GAP = 10; +export const BOTTOM_BAR_GAP = 0; export function BottomTabsBar({ tabs, icons, current, onSelect }: Props) { const insets = useSafeAreaInsets(); @@ -164,7 +168,9 @@ const styles = StyleSheet.create({ }, pill: { height: BOTTOM_BAR_HEIGHT, - borderRadius: BOTTOM_BAR_HEIGHT / 2, + borderTopLeftRadius: 26, + borderTopRightRadius: 26, + borderBottomWidth: 0, backgroundColor: theme.card, borderWidth: 1, borderColor: theme.border, diff --git a/mobile/src/navigation.tsx b/mobile/src/navigation.tsx index b70968f..466bafe 100644 --- a/mobile/src/navigation.tsx +++ b/mobile/src/navigation.tsx @@ -5,11 +5,10 @@ import { } from '@react-navigation/native'; import { BugReportFAB } from './components/BugReportFAB'; import { BottomTabsBar } from './components/BottomTabsBar'; -import { GoonMark } from './components/GoonWordmark'; import { GoonClient } from './api'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import React from 'react'; -import { Pressable, Text, View } from 'react-native'; +import { View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { AppLockSettingsScreen } from './screens/AppLockSettingsScreen'; import { BlacklistScreen } from './screens/BlacklistScreen'; @@ -131,13 +130,7 @@ type TopTab = 'Scenes' | 'Movies' | 'Sites' | 'JAV' | 'Anime'; * `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, -}: { - navigation: { setParams: (p: { tab?: string }) => void; navigate: (r: 'Donate' | 'AppLockSettings') => void }; - onLogout: () => void; -}) { +function HomeScreen({ navigation }: { navigation: { setParams: (p: { tab?: string }) => void } }) { const insets = useSafeAreaInsets(); const tabs: TopTab[] = ['Scenes', 'Movies', 'Sites', 'JAV', 'Anime']; const [tab, setTab] = React.useState('Scenes'); @@ -148,47 +141,10 @@ function HomeScreen({ }, [tab, navigation]); return ( - - {/* Własny nagłówek zamiast natywnego (headerShown:false): natywny należy do - ekranu, a ten pasek musi przeżywać przełączanie zakładek. Ikony po prawej są - teraz jednakowe na każdej zakładce (wcześniej ♥ i ⚙ miał tylko Scenes). */} - - - - - {tab} - - - navigation.navigate('Donate')} hitSlop={12}> - ♥ - - navigation.navigate('AppLockSettings')} hitSlop={12}> - ⚙ - - - 🚪 - - - + + {/* Gornej belki nie ma (2026-09-07): nazwe sekcji mowi pasek na dole, kolo zebate + siedzi w wierszu narzedzi, darowizna i zmiana backendu w ustawieniach. Zostaje + tylko odstep na pasek statusu. */} {tab === 'Movies' ? ( @@ -254,7 +210,7 @@ export function AppNavigator({ onLogout, client, appVersion }: AppNavigatorProps }} > - {({ navigation }) => } + {({ navigation }) => } - {() => } + {() => } void }) { const [settings, setSettings] = useState(null); const [bioAvailable, setBioAvailable] = useState(false); const [stage, setStage] = useState('menu'); @@ -65,6 +65,9 @@ export function AppLockSettingsScreen() { const { gridColumns, setGridColumns, defaultQuality, setDefaultQuality, autoRotate, setAutoRotate } = usePreferences(); const navigation = useNavigation>(); const client = useClient(); + // Sam host, bez schematu: user ma zobaczyc, czy siedzi na instancji publicznej, + // czy na wlasnym serwerze. + const backendHost = client ? client.baseUrl.replace(/^https?:\/\//, '') : null; const queryClient = useQueryClient(); const [deviceId, setDeviceId] = useState(''); const [importCode, setImportCode] = useState(''); @@ -223,6 +226,37 @@ export function AppLockSettingsScreen() { return ( + {/* Darowizna i backend byly w gornej belce; belka znikla 2026-09-07. */} + + Support the project + + Goon is free, open-source and ad-free. Donations cover the server and the API keys. + + navigation.navigate('Donate')}> + ♥ Donate + + + + + Backend + + {backendHost ? `Connected to ${backendHost}` : 'Not connected'} + + {onLogout ? ( + + Alert.alert('Switch backend', 'Sign out and pick the public instance or your own server?', [ + { text: 'Cancel', style: 'cancel' }, + { text: 'Sign out', style: 'destructive', onPress: onLogout }, + ]) + } + > + Switch backend / sign out + + ) : null} + + App lock diff --git a/mobile/src/screens/MoviesScreen.tsx b/mobile/src/screens/MoviesScreen.tsx index a7912f1..1f04b6c 100644 --- a/mobile/src/screens/MoviesScreen.tsx +++ b/mobile/src/screens/MoviesScreen.tsx @@ -25,7 +25,7 @@ import { MoviePosterCard } from '../components/MoviePosterCard'; import { getLastSeen, markSeen } from '../lib/seenStore'; import type { RootStackParamList } from '../navigation'; import { theme } from '../theme'; -import { PillButton, SCREEN_PAD_H, SCREEN_PAD_TOP, SearchInput, Toolbar } from '../ui'; +import { IconButton, SCREEN_PAD_H, SCREEN_PAD_TOP, SearchInput, SettingsButton, Toolbar } from '../ui'; const PER_PAGE = 30; // 3 kolumny, plakaty 2:3 mieszczą się dobrze i widać 50% więcej filmów na ekran @@ -122,11 +122,14 @@ export function MoviesScreen() { autoCorrect={false} returnKeyType="search" /> - setFiltersOpen(true)} /> + ) : null} - 0 ? ` ${activeCount}` : ''}`} + 0} + badge={activeCount} onPress={() => setFilterOpen(true)} /> + {saved.length > 0 ? ( diff --git a/mobile/src/screens/SitesScreen.tsx b/mobile/src/screens/SitesScreen.tsx index cd22bf6..d6e45c3 100644 --- a/mobile/src/screens/SitesScreen.tsx +++ b/mobile/src/screens/SitesScreen.tsx @@ -21,7 +21,7 @@ import { import { useClient } from '../ClientContext'; import type { RootStackParamList } from '../navigation'; import { theme } from '../theme'; -import { PillButton, SCREEN_PAD_H, SCREEN_PAD_TOP, SearchInput, Toolbar } from '../ui'; +import { PillButton, SCREEN_PAD_H, SCREEN_PAD_TOP, SearchInput, SettingsButton, Toolbar } from '../ui'; import type { SourceOut, SourceRating } from '../types'; type Order = 'popular' | 'recent'; @@ -95,6 +95,7 @@ export function SitesScreen() { + diff --git a/mobile/src/ui.tsx b/mobile/src/ui.tsx index e22f477..481519f 100644 --- a/mobile/src/ui.tsx +++ b/mobile/src/ui.tsx @@ -1,3 +1,7 @@ +import { MaterialCommunityIcons } from '@expo/vector-icons'; +import { useNavigation } from '@react-navigation/native'; +import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import type { RootStackParamList } from './navigation'; /** * Wspólny zestaw kontrolek nagłówka ekranów-list (Scenes, Movies, Sites, JAV, Anime). * @@ -92,6 +96,56 @@ export function PillButton({ ); } +/** + * Kwadratowy przycisk z ikona zamiast pigulki z napisem. `badge` to licznik w rogu + * (np. liczba aktywnych filtrow), pokazywany tylko gdy > 0. + */ +export function IconButton({ + icon, + active, + badge, + onPress, + accessibilityLabel, +}: { + icon: React.ComponentProps['name']; + active?: boolean; + badge?: number; + onPress?: () => void; + accessibilityLabel: string; +}) { + return ( + + + {badge && badge > 0 ? ( + + {badge} + + ) : null} + + ); +} + +/** + * Wejscie do ustawien. Gorna belka znikla (2026-09-07), wiec kolo zebate siedzi w + * wierszu narzedzi kazdej sekcji; darowizna i zmiana backendu sa w ustawieniach. + */ +export function SettingsButton() { + const navigation = useNavigation>(); + return ( + navigation.navigate('AppLockSettings')} + /> + ); +} + /** Wiersz narzędzi: pole + przyciski, jednakowy odstęp i margines na każdym ekranie. */ export function Toolbar({ children }: { children: React.ReactNode }) { return {children}; @@ -99,6 +153,29 @@ export function Toolbar({ children }: { children: React.ReactNode }) { const styles = StyleSheet.create({ toolbar: { flexDirection: 'row', alignItems: 'center', gap: 10, marginBottom: 12 }, + iconBtn: { + width: CONTROL_H, + height: CONTROL_H, + borderRadius: RADIUS, + backgroundColor: theme.card, + borderColor: theme.borderStrong, + borderWidth: 1, + alignItems: 'center', + justifyContent: 'center', + }, + badge: { + position: 'absolute', + top: -6, + right: -6, + minWidth: 18, + height: 18, + borderRadius: 9, + paddingHorizontal: 4, + backgroundColor: theme.accent, + alignItems: 'center', + justifyContent: 'center', + }, + badgeText: { color: theme.fg, fontSize: 11, fontFamily: fonts.display }, search: { flex: 1, height: CONTROL_H,