Commit graph

55 commits

Author SHA1 Message Date
goon-foss
7bfd194485 fix(mobile): Edge - serduszko nie rusza dzwieku ani nie przewija klipu, jeden przycisk dzwieku, stroik feedu
Zgloszenia Jana 2026-09-16:
1+3. Tapniecie serduszka przelaczalo dzwiek i przewijalo klip na poczatek. Gesty lapala
   cala komorka razem z przyciskami, wiec tap w serduszko byl tez tapem w ekran, a zmiana
   dzwieku restartowala odtwarzanie (efekt aktywacji strony mial soundOn w zaleznosciach).
   Teraz gesty lapie tylko warstwa wideo, a wyciszenie ma osobny efekt.
2. Dwa przyciski dzwieku. Zostaje ten w kolumnie przy kciuku, w gornym pasku wchodzi stroik.
4. Za malo tagow na starcie: bylo 24 z 40, „anal" (27. co do liczby klipow) wypadal.
   Teraz 60 tagow + nisze + szukanie po calym slowniku (1,7 tys. tagow, nowy param q),
   wskazanie wazy 8 zamiast 5, a stroik mozna otworzyc w kazdej chwili i zmiana dziala
   od nastepnego rozdania.
5. Losowe miganie przy przewijaniu: dociagniecie kolejnej strony feedu podmienialo tablice
   klipow i restartowalo biezacy klip. Efekt zalezy teraz od numeru strony i adresow wideo.

Sprawdzone na emulatorze: tap w serduszko zostawia wyciszenie bez zmian i zapisuje like,
przycisk dzwieku odcisza, gorny pasek otwiera stroik, szukanie „anal" daje 8 wariantow,
a po Apply w clip_affinity siedzi anal=8.0. Edge dalej odklada zdarzenia w clip_feed_events.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:10 +02:00
goon-foss
bfa3444de2 feat(mobile): strona tworcy w Edge
Tapniecie nazwy tworcy otwiera jego strone: siatka wszystkich klipow, a tapniecie
kafelka gra je na pelnym ekranie z tym samym przewijaniem w pionie co Edge.
Zgloszenie z apki 2026-09-15: "cannot tap username as it's hidden behind icon tray".

- ClipPager: pionowy pager z dwoma playerami wyjety ze SwipeScreen, wspolny dla Edge
  i strony tworcy; feed, telemetria i autoSwipe zostaly w ekranach
- /clips?creator= oddaje `total` (liczba klipow tworcy) do naglowka
- ze strony tworcy leca tylko like/unlike i "nie interesuje": ogladanie stad nie moze
  zabetonowac feedu na jednym tworcy

Sprawdzone na emulatorze: link z Edge otwiera strone (@lilylovesyou2, 2 clips, verified),
kafelki trzymaja trzecia szerokosci takze w niepelnym rzedzie, pelny ekran gra i zamyka
sie przyciskiem pod paskiem stanu, a Edge dalej odklada zdarzenia w clip_feed_events.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:09 +02:00
goon-foss
7d5dd450f7 fix(mobile): monit o nowe APK takze na tym samym kanale OTA
0.4.0 i 0.4.1 maja ten sam runtime 1.4, a monit porownywal tylko runtime, wiec nikt
z 0.4.0 nie dostal propozycji aktualizacji i crash expo-video przy zamykaniu z ostatnich
wracal do Sentry dzien po poprawce (147164135).

- /version oddaje apk_build (versionCode 15)
- aplikacja czyta versionCode ZAINSTALOWANEGO APK przez natywny modul Sentry
  (expo-constants w SDK 52 nie oddaje go wcale, expo-application wymagalby nowego APK)
- numer builda trafia tez do kontekstu zgloszen z apki: app_version jedzie z paczka OTA,
  wiec nie mowil, ktore wydanie natywne ma zglaszajacy

Sprawdzone na emulatorze: 0.4.1 nie dostaje monitu i raportuje build=15, po instalacji
0.4.0 monit "Update available" pokazuje sie przy starcie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:09 +02:00
goon-foss
7ed878ce16 feat(mobile): gorne belki w jednym wierszu, pasek w Edge chowa sie przy przewijaniu
- SegmentTabs w ui.tsx: zakladki w wierszu narzedzi obok ikon
- Ulubione, performerka, studio, Performers i Tags: jeden wiersz pod naglowkiem
  zamiast trzech-czterech (etykieta z licznikiem, zakladki, podpowiedz, sortowanie)
- gwiazdka na ekranie performerki i studia bierze /favorites?counts=false
- Edge: kolejny klip chowa pasek, cofniecie pokazuje; podpis, przyciski i postep
  jada razem z paskiem; FAB zgloszen ukryty, lezal na "Not interested"
- changelog 2026-09-15c/d

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:37:53 +02:00
goon-foss
9872d5e4ca feat(mobile): zakladka Swipe, pionowy feed klipow (etap 4, APK 0.4.0 / runtime 1.4)
Nowa zakladka w dolnym pasku: react-native-pager-view (pion, natywny snap), dwie
instancje createVideoPlayer (aktywna + nastepna w buforze), komorka z posterem,
podpisem tworcy i tagami, kolumna przyciskow, pasek postepu. Gesty bez reanimated:
tap = dzwiek, double-tap = ulubione z wybuchem serca i haptyka, przytrzymanie = 2x,
przesuniecie w lewo = arkusz "show less of this" (tworca / tagi / nisze / seen it,
plus blokada tworcy). Onboarding 3 tapow z top tagow, AutoSwipe (off/5/10 s),
licznik obejrzanych, nowe rozdanie.

Telemetria: SwipeTelemetry zbiera zdarzenia i wysyla paczki co 5 s / 10 zdarzen /
w tle; przy opuszczeniu strony impression z dwell, skip (<2 s) albo complete (petla
lub >=80%). Serwer z tego uczy wagi i uklada 80% nastepnych stron.

Pager to modul natywny, wiec import jest miekki (require w try/catch) i zakladka
pokazuje sie tylko od runtime 1.4; ten sam bundle leci OTA na 1.2/1.3 z wpisem
"pobierz 0.4.0" (onlyBelowRuntime), a wpis o Swipe ma nowe pole minRuntime.
Bump: app.json 0.4.0 / runtime 1.4, versionCode 14, AndroidManifest 1.4,
publish_update RUNTIME_DEFAULT 1.4, strona goon-foss.org pod 0.4.0.

Sprawdzone na emulatorze (APK 0.4.0): zakladka widoczna, onboarding zapisany na
serwerze, feed spersonalizowany 8/2, ExoPlayer dekoduje wideo i audio, swipe daje
zdarzenia complete/impression, double-tap daje like + ulubione + wagi.
2026-09-15 09:24:13 +02:00
goon-foss
d5fb3fb521 fix(mobile): reset filtrow dziala od razu, licznik filtrow wzgledem domyslnych, rok w filtrze filmow 1900..2100
- ScenesFilterModal: Reset all filters stosuje domyslne i zamyka arkusz (f5193fba)
- ScenesScreen: has_playback domyslnie wlaczone nie liczy sie jako filtr, za to sort,
  min. dlugosc, min. jakosc i stuby tak
- MovieFiltersSheet: rok poza 1900..2100 ignorowany zamiast 422 (2b6dbc75)
- changelog 2026-09-14a, OTA 6cca22ce na 1.3

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 14:38:59 +02:00
goon-foss
320d928927 feat(mobile): naglowki ekranow podrzednych jak sekcje glowne, ikony ulubione/ukryj, pasek dolny wyzszy z pierscieniem centrowanym przez layout
- screenOptions: tlo ekranu, bez cienia, tytul 17 display, tint accentText
- HeaderIconButton (star/star-outline, eye-off-outline) na 5 ekranach zamiast ★/🚫
- BottomTabsBar: 76 dp, pierscien statyczny w iconBox w spoczynku, kapsula tylko w
  trakcie przejscia, srodki zaokraglone do piksela
- changelog 2026-09-08b/c, OTA 1cbb9181 i 18ba425a na 1.3
2026-09-08 10:09:34 +02:00
goon-foss
8c75b12066 feat(mobile): pasek chowa sie przy przewijaniu w dol (hystereza po drodze), FAB jedzie z nim, podpowiedz Sites do pierwszego przypiecia
- useAutoHideOnScroll: licznik drogi w jednym kierunku (48 px w dol chowa, 24 w gore
  pokazuje), strefy zawsze-widoczny przy gorze i dole listy, overscroll ignorowany
- HomeScreen useFocusEffect pokazuje pasek po powrocie z ekranu szczegolow
- changelog 2026-09-07e/f, OTA 40931479 i 8604dadb na 1.3
2026-09-07 11:53:31 +02:00
goon-foss
d9fbc08218 feat(mobile): pasek znika pod klawiatura, stukniecie w aktywna sekcje przewija na gore, Scenes w jednym wierszu ikon
- lib/bottomBar.ts: stale paska, szyna scroll-top, wartosc Animated do chowania
  (hysteresis po przebytej drodze, strefy gora/dol), inset dla list
- BottomTabsBar: absolute nad trescia, translateY z native drivera, null przy klawiaturze
- Scenes: Performers/Tags/Favorites jako IconButton obok lejka i zebatki, chipsy
  zapisanych wyszukiwan tylko przy fokusie albo wpisanym tekscie, Save jako chip
- changelog 2026-09-07d, OTA 3f7e21c5 na 1.3
2026-09-07 11:45:53 +02:00
goon-foss
90724af8ef 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
2026-09-07 11:37:12 +02:00
goon-foss
dce738b8ab chore(mobile): usun gorny pasek zakladek, zastapiony dolnym 2026-09-07 11:23:56 +02:00
goon-foss
b847b300bf feat(mobile): zakladki na dole ekranu, pierscien swiatla rozciaga sie do nowej ikony
- BottomTabsBar: pigulka nad krawedzia, aktywna ikona w pierscieniu; przy zmianie
  przednia krawedz wystrzela, tylna dogania (kapsula od starej do nowej), jeden
  kolor accentText z miekka poswiata zamiast neonu z reela
- naglowek: nazwa sekcji obok logo zamiast gornego paska
- BugReportFAB wisi nad paskiem na ekranie-gospodarzu
- changelog 2026-09-07b, OTA a2328005 na 1.3
2026-09-07 11:23:49 +02:00
goon-foss
bdac60f022 feat(mobile): Chromecast (0.3.0, runtime 1.3)
Zgloszenie de93ba42 ("Can't stream to Chrome cast"). Cast to natywny SDK, wiec NIE da
sie go wyslac przez OTA: to nowe APK, ktore ludzie musza pobrac sami. Klucz podpisujacy
ten sam, wiec ALLOWED_APP_SIG_HASH bez zmian i aktualizacja wchodzi na wierzch starej.

Argument, ktory przewazyl: od czerwca release ma wlaczone FLAG_SECURE, wiec zwykle
mirrorowanie ekranu na telewizor jest zablokowane. Cast jest jedyna droga na duzy ekran.

Zasieg: 77% udanych odtworzen konczy sie bezposrednim adresem, plus czesc hosterow
filmowych oddajacych gotowy plik. Okolo 13% (porndoe, mypornerleak, superporn) idzie
przez WebView i castowac sie NIE DA, tam przycisku nie ma.

Wpiete recznie, bez `expo prebuild`, bo katalog android/ jest w repo i ma reczne zmiany,
ktore prebuild by przepisal. Cztery edycje, dokladnie to co robi config plugin:
manifest (OPTIONS_PROVIDER + expanded controller), MainActivity, castFrameworkVersion
w rootProject.ext oraz JAWNA zaleznosc play-services-cast-framework w app/build.gradle.
Ta ostatnia jest konieczna, bo biblioteka deklaruje ja jako `implementation`, co nie
jest przechodnie na sciezke kompilacji, i bez niej build pada na compileReleaseKotlin.

Identyfikator odbiornika CELOWO zaden: bez wpisu biblioteka bierze domyslny odbiornik
Google. Rejestracja wlasnego wiazalaby konto Google z Goonem, a przy tresci dla
doroslych latwo o cofniecie.

Urzadzenia bez Google Play Services zabezpieczone w DWOCH miejscach, bo mamy uzytkownika
na LineageOS (GOON-3B) i sideload na zegarku (GOON-51): `getSharedInstance` w try/catch
po stronie natywnej, a po stronie JS cala obsluga w osobnym `CastControl`, montowanym
dopiero gdy `useCastAvailable` potwierdzi Play Services. To nie jest ostroznosc na
wyrost: hooki biblioteki synchronicznie subskrybuja natywne zdarzenia i bez GMS wywracaja
ekran, a hooka nie da sie wywolac warunkowo.

Chromecast pobiera plik SAM i nie wysyla naszych naglowkow, wiec zrodla wymagajace
Referera ida przez /proxy (dokłada go po stronie serwera), a reszta bezposrednio, zeby
nie obciazac VPS. Do tego proxy przestaje przekazywac CORS hostera: mixdrop oddawal
`Access-Control-Allow-Origin: https://mixdrop.my`, co odbiornik odrzucal przy HLS.

Przy okazji GOON-3B: doszedl brakujacy wpis `com.google.android.gms.version`, ktory
wywracal apke na LineageOS, gdy Chromium probowal podpiac skaner kodow.

Zweryfikowane na emulatorze na podpisanym APK: certyfikat identyczny ze starym
(3294aba5...), instalacja NA WIERZCH 0.2.2 udana, wersja 13/0.3.0, runtime 1.3 w
manifescie, aplikacja wstaje bez crasha, ExoPlayer gra (MediaCodec dla video), a SDK
Casta startuje poprawnie: dynamite sie laduje i `MediaRouterProxy` czyta NASZ CastOptions.
Logika wyboru adresu przetestowana osobno na osmiu przypadkach.

CZEGO NIE ZWERYFIKOWALEM: realnego rzutu na telewizor. W sieci emulatora nie ma zadnego
Chromecasta, wiec `loadMedia` i odtwarzanie po stronie odbiornika sa niesprawdzone.

Build wymaga SENTRY_DISABLE_AUTO_UPLOAD=true, bo sentry.properties czeka na
SENTRY_ORG/SENTRY_PROJECT/SENTRY_AUTH_TOKEN ze srodowiska (Infisical, workspace
goon-app). Skutek: slady JS z 0.3.0 beda w Sentry nieczytelne do czasu przebudowy z tymi
zmiennymi.
2026-08-24 14:27:41 +02:00
goon-foss
c9fa6edc6d feat(mobile): scalaj wiele duplikatow naraz zamiast parami
Zgloszenie c7f5e59e: "przydalaby sie mozliwosc zaznaczania wiecej niz 2 video
przy duplikatach". Przy pieciu kopiach tej samej sceny stary uklad wymagal
czterech przebiegow, kazdy z osobnym dialogiem, i za kazdym razem trzeba bylo
na nowo wskazac oryginal.

Model jest teraz odwrocony: dlugie przytrzymanie wybiera scene, ktora ZOSTAJE
(plakietka KEEP), a kolejne tapniecia zaznaczaja i odznaczaja jej duplikaty
(plakietka DUPLICATE, kafelek gasnie). Banner liczy zaznaczone i scala wszystkie
jednym przyciskiem. Dzieki temu uzytkownik swiadomie wybiera te kopie, ktorej
tytul i miniaturka przetrwaja, zamiast trafiac w nia przypadkiem.

Backend bez zmian, endpoint scala parami, wiec lecimy petla. Kazde scalenie to
osobna transakcja, wiec czesciowa porazka nie cofa udanych i raportujemy ja
wprost zamiast udawac sukces.

Sprawdzone na emulatorze na opublikowanej paczce: pozycja w menu, plakietki
KEEP i DUPLICATE, licznik 2 -> 1 -> 2 przy odznaczaniu, tresc potwierdzenia
z lista scen. Samego scalania nie wykonalem, to sa prawdziwe sceny z produkcji.
2026-08-23 21:25:32 +02:00
goon-foss
1e6be1926e fix(mobile): zdejmij maintainVisibleContentPosition, wywala apke na amen
GOON-1S: 53 wystapienia u 35 osob od 2026-07-03, poziom fatal. Lancuch przyczyn jest
jednoznaczny: JSApplicationIllegalArgumentException przy ustawianiu wlasciwosci
maintainVisibleContentPosition na RCTScrollView, dalej
MaintainVisibleScrollPositionHelper.getUIManagerModule() robi assertNotNull i gdy
ScrollView powstaje w chwili, w ktorej UIManager jest niedostepny, leci AssertionError.
To blad React Native 0.76.9, nie da sie go obejsc konfiguracja.

Wlasciwosc byla anti-jankiem: przy sort=created_at scrapery dosypuja sceny na gore,
wiec refetch potrafil szarpnac trescia pod palcem. Skakanie listy jest gorsze niz nic,
ale crash jest gorszy od skakania. Do rozwazenia po podniesieniu React Native.

Przy okazji GOON-4N (Cannot read property 'length' of undefined, 2 osoby): dokladnego
miejsca NIE da sie wskazac, bo build 0.2.2 poszedl bez source map, a zaden z naszych
czterech getNextPageParam nie siega po .length. Dokladamy tam tania defensywe na
niepelna strone; jesli bedzie wracac, najpierw trzeba naprawic wysylke source map.

Opublikowane OTA na 1.2 i 1.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 17:01:54 +02:00
goon-foss
bbc2059728 feat(ui): badge jakosci i nazwa serwisu na kafelku sceny
Kierunek A z makiet (miniaturki niosa ekran, chrome cichy) + jeden element z C:
jakosc i zrodlo widoczne wprost na kafelku.

Backend musial to najpierw WYSTAWIC, bo lista jedzie w trybie `light`, ktory okrawa
playback_sources do samej miniatury:
  - `SceneOut.max_quality_p` (kolumna z migracji 0029, dotad uzywana tylko jako filtr),
  - slim wpis niesie PRAWDZIWY `origin` zrodla wybranej miniatury zamiast "".

Kafelek: badge jakosci w LEWYM dolnym rogu (czas zostaje w prawym, ten sam ciezar
wizualny), a w linii meta studio + przygaszona nazwa serwisu. Badge pokazujemy TYLKO
gdy jakosc jest znana (6,5% scen), bo ma byc faktem, nie zgadywaniem.

Zweryfikowane na emulatorze na PRAWDZIWYCH danych: zeby to bylo mozliwe, zbudowalem
build debugowy podpisany kluczem release (przechodzi kontrole X-App-Signature, a jako
debug nie ma FLAG_SECURE, wiec da sie zrobic zrzut). Widac "4K" i "1280p" w rogu oraz
"ONLY FANS  SXYPRN" w linii meta. Tymczasowa zmiana podpisu w build.gradle cofnieta.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 12:41:16 +02:00
goon-foss
576058497a fix(ui): grupuj changelog po miesiacu, zdejmij naglowek z Sites
Changelog: 17 sierpniowych wpisow drukowalo "AUGUST 2026" 17 razy, bo naglowek szedl
przy KAZDYM wpisie. Teraz wpisy sa laczone w grupy miesieczne (sa juz newest-first,
wiec wystarczy sklejac kolejne z tym samym `date`), naglowek leci raz na grupe.

Sites: usuniety tytul "SITES" + licznik i podpowiedz "tap a tube -> newest scenes".
Byl jedynym ekranem-zakladka z wlasnym naglowkiem, przez co jego tresc zaczynala sie
nizej niz na pozostalych. Martwe style (headerRow/headerLabel/headerCount/hint) wyciete.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 12:23:04 +02:00
goon-foss
6d338219ea fix(ui): przesuwane podkreslenie zamiast ciekłej kropli w zakladkach
Zgloszenie 2026-08-18: kropla "zrobila wiecej zlego niz dobrego". Trzy zarzuty,
wszystkie trafne:
  - nie wygladala ladniej,
  - rysunek SVG mial 44 px i wystawal ponad pasek, wiec naglowek spuchl i rozjechalo
    sie wyrownanie wiersza do srodka,
  - morfowanie ksztaltu nie przypominalo wzoru.

Research wzorcow z liderow (X/Twitter, YouTube, Reddit, App Store, Duolingo, apki
bankowe): gorne zakladki to wszedzie plaski, powsciagliwy pasek STALEJ WYSOKOSCI z
PRZESUWANYM wskaznikiem, nie morfowanym. Uzytkownik wybral podkreslenie (wzorzec
dominujacy na Androidzie).

TopTabsBar: aktywna zakladka = accentText + cienka kreska hugujaca tekst, przejezdza
w 220 ms ease-out (translateX + width z pomiarow onLayout). Wysokosc = wiersz tekstu,
wiec logo/zakladki/ikony znow sa w jednej linii. Naglowek wraca na theme.card (trik z
theme.bg byl tylko po to, zeby kropla byla widoczna).

Usuniete: LiquidTabs.tsx + lib/liquidTabPath.ts (caly aparat SVG-morph, martwy).

Zweryfikowane na emulatorze nagraniem klatka po klatce: kreska przejezdza Anime->Scenes
mijajac zakladki, kolory sie przelaczaja, laduje pod aktywna; wiersz wyrownany.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 11:22:02 +02:00
goon-foss
0949091f78 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>
2026-08-18 09:59:24 +02:00
goon-foss
e074229bbb feat(ui): pasek zakladek roztapia sie wokol aktywnej pozycji
Wzorowane na reelu _code_and_chill_ ("the bar melts around it"), ale
technika wzieta z jego drugiego zdania: "every socket is solved for
tangency, so the liquid never creases". Czyli sciezka LICZONA, nie
rozmywana.

Filtr "goo" (rozmycie + prog alfy) byl pierwszym pomyslem i zostal
ODRZUCONY po zajrzeniu w zrodlo react-native-svg. Filtry na Androidzie
dzialaja (GroupView extends RenderableView, ktory obsluguje mFilter), ale
RenderableView.java:376 przy KAZDYM rysowaniu robi Bitmap.createBitmap(
canvas.getWidth(), canvas.getHeight(), ARGB_8888), rysuje do niej element,
naklada programowy filtr i wrzuca wynik z powrotem. Przy animowanej kropli
to pelnoekranowa alokacja na klatke, w nagłowku KAZDEGO ekranu.

liquidTabPath: gniazdo to dwa luki styczne jednoczesnie do krawedzi paska
(srodek na y=top+k) i do kropli (odleglosc srodkow = r+k), stad
dx = sqrt((r+k)^2 - (top+k-cy)^2). Jedna <Path>, zero alokacji.

Weryfikacja liczbowa (nie wizualna): trzy niezmienniki stycznosci trzymaja
sie do 1e-9, piec przypadkow brzegowych OK. Test wylapal brakujacy warunek
`cy - r < top`: bez niego wzor ma rozwiazanie takze gdy kropla siedzi CALA
w pasku (top=26, cy=45, r=17, k=12 -> dx≈28,1) i powstawaloby gniazdo, w
ktore nie ma sie co wtopic.

Animacja: Animated.Value + listener przepisujacy cx do stanu, bo sciezka
to string i nie da sie jej podac Animated wprost (brak Reanimated w
projekcie). ~12 re-renderow SVG na 200 ms przejscia, poza tym komponent stoi.
useNativeDriver=false swiadomie: animujemy geometrie, nie transform.

Etykieta aktywnej zakladki siedzi na wypelnieniu akcentu — jasny tekst daje
tam 5,03:1, jedyny wariant tego koloru przechodzacy AA (patrz theme.ts).
2026-08-14 10:13:30 +02:00
goon-foss
2a163cbf2c feat(tile): dwie linie tytulu + zdejmowanie powtorzonej nazwy studia
Pomiar na 200 tys. grywalnych scen >=60 s (2026-08-13): przy JEDNEJ linii
pelny tytul widzialo **14,3%** scen. Mediana tytulu to 46 znakow, a w
kolumnie dwukolumnowej siatki miesci sie ~24 na linie, wiec 85,7% tytulow
bylo przycietych. Przy dwoch liniach pelny tytul widzi 54,4%.

To SWIADOMIE odwraca czesc wczesniejszej decyzji ("Jan feedback: wieksze
miniaturki, mniej tekstu" w docstringu tego pliku) — uzgodnione, bo tamta
uwaga dotyczyla nadmiaru metadanych, nie przycinania samego tytulu.
Miniaturka zostaje w tym samym rozmiarze, rosnie tylko blok tekstu (~18 px).

Do tego `titleWithoutStudio`: gdy druga linia pokazuje studio, zdejmujemy
jego nazwe z PRZODU tytulu ("MYLF - Aria's MILF Temptation" nad meta
"MYLF"). Dotyczy 8,2% scen. Zdejmujemy tylko przedrostek, wiec studio na
koncu tytulu ("… - ATKGirlfriends") zostaje nietkniete. Gdy po zdjeciu
zostaje <12 znakow, oddajemy tytul nietkniety, bo "Scene 1" jest gorsze
niz powtorzenie. 9 przypadkow testowych na realnych tytulach.

Korekta wlasnej diagnozy z przegladu: napisalem tam, ze tytul i studio
maja niemal rowna wage. Nieprawda — 14 px display/fg vs 10 px mono/muted
wersalikami. Hierarchia byla w porzadku, problemem bylo obciecie.
2026-08-14 09:58:20 +02:00
goon-foss
7deda639bf fix(theme): rozdziel role akcentu i dodaj ramke, ktora cokolwiek oddziela
Pomiar WCAG na realnych parach z apki (2026-08-13):

    accent #B23A48 jako tekst:  3,21 na bg | 2,96 na bgElevated | 2,75 na card
    border #3A3128 jako granica: 1,48 na bg | 1,27 na card

Czyli kolor MARKI byl ponizej nawet progu 3:1 dla elementow interfejsu,
a nie tylko ponizej 4,5 dla tekstu. Dotyczylo to aktywnych zakladek,
gwiazdek ulubionych, linkow i chipow. Ramki przy 1,27 nie byly granica,
tylko cieniem.

NIE zmieniam koloru marki. Podniesienie samego `accent` do progu tekstu
wymagaloby zejscia w roz (#CE6975), co likwiduje tozsamosc, ktorej broni
naglowek theme.ts. Zamiast tego rozdzielam ROLE tego samego koloru:

  accent      zostaje do WYPELNIEN — jasny tekst na nim ma 5,03, przechodzi
  accentText  #C75260 dla tekstu i obwodek — 4,30 / 3,96 / 3,68

62 podmiany w 24 plikach (34 color, 26 borderColor, 2 thumbColor).
38 wypelnien nietknietych. Sprawdzone skryptem, ze zaden zmieniony tekst
nie stoi na tle akcentu.

borderStrong #7B7065 dla granic NIOSACYCH ZNACZENIE (pola tekstowe, 12
miejsc); dekoracyjne wloski zostaja na `border`. Wartosc dobrana pod obie
powierzchnie, bo pola leza i na bg, i na card: #6B6157 dawal na karcie
2,66, a #73695E dokladnie 2,999, czyli wciaz ponizej progu.
2026-08-14 09:50:08 +02:00
goon-foss
a4486980a4 style: myslniki em/en z komentarzy i docstringow (calosc repo)
1745 wystapien w 291 plikach (backend, scripts, mobile). Dominowal jeden ksztalt,
' — ' laczace zdania, wiec poszedl przecinek; myslnik otwierajacy mysl zdjety;
zakresy 0–5 i A–Z na dywiz.

Podzial komentarz/kod robil skaner stanow, nie regex, zeby nie ruszyc myslnika
stojacego w stringu albo w wyrazeniu regularnym. Potwierdzone maszynowo: po wycieciu
komentarzy z wersji HEAD i z dysku obie sa identyczne we wszystkich 291 plikach,
czyli poza komentarzami nie zmienilo sie nic. 233 pliki .py parsuja sie bez bledu,
tsc ma te same 11 bledow w tych samych 3 plikach co przed zmiana.

Dwie rzeczy wymagaly poprawki po automacie: wyrownane listy definicji, gdzie myslnik
byl separatorem kolumny (37 miejsc, kolumna przywrocona), i trzy przeniesienia mysli
do nowej linii, gdzie zostawal wiszacy przecinek na poczatku (poprawione recznie).

Bundla nie republikuje: Hermes i tak nie niesie komentarzy, wiec dla uzytkownika
to zero zmiany.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:51:57 +02:00
goon-foss
017927793a style(mobile): myslniki em/en poza tekstow widocznych dla uzytkownika
32 miejsca w 14 plikach: changelog, onboarding, ekrany Sites/Blacklist/Login/Player,
komunikaty bledow, placeholdery. Zamiast myslnika przecinek, dwukropek, kropka albo
nawias, zaleznie od tego co dane zdanie robi.

Zostawione swiadomie: pojedynczy glif U+2014 jako znacznik BRAKU WARTOSCI
(release_year ?? '—', nieocenione osie w SitesScreen, separator zakresu w filtrze
filmow). To element interfejsu, nie proza, a zwykly dywiz wyglada tam gorzej.
Zostawione tez komentarze w kodzie, w tym te wewnatrz INJECTED_JS.

Przy okazji: MigrationBanner dostal twardy warunek na runtime (needsManualMigration).
Wczesniej przed pokazaniem go nowej wersji chronilo TYLKO to, ze kanal OTA 1.2 byl
pusty. Pierwsza publikacja na 1.2 wyslalaby ten sam bundle i baner kazalby migrowac
z wersji, na ktora user wlasnie przeszedl.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:29:21 +02:00
goon-foss
1a6ddfef40 fix(mobile): skroc tresc banera migracji + changelog + em-dash w dialogu instalacji
Weryfikacja na emulatorze (build debugowy, Metro): pasek i modal renderuja sie
poprawnie, kod synchronizacji sie pokazuje, przycisk otwiera goon-foss.org.
Tresc byla za dluga, urywala sie na naglowku kroku 4 i wygladala jak zepsuta;
po skroceniu miesci sie bez scrollowania.

Przy okazji potwierdzone na dexach: ExpoKeepAwake/KeepAwakeModule wchodzi teraz
do APK, wiec keep-awake zadziala po wydaniu 0.2.2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 09:32:04 +02:00
goon-foss
0c818ac1df feat(mobile): baner migracji na nowo podpisane APK + expo-keep-awake do buildu
Klucz podpisujacy stare buildy przepadl, wiec update in-place jest niemozliwy:
Android nadpisze aplikacje tylko buildem z tym samym podpisem. Odinstalowanie
czysci SecureStore, a w nim goon.device_id, czyli kod synchronizacji, bez ktorego
ulubione/postep zostaja na serwerze bez sposobu wskazania ich. Baner pokazuje kod
na wierzchu i prowadzi przez kroki (kopiuj kod, pobierz, odinstaluj, wklej kod).

expo-keep-awake: sprawdzenie stringow w dexach APK 0.2.1 potwierdzilo, ze modulu
ExpoKeepAwake tam nie ma (jest tylko interfejs z expo-modules-core), wiec ekranu
gasnacego w trakcie ogladania NIE dalo sie naprawic przez OTA. Teraz jawna
zaleznosc, autolinking ja widzi, wchodzi do APK 0.2.2 (runtime 1.2).

UWAGA przy publikacji banera na runtime 1.1: manifest bierze runtimeVersion z
argumentu --runtime, wiec 1.1 jest serwowane poprawnie mimo app.json=1.2, ale
extras nadal niosa app.json (APP_VERSION zaczyna raportowac 0.2.2). Dlatego
serwerowe /version trzeba bumpnac do 0.2.2 razem z wgraniem APK, inaczej stary
dialog Update available wyskoczy z mylacym Server 0.2.1 / App 0.2.2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 09:17:30 +02:00
goon-foss
4417ae0ff0 feat(tags): scal duplikaty liczby mnogiej + prewencja + skrocone liczniki
Some checks failed
Backend tests / test (push) Has been cancelled
1) Duplikaty tagow wrocily, ale INNYM wzorcem niz w lipcu: alnum-klucz z natury nie
lapie liczby mnogiej ('blowjob' != 'blowjobs'). Audyt: 1944 pary, m.in.
Blowjob/Blowjobs (390728 vs 791), Teen/Teens (53096 vs 41294), Cumshot/Cumshots.
Scalone oba kierunki (kanoniczny = wiekszy scene_count): 1938 + 2063 tagow,
przeniesione 251251 + 26142 przypisan scen i 118522 + 392 filmow. Zostaje 581 par
(lancuchy i remisy) - celowo pominiete, wymagaja recznej decyzji.

2) Prewencja w _resolve_by_altkey: gdy alnum-klucz nie trafi, probujemy obu form
(+s / -s). Tylko proste 's' - form nieregularnych (panty/panties) NIE ruszamy, bo
zbyt latwo o falszywy zlew (glass/glasses, bra/bras). Zweryfikowane na prodzie:
Blowjobs->Blowjob, Teens->Teen, Cumshots->Cumshot, Lesbians->Lesbian.

3) UI: formatCount() skraca duze liczniki (181764 -> 181k, 1200 -> 1,2k) w tagach,
performerach, ulubionych i filtrach filmow - user-request, chipy przestaja puchnac.
2026-08-03 09:19:50 +02:00
goon-foss
33553729f8 feat(diag): sxyprn resolve reason in bug-report auto-context
Some checks failed
Backend tests / test (push) Has been cancelled
'sxyprn ładuje reklamy' jest niereprodukowalny z naszych IP (strona zwraca
data-vnfo → resolver OK) → podejrzenie region/IP-gate u usera. resolveSxyprnPage
zapamiętuje powód ostatniego resolve (http_<status> / challenge_<len> /
no_vnfo_<len> / post_not_found / vnfo_parse_err / ok_N) i BugReportFAB dokleja go
jako sxyprn=<reason> do auto-contextu. Przy kolejnym zgłoszeniu zobaczymy CO sxyprn
realnie zwrócił temu userowi, bez pytania. Non-behavioral (nie rusza resolve).
2026-07-22 11:25:11 +02:00
goon-foss
21500837ab feat(bugreport): auto-attach device + last-playback context
Some checks failed
Backend tests / test (push) Has been cancelled
Playback reports ("doesn't start", "audio lags") came in with no way to know the
device or which source/server was used, forcing a follow-up question. Now the bug
report auto-context also carries:
- device = phone model / Android version (Platform.constants, zero-dep)
- play = last-played origin/host, mode, position, and last player error

New in-memory lastPlayback store written by PlayerScreen on source/status change, read
by BugReportFAB when composing a report. Reset on app restart (current session only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:53:30 +03:00
goon-foss
cb0b843f48 refactor(review): dedup favorites/list visibility + SQL-aggregate count, share mobile isNew
Follow-up cleanup from the ultra-review (behaviour-preserving, verified equivalent):

- scenes.py: extract live_playback_exists / blacklist_clauses / stub_exclusion_clause;
  list_scenes and favorites now share ONE definition of "visible scene" (was a hand-kept
  copy in favorites -> the count-vs-list drift class). Verified identical: helper vs old
  inline both count 1,853,327 scenes.
- favorites.py: replace the two copy-pasted count blocks with one _new_counts(kind=...)
  that counts in SQL (count(*) FILTER over the windowed subquery) instead of streaming up
  to N*200 rows to Python; joins the favorite table for per-row last_seen. Deployed
  _new_counts verified == hand SQL (studios 364). Dropped now-unused imports.
- mobile: extract lib/newScenes.ts (isNewScene / sortNewFirst); SceneTile + Performer/
  StudioScenes use it (was triplicated, already drifted once in the deleted FavoriteSceneRow).
- SceneDetail: fold tube:pornxpph into the phoneResolver map (was a verbatim-duplicated block).
- deep_crawl: persist the cursor after every completed page (was once at run end), so a
  mid-page hard-kill past the soft budget can't lose progress (GOON-V hardening).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:41:37 +02:00
goon-foss
15e7c1646d fix(review): player recovery deadlocks, quick-play re-fire, backfill gaps, em-dashes
Addresses the ultra-review findings on this branch:

Player (PlayerScreen.tsx): the new recoveryPending mirrored the fallback-chain guards
by hand and could deadlock into a permanent "Reconnecting" spinner with no way to Mark
broken — for gone (410) sources on IP-bound tubes (re-resolve bails before setting
reResolveDone) and for any post-load error on those tubes (re-resolve is initial-load
only). Derive one reResolveApplicable flag (IP-bound AND initial-load AND not-gone) and
use it for both the chain gate and the spinner, so gone/post-load errors fall through to
proxy/WebView or the terminal error card. Seek-recovery now falls through to the chain
when player.replace() throws instead of returning.

Quick-play (SceneDetail): the autoplay route param persisted and autoPlay={i===0} re-fired
when the source list reordered (e.g. after Mark broken drops the dead source), bouncing the
user into the player. Consume it once via onAutoPlayConsumed -> nav.setParams({autoplay:false}).

Backfill semantics: performer-driven direct-scraper "backward fill" now tags scenes
backfill=True (search-by-name pulls the whole old catalog); merge coalesces backfill
(keep AND drop) so a fresh scene merged into a dead dup keeps NEW; deep-crawl only tags
backfill on a tube's FIRST sweep (swept_once) so re-sweep catalog growth stays genuine;
pilot script tags backfill.

Perf/migration: migration 0026 is now idempotent (IF NOT EXISTS; prod got the column via
manual ALTER) and adds ix_scene_performers_performer_id (favorites count filtered
performer_id with no index); index also created on prod.

Cleanup: deleted dead FavoriteSceneRow (unused import in two screens, stale isNew without
the backfill guard); removed em-dashes from all lines this branch added (user CLAUDE.md
rule), including the user-facing changelog / Settings / player-overlay strings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:20:40 +02:00
goon-foss
07cc3fdfba fix(favorites): exclude bulk-backfill scenes from "+N new" (tube fake dates)
Browse scrapers backfilling old catalogs stamp the tube's import/post date as
release_date, so old content (e.g. 83 MissaX classics via perverzija, ~3600/3 days
across eporner/youporn/etc.) fake-ranked as newest and flooded the favorites "+N".
NULLing the dates was a non-starter — the stub filter would hide 251k performer-less
scenes. Instead: a Scene.backfill flag marks bulk catalog imports; they stay visible but
never count as "new".

- scenes.backfill column (+ index, migration 0026); resolve_scene/_process_scene thread it.
- deep_crawl tags scenes from pages beyond the "latest" threshold (>2) as backfill;
  latest pages + TPDB/StashDB delta stay genuine. Cursor reset re-sweeps page 1 so real
  new content is always caught fresh.
- favorites +N (performers + studios) excludes backfill within the top-200 window.
- SceneOut exposes `backfill`; mobile NEW badge + NEW-first re-sort skip it (badge==count).
- Retroactive: tagged 439k existing scenes in bulk (>10 non-canonical / studio / day)
  clusters. Device check: favorite-studios +N 11626 (naive) -> 236.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 16:04:01 +02:00
goon-foss
17d82d465a feat(mobile): quick-play ▶ on scene thumbnails
Tap the ▶ overlay on a tile to play the best source without opening SceneDetail first
(user request: fewer steps). It routes to SceneDetail with an autoplay flag that fires the
top source's existing resolve on mount — reusing all the phone-side/backend resolve,
quality-picker and fallback handling in place rather than duplicating it. With a default
quality set (Settings → Playback) this is one tap to video; otherwise the quality chooser
still appears. ▶ is hidden in duplicate-select mode; tap elsewhere on the tile = details.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 10:45:50 +02:00
goon-foss
c029b7c687 fix(mobile): anchor scene lists so prepended scenes don't jump the scroll
Lists sort by created_at desc, so scrapers add new scenes at the top; on refetch those
prepend above the viewport and the whole list slid down under the user's thumb (jitter/
tearing while browsing filtered results). Added maintainVisibleContentPosition to the
shared sceneGridProps() so RN pins the visible item and corrects the offset; a small
autoscrollToTopThreshold still surfaces new items when the user is at the very top.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 10:37:19 +02:00
goon-foss
0ce4675574 fix(mobile): onboarding pager — measure page width so last slide shows "Start browsing"
scrollTo/onScroll used the full screen width, but the ScrollView viewport is narrower
(card margins + padding), so the computed index desynced from the visible slide — the
last slide kept showing "Next"/"Skip" instead of "Start browsing". Measure the real
viewport width via onLayout and use it for paging, scrollTo and index. Caught on the
emulator (uiautomator dump — FLAG_SECURE blocks screenshots).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:21:19 +02:00
goon-foss
e1dd46c6f2 feat(mobile): first-launch tutorial (pages, features, long-presses, player gestures)
A 7-slide carousel shown once on first launch:
- the three tabs (Scenes/Movies/Sites)
- search, filters, saved searches, Performers/Tags/Favorites
- long-press actions (hide/duplicate a scene, remove a wrong performer, link diagnostics)
- player gestures (tap controls, double-tap ±15s, swipe to scrub, unmute)
- favorites, Hidden content, PIN lock, the ? report button, Sites ★ ratings

Gated by a SecureStore flag; replayable from Settings ⚙ → Replay tutorial (via a
tiny onboarding bus). Suppresses the What's-new popup for brand-new users (the tour
covers it) and marks the changelog seen on finish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:08:56 +02:00
goon-foss
8c8a3d5823 feat(mobile): movies — performer filter + 3-column grid
Two Movies-list reports. (1) 1044cd34 'do movies have a metadata base for performers/categories/studio/year': yes — 90% have year, 92% studio, 81% performers, 93% tags, and the filter already covered studio/genre/year. Added the missing dimension: a performer search-and-select in MovieFiltersSheet (backend listMovies + api.ts already accepted performer_ids; only the UI was missing). (2) 0200956f 'use the space better': Movies grid goes 2 -> 3 columns (poster card is flex:1, scales fine) so ~50% more films per screen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 23:21:22 +02:00
goon-foss
f3802ca5c6 fix(mobile): scene-list scroll perf + native phone-side fpoxxx resolver
(1) Scroll jank/device load on long scene lists (report 5b7ca1e1): SceneTile is now React.memo'd so typing in search no longer re-renders every mounted tile, and sceneGridProps bounds the render window (windowSize 7 etc.) — required because removeClippedSubviews stays false to avoid thumbnail blanking. Applies to all scene grids. (2) fpoxxx played an ad instead of the video via the WebView fallback (reports f79beefb/cfa207c7). fpoxxx is KVS with an IP-bound + session-bound get_file token (cross-IP 403 confirmed), so it must resolve phone-side: new fpoxxxResolver fetches the page + follows get_file on the device (KVS real_url port for the function/0 case), wired into SceneDetailScreen like sxyprn/eporner. Verified from a residential IP: get_file -> CDN returns 206 video/mp4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 11:02:21 +02:00
goon-foss
66cd2e2cc4 feat(mobile): column toggle, duration filter, saved searches, screen protection (mobilism feedback)
Batch from user feedback: (1) Grid columns 1/2/3 setting (PreferencesContext, persisted) across all scene grids — default 2 was too small on phones. (2) Min-duration filter chips (5/10/20/30+ min) to hide ad-clips. (3) Saved-search chips + Save button (backed by /saved-searches). (4) Re-enabled screen-capture protection (Recents hide + screenshot block) for distributed users — verified active on emulator (screencap returns 0 bytes). (5) 'Checking for updates' gate before the PIN screen so a background OTA restart no longer causes a double PIN prompt. Changelog entry added. Published OTA runtime 1.1 (a9620b12).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 13:52:27 +02:00
goon-foss
b430811b93 fix(mobile): capture site/origin text params in bug-report auto-context
SiteScenes passes the tube as origin/name (strings), not UUIDs, so the existing UUID-only auto-context loop dropped them. Reports like 'ingest of this site has been stuck 2 days' (14f3a655) arrived without any site identifier. Add a second loop for known string identity params (origin/name/sitetag/tag/q), length-capped, so per-site/per-performer reports become actionable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-15 09:35:58 +02:00
goon-foss
c3ed0245e4 feat(mobile): "What's new" popup after OTA updates
After an OTA bundle is applied, show a one-time popup listing recent changes. The
changelog ships in the bundle (mobile/src/changelog.ts), so it is always in sync with
the code that just arrived. WhatsNewModal compares the newest entry id against the last
one seen (SecureStore); shows unseen entries, marks seen on dismiss, and stays quiet
until the next update adds an entry. First run shows only the newest entry (no history
dump). Mounted over the navigator when signed in.

Each OTA publish should prepend a new entry at the top of CHANGELOG.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 11:41:54 +02:00
goon-foss
f1c1e60007 feat(mobile): "Your messages" inbox on bug FAB + geo-block playback hint
Bug FAB now has two tabs: "Report a bug" (existing) and "Your messages", which lists
this device's reports with any admin reply in a highlighted box. A badge dot on the FAB
shows unread replies; opening the tab marks them seen. Polls every 90s and on open.

PlayerScreen: when the WebView fallback (residential IP) cannot extract a stream within
25s and there is no 404/410, show a one-time hint that the source may be blocked in the
user's region or by their ISP (try another source or a VPN) - so a geo/network block on
the user's side does not read as a broken app.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 11:35:44 +02:00
goon-foss
864376c58b fix(mobile): English long-press action labels + clean thumb error placeholder
bug-report c25e9b55: long-press scene actions were in Polish — translate menu,
banner and confirm dialogs to English. Thumb 'error' state (e.g. expired sxyprn
thumbnail 404) now shows the same 🎬 placeholder as 'empty' instead of a ⚠ broken
glyph (bug 2026-06-10).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 10:11:10 +02:00
goon-foss
06c6dfbf24 feat(mobile): tile long-press actions (hide / mark-duplicate), drop dead preview
bug-report 5a6844db: the hold-to-preview animated gesture did nothing useful.
Replace it with a long-press action menu on scene tiles:
  - Ukryj scenę → POST /scenes/{id}/hide
  - Oznacz jako duplikat → enter selection mode; tapping another tile merges the
    long-pressed scene INTO the tapped one (POST /scenes/{keep}/merge/{drop}).
SceneActionsProvider holds the selection state + a bottom banner, so it works across
all 5 scene-list screens via the shared SceneTile (no per-screen wiring). Selecting
mode highlights tappable tiles and badges the pending duplicate. Animated thumbnails
kept only as a still-fallback image; has_animated_thumbnail filter removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 09:52:15 +02:00
goon-foss
77b4916083 mobile: skeleton grid while scene lists load (perceived perf)
Scene-list screens showed a small spinner while waiting on the API, so a slow
list read felt like a blank stall. Replace the initial-load spinner on
ScenesScreen and TagScenesScreen with a SceneGridSkeleton — a 2-col grid of
pulsing placeholder tiles laid out 1:1 with SceneTile (16:9 thumb + title + meta
lines). It paints instantly with zero data, so the screen feels responsive even
when the query takes a moment, and the skeleton->content swap doesn't reflow.

Pairs with the backend list-count fix (most filtered lists are now ~0.1s); the
skeleton also masks the residual slow path (enormous tags) so it no longer reads
as a freeze.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 12:03:33 +02:00
goon-foss
eead9f159c i18n(mobile): polish UI strings → English
Tłumaczenie wszystkich user-facing stringów PL→EN (bug-report 2026-05-31
"dalej wszystko po polsku"). Alerty, przyciski, placeholdery, labelki w 12
ekranach/komponentach: BugReportFAB, AppLock(Screen/Settings/PinEntry),
applock biometric prompts, doodstream error msgs, MovieDetail, PlaybackQuality,
Player, SceneDetail, ScenesFilter, SiteScenes. Komentarze w kodzie zostają PL.

Zmiany były WIP drugiego okna (uncommitted); wjechały do bundla 0.2.1 przy
buildzie (były w working tree) — apka zainstalowana już ma EN. Ten commit
utrwala je w gicie żeby nie zginęły. Czysto stringi, zero zmian logiki.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 16:27:55 +02:00
goon-foss
9acf2f8ea1 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>
2026-05-31 12:51:32 +02:00
goon-foss
74e21caca2 fix(ota+mobile): strip expo-font from bundle, runtime back to 1.0
DIAGNOZA NA EMULATORZE (emulator-5554, goon-v0.1.9.apk):
Dwa błędne założenia z poprzednich sesji obalone empirycznie:

1. RUNTIME: APK ma EXPO_RUNTIME_VERSION="1.0" (NIE 0.1.9 — pomyliłem versionName
   z runtime). App akceptuje TYLKO manifest runtime 1.0. Mój wcześniejszy
   "fix" na 0.1.9 (211aaaa) był wstecz — app go ignorował. Cofnięte: app.json
   + publish_update RUNTIME_DEFAULT z powrotem na "1.0".

2. CRASH: prawdziwa przyczyna "nic się nie pojawia" — OTA bundle z expo-font
   crashował: "Cannot find native module 'ExpoFontLoader'" → expo-updates
   ErrorRecovery rollback. APK (build 22-maja) nie ma natywnego ExpoFontLoader
   (expo-font dodany 30-maja, PO buildzie APK). OTA NIE MOŻE dostarczyć native
   modułu. Potwierdzone: embedded bundle + served bundle grep = 0 ExpoFontLoader;
   stary font-bundle crashował, font-stripped NIE.

FIX: usunięto useFonts z App.tsx + expo-font import; theme.fonts → undefined
(system font); SceneTile/MoviePosterCard/navigation/GoonWordmark fontFamily →
fontWeight. Wszystko inne (2-col grid, oxblood, logo SVG-RNSVG-jest-w-APK)
zostaje. Custom fonty wrócą przy rebuildzie APK z expo-font (option B).

ZWERYFIKOWANE: bundle d5b87e5c (runtime 1.0, 0 ttf) — emulator launch:
`ReactNativeJS: Running "main"`, zero JS errors, brak ExpoFontLoader crash.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 11:41:29 +02:00
goon-foss
8d272acf64 feat(brand): oo logo — app icons, landing, in-app mark (Gemini-generated)
Wybrane logo: interlocked double-o "oo" (off-white ringi + oxblood doty na warm
charcoal). Wygenerowane przez Gemini 3 Pro Image (Nano Banana), wybrane z 8
wariantow przez Jana.

Native icons (wejda przy nast. APK buildzie, nie OTA):
- assets/icon.png, adaptive-icon.png, splash.png, favicon.png — zlozone z mastera
  przez PIL (mark wyciety po alpha-masce, osadzony na dokladnym #15110D, rozne
  fill-ratio per asset).
- app.json: adaptiveIcon + splash backgroundColor #0E1018 (stary navy) -> #15110D.

In-app (OTA):
- GoonMark SVG przerobiony z pojedynczego ring+dot na double-o (2 ringi + doty),
  spojny z app-icon. Login: mark 92 + wordmark 40.

Landing goon-foss.org (osobny deploy na caddy volume):
- /logo.png + /favicon.png upload, <link rel=icon/apple-touch-icon>, hero brand
  block: dot+text -> <img logo> + dwutonowy "g[oo]n".

OTA: a81ea98c-723d-4b39-9dc0-bbe8736c104e.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 22:38:52 +02:00
goon-foss
d5f4fc3f84 feat(mobile): custom fonts (General Sans + Geist Mono) + logo rework
FONTY:
- Dodane assets/fonts/: GeneralSans Regular/Medium/Semibold (Fontshare, free
  commercial) + GeistMono Regular (Vercel OFL). Pobrane jako .ttf.
- expo-font ~13.0.4 (matchuje SDK 52). Native module jest w APK bo `expo`
  ciagnie expo-font jako bezposrednia zaleznosc -> useFonts dziala przez OTA
  bez rebuildu.
- App.tsx: useFonts() gate (blokuje render do zaladowania, .ttf z bundla <100ms)
  + globalny Text.defaultProps fontFamily=GeneralSans-Regular dla body.
- theme.ts: fonts = { body, medium, display, mono }. RN nie syntezuje weightow
  dla custom fontow, wiec 4 osobne rodziny per-weight (gotcha udokumentowany).
- Jawne fonty na high-traffic: SceneTile (title=display, meta+dur=mono),
  MoviePosterCard (j.w.), navigation (taby display/medium, header display).

LOGO:
- GoonWordmark przepisany: zamiast krzywych recznych SVG path (o-ka jako
  nachodzace elipsy, zniekształcone n) renderuje PRAWDZIWY tekst w General Sans
  Semibold. Dwutonowy twist: "g[oo]n" ze srodkowym "oo" w oxblood.
- GoonMark (monogram): czysty SVG koncentryczny ring + dot (oxblood) — motyw
  soczewki/oka. Dla app-icon/splash gdzie font niedostepny.
- Wpiety na AgeGate (wordmark 40), Login (mark 44 + wordmark 44), nav header.

OTA: c986c911-0868-44f7-9f4a-fc2a74e53095 live (23 assets, 4 fonty serwuja 200).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 22:25:26 +02:00