From 0281e449fe2dc819ce990fc1bfbc60aa050d2468 Mon Sep 17 00:00:00 2001 From: jtrzupek Date: Sun, 31 May 2026 12:51:32 +0200 Subject: [PATCH] =?UTF-8?q?build(apk):=200.2.0=20=E2=80=94=20expo-font=20n?= =?UTF-8?q?ative,=20runtime=201.1,=20fonts=20re-enabled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Option B (rebuild APK) — odblokowuje custom fonty na stałe + sprawia że przyszłe font-OTA nie crashują. - runtime 1.0 → 1.1 (app.json + AndroidManifest EXPO_RUNTIME_VERSION): nowy APK ma native ExpoFontLoader, więc MUSI mieć inny runtime niż stare instalacje 1.0 (inaczej font-OTA crashnęłoby stare). 1.0 channel zostaje na d5b87e5c (font-stripped) dla starych, 1.1 = nowy APK z fontami. - version 0.2.0 / versionCode 10 (build.gradle) — in-app updater (/version=0.2.0) zaoferuje install starym 0.1.9. - Fonty przywrócone (useFonts, theme.fonts realne, SceneTile/MoviePosterCard/ navigation/GoonWordmark fontFamily) — działają bo native jest w APK. - Build: gradlew assembleRelease (autolinking expo-font, BEZ prebuild — zachowane custom native AntiTamper/ApkInstaller), Sentry source-map upload wyłączony (SENTRY_DISABLE_AUTO_UPLOAD, brak org/auth — krok poboczny). - app/main.py /version 0.1.9 → 0.2.0. ZWERYFIKOWANE na emulatorze: podpis SHA-256 == ALLOWED_APP_SIG_HASH (anti-tamper OK), ExpoFontLoader w classes3.dex, `ReactNativeJS: Running "main"` bez crasha. APK live: /static/app-release.apk + goon-v0.2.0.apk + landing webroot. UWAGA: launcher-icon (native mipmaps) NIE zmienione w tym buildzie — nadal stara ikona. Nowy oo-icon wymaga regeneracji res/mipmap-* + rebuild (follow-up). Co-Authored-By: Claude Opus 4.8 (1M context) --- app/main.py | 4 ++- mobile/App.tsx | 30 +++++++++++++++---- mobile/android/app/build.gradle | 4 +-- .../android/app/src/main/AndroidManifest.xml | 2 +- mobile/app.json | 4 +-- mobile/src/components/GoonWordmark.tsx | 5 ++-- mobile/src/components/MoviePosterCard.tsx | 8 ++--- mobile/src/components/SceneTile.tsx | 8 ++--- mobile/src/navigation.tsx | 6 ++-- mobile/src/theme.ts | 12 +++----- 10 files changed, 50 insertions(+), 33 deletions(-) diff --git a/app/main.py b/app/main.py index b7bacf2..c1256c8 100644 --- a/app/main.py +++ b/app/main.py @@ -19,6 +19,7 @@ from app.api.playback import movies_router as movies_playback_router from app.api.playback import router as playback_router from app.api.scene_favorites import router as scene_favorites_router from app.api.scenes import router as scenes_router +from app.api.seo import router as seo_router from app.api.sources import router as sources_router from app.api.stream_proxy import router as stream_proxy_router from app.api.taxonomies import router as taxonomies_router @@ -81,6 +82,7 @@ app.include_router(expo_updates_router) app.include_router(watch_router) app.include_router(admin_router) app.include_router(admin_html_router) +app.include_router(seo_router) mount_static(app) @@ -113,7 +115,7 @@ def version() -> dict[str, str | None]: # mobile sklei z baseUrl. public_url = os.environ.get("BACKEND_PUBLIC_URL", "").rstrip("/") apk_url = f"{public_url}/static/app-release.apk" if public_url else "/static/app-release.apk" - return {"version": "0.1.9", "apk_url": apk_url} + return {"version": "0.2.0", "apk_url": apk_url} @app.get("/readyz") diff --git a/mobile/App.tsx b/mobile/App.tsx index f99d2ef..5d5976a 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -6,6 +6,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import * as Sentry from '@sentry/react-native'; import Constants from 'expo-constants'; import { registerRootComponent } from 'expo'; +import { useFonts } from 'expo-font'; +import { Text as RNText } from 'react-native'; import * as ScreenCapture from 'expo-screen-capture'; import { StatusBar } from 'expo-status-bar'; import * as Updates from 'expo-updates'; @@ -75,12 +77,30 @@ const queryClient = new QueryClient({ }, }); -// NB: custom fonty (General Sans + Geist Mono) USUNIĘTE z bundla 2026-05-31 — -// `expo-font`/`ExpoFontLoader` natywny moduł NIE jest w APK 0.1.9 (build 22-maja, -// przed dodaniem expo-font) → useFonts crashował OTA bundle (ErrorRecovery rollback). -// System font do czasu rebuildu APK z expo-font. Patrz [[reference-ota-runtime-version]]. +// Globalny default fontu dla całego — General Sans Regular jako body. +// Komponenty które chcą display/mono nadpisują fontFamily jawnie (bo RN nie +// syntezuje weightów dla custom fontów). Bold-ale-bez-fontFamily tekst zostanie +// Regular weightem General Sans — wciąż distinctive face, akceptowalne dla +// nietkniętych ekranów; high-traffic komponenty mają jawny Semibold. +let _textDefaultApplied = false; +function applyDefaultFont() { + if (_textDefaultApplied) return; + _textDefaultApplied = true; + const T = RNText as unknown as { defaultProps?: { style?: unknown } }; + T.defaultProps = T.defaultProps || {}; + const prev = T.defaultProps.style; + T.defaultProps.style = [{ fontFamily: 'GeneralSans-Regular' }, prev].filter(Boolean); +} export default function App() { + const [fontsLoaded] = useFonts({ + 'GeneralSans-Regular': require('./assets/fonts/GeneralSans-Regular.ttf'), + 'GeneralSans-Medium': require('./assets/fonts/GeneralSans-Medium.ttf'), + 'GeneralSans-Semibold': require('./assets/fonts/GeneralSans-Semibold.ttf'), + 'GeistMono-Regular': require('./assets/fonts/GeistMono-Regular.ttf'), + }); + if (fontsLoaded) applyDefaultFont(); + const [hydrated, setHydrated] = useState(false); const [ageAccepted, setAgeAccepted] = useState(false); const [client, setClient] = useState(null); @@ -250,7 +270,7 @@ export default function App() { return () => sub.remove(); }, []); - if (!hydrated || !lockReady) { + if (!fontsLoaded || !hydrated || !lockReady) { return ( diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index e62c7b4..663cf03 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -93,8 +93,8 @@ android { applicationId 'com.goon.mobile' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 9 - versionName "0.1.9" + versionCode 10 + versionName "0.2.0" } signingConfigs { debug { diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml index 9eaf595..679ddd8 100644 --- a/mobile/android/app/src/main/AndroidManifest.xml +++ b/mobile/android/app/src/main/AndroidManifest.xml @@ -25,7 +25,7 @@ - + diff --git a/mobile/app.json b/mobile/app.json index ccc0189..0342556 100644 --- a/mobile/app.json +++ b/mobile/app.json @@ -2,11 +2,11 @@ "expo": { "name": "goon", "slug": "goon", - "version": "0.1.9", + "version": "0.2.0", "orientation": "portrait", "userInterfaceStyle": "automatic", "newArchEnabled": false, - "runtimeVersion": "1.0", + "runtimeVersion": "1.1", "updates": { "enabled": true, "url": "https://api.goon-foss.org/expo-updates/manifest", diff --git a/mobile/src/components/GoonWordmark.tsx b/mobile/src/components/GoonWordmark.tsx index d8ba112..2691c7b 100644 --- a/mobile/src/components/GoonWordmark.tsx +++ b/mobile/src/components/GoonWordmark.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { Text, View } from 'react-native'; import Svg, { Circle } from 'react-native-svg'; -import { theme } from '../theme'; +import { fonts, theme } from '../theme'; interface WordmarkProps { /** fontSize wordmarku w px. */ @@ -29,9 +29,8 @@ interface WordmarkProps { } export function GoonWordmark({ size = 26, color = theme.fg, mono = false }: WordmarkProps) { - // System bold (custom font usunięty z OTA bundla — ExpoFontLoader nie w APK). const base = { - fontWeight: '800' as const, + fontFamily: fonts.display, fontSize: size, letterSpacing: -size * 0.03, includeFontPadding: false as const, diff --git a/mobile/src/components/MoviePosterCard.tsx b/mobile/src/components/MoviePosterCard.tsx index af47e6a..78cf24e 100644 --- a/mobile/src/components/MoviePosterCard.tsx +++ b/mobile/src/components/MoviePosterCard.tsx @@ -3,7 +3,7 @@ import { Image } from 'expo-image'; import React from 'react'; import { Pressable, StyleSheet, Text, View } from 'react-native'; -import { theme } from '../theme'; +import { fonts, theme } from '../theme'; import type { MovieOut } from '../types'; export function MoviePosterCard({ @@ -101,7 +101,7 @@ const styles = StyleSheet.create({ paddingHorizontal: 6, paddingVertical: 2, }, - newBadgeText: { color: theme.fg, fontSize: 9, fontWeight: '800', letterSpacing: 0.6 }, + newBadgeText: { color: theme.fg, fontSize: 9, fontFamily: fonts.mono, fontWeight: '700', letterSpacing: 0.6 }, posterDimmed: { opacity: 0.45 }, watchedBadge: { position: 'absolute', @@ -124,7 +124,7 @@ const styles = StyleSheet.create({ backgroundColor: 'rgba(0,0,0,0.5)', }, progressFg: { height: 3, backgroundColor: theme.accent }, - title: { color: theme.fg, fontSize: 13, fontWeight: '600', marginTop: 6, letterSpacing: -0.2 }, + title: { color: theme.fg, fontSize: 13, fontFamily: fonts.display, marginTop: 6, letterSpacing: -0.2 }, titleDimmed: { color: theme.muted }, - meta: { color: theme.muted, fontSize: 10, fontWeight: '600', marginTop: 2, letterSpacing: 0.5, textTransform: 'uppercase' }, + meta: { color: theme.muted, fontSize: 10, fontFamily: fonts.mono, marginTop: 2, letterSpacing: 0.5, textTransform: 'uppercase' }, }); diff --git a/mobile/src/components/SceneTile.tsx b/mobile/src/components/SceneTile.tsx index 7f1cee7..94749cc 100644 --- a/mobile/src/components/SceneTile.tsx +++ b/mobile/src/components/SceneTile.tsx @@ -27,7 +27,7 @@ import React, { useState } from 'react'; import { Pressable, StyleSheet, Text, View } from 'react-native'; import type { RootStackParamList } from '../navigation'; -import { theme } from '../theme'; +import { fonts, theme } from '../theme'; import type { SceneOut } from '../types'; import { Thumb } from './Thumb'; @@ -190,13 +190,13 @@ const styles = StyleSheet.create({ durText: { color: theme.fg, fontSize: 11, - fontWeight: '600', + fontFamily: fonts.mono, fontVariant: ['tabular-nums'], }, title: { color: theme.fg, fontSize: 14, - fontWeight: '600', + fontFamily: fonts.display, marginTop: 8, letterSpacing: -0.2, }, @@ -204,7 +204,7 @@ const styles = StyleSheet.create({ meta: { color: theme.muted, fontSize: 10, - fontWeight: '600', + fontFamily: fonts.mono, marginTop: 3, letterSpacing: 0.5, textTransform: 'uppercase', diff --git a/mobile/src/navigation.tsx b/mobile/src/navigation.tsx index 56f44bb..2613853 100644 --- a/mobile/src/navigation.tsx +++ b/mobile/src/navigation.tsx @@ -24,7 +24,7 @@ import { SitesScreen } from './screens/SitesScreen'; import { StudioScenesScreen } from './screens/StudioScenesScreen'; import { TagScenesScreen } from './screens/TagScenesScreen'; import { TagsScreen } from './screens/TagsScreen'; -import { theme } from './theme'; +import { fonts, theme } from './theme'; export type RootStackParamList = { Scenes: undefined; @@ -101,7 +101,7 @@ function TopTabs({ style={{ color: active ? theme.accent : theme.muted, fontSize: 13, - fontWeight: active ? '700' : '500', + fontFamily: active ? fonts.display : fonts.medium, letterSpacing: 0.3, }} > @@ -145,7 +145,7 @@ export function AppNavigator({ onLogout, client, appVersion }: AppNavigatorProps