build(apk): 0.2.0 — expo-font native, runtime 1.1, fonts re-enabled

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) <noreply@anthropic.com>
This commit is contained in:
jtrzupek 2026-05-31 12:51:32 +02:00
parent 64506690df
commit 0281e449fe
10 changed files with 50 additions and 33 deletions

View file

@ -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")

View file

@ -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 <Text> — 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<GoonClient | null>(null);
@ -250,7 +270,7 @@ export default function App() {
return () => sub.remove();
}, []);
if (!hydrated || !lockReady) {
if (!fontsLoaded || !hydrated || !lockReady) {
return (
<View style={{ flex: 1, backgroundColor: theme.bg, justifyContent: 'center' }}>
<ActivityIndicator color={theme.fg} />

View file

@ -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 {

View file

@ -25,7 +25,7 @@
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://api.goon-foss.org/expo-updates/manifest"/>
<meta-data android:name="expo.modules.updates.EXPO_RUNTIME_VERSION" android:value="1.0"/>
<meta-data android:name="expo.modules.updates.EXPO_RUNTIME_VERSION" android:value="1.1"/>
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>

View file

@ -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",

View file

@ -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,

View file

@ -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' },
});

View file

@ -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',

View file

@ -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
<Stack.Navigator
screenOptions={{
headerStyle: { backgroundColor: theme.card },
headerTitleStyle: { color: theme.fg },
headerTitleStyle: { color: theme.fg, fontFamily: fonts.display },
headerTintColor: theme.accent,
contentStyle: { backgroundColor: theme.bg },
}}

View file

@ -56,15 +56,11 @@ export const theme = {
* Gdy useFonts jeszcze nie ready, App.tsx blokuje render (fonty z bundla
* ładują się <100ms), więc te stałe zawsze valid przy pierwszym paint.
*/
// Custom fonty USUNIĘTE z OTA bundla 2026-05-31 (ExpoFontLoader native nie ma w
// APK 0.1.9 → crash). `undefined` = system font (San Francisco/Roboto). Komponenty
// fallbackują na fontWeight dla hierarchii. Przywrócić do realnych rodzin gdy
// nowy APK z expo-font wejdzie do dystrybucji. Patrz [[reference-ota-runtime-version]].
export const fonts = {
body: undefined as string | undefined,
medium: undefined as string | undefined,
display: undefined as string | undefined,
mono: undefined as string | undefined,
body: 'GeneralSans-Regular',
medium: 'GeneralSans-Medium',
display: 'GeneralSans-Semibold',
mono: 'GeistMono-Regular',
} as const;
export function scoreColor(score: number): string {