Przeglądaj źródła

Sessie afsluiten: 119 naar versie 2.0, AdBanner-inzicht in CLAUDE.md

TASKS.md
- nieuw blok "Versie 2.0 - na de livegang" met App Links (was 119, op
  Bob's verzoek geparkeerd) en het cachen van tab-fetches
- de Bob-tabel bevat daarmee alleen nog livegang-werk

CLAUDE.md
- nieuw: waarom FlutterFlowAdBanner bij het laden springt (placeholder
  zonder hoogte, extra lang bij showsTestAd) en hoe je dat oplost met
  een Container + responsive hoogte, inclusief de valkuil dat een
  padding binnen die Container van de bannerhoogte afgaat
- gecorrigeerd: categorie is op alle zeven flutterflowmobiel1-displays
  een lijst, niet een komma-string op services_4 t/m 7 (hermeten over
  209 records, plus 52 events op de horeca-agenda)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bob 10 godzin temu
rodzic
commit
824e118bb9
2 zmienionych plików z 103 dodań i 63 usunięć
  1. 30 7
      CLAUDE.md
  2. 73 56
      TASKS.md

+ 30 - 7
CLAUDE.md

@@ -3933,6 +3933,28 @@ Schrijven met een **niet-platte body** (geneste structs, arrays), eigen
 foutafhandeling of logica vóór/ná het verzoek → custom action. Dát is
 de echte reden dat `stadsactiviteitCreate`/`bestandUpload` bestaan.
 
+**`FlutterFlowAdBanner` "opent groot en wordt dan klein" — dat is de placeholder,
+niet AdMob.** Bevestigd 2026-09-20. `lib/flutter_flow/flutter_flow_ad_banner.dart`
+rendert vóór het laden een zwarte `Container` **zonder eigen hoogte** met een
+laadtekst erin — en die tekst is fors langer zolang `showsTestAd: true` (er komt
+een waarschuwingsalinea bij), ruwweg 150 dp op 411 dp breed. Zodra de banner binnen
+is wordt de Container exact zo hoog als de banner. Staat er een `Expanded` onder,
+dan krimpt en groeit de hele lijst mee.
+- **Fix: wrap de AdBanner in een `Container` met een vaste Height.** De layout
+  reserveert dan altijd dezelfde ruimte. Gebruik een **Responsive Value**
+  `50 / 50 / 90 / 90` — Google's anchored-adaptive-hoogtes zijn <400 dp → 32,
+  400-720 → 50, >720 → 90, dus een tablet wil echt 90.
+- ⚠️ **Tel een bestaande `Padding` mee in die hoogte.** Zit de padding *binnen* de
+  Container, dan gaat hij van de bannerhoogte af (50 − 15 = 35) en wordt de
+  advertentie onderaan afgeknepen — zonder foutmelding. Op `PUitgaanPage` is dat
+  opgelost met `65 / 65 / 105 / 105` bij een padding-top van 15.
+- **Laat "Ad Banner Dimensions" leeg** (= adaptive). Zet je width+height, dan gaat
+  de widget naar een **custom** `AdSize`, en die vult AdMob beduidend slechter dan
+  een standaard/adaptive formaat.
+- De zwarte laadtekst blijft hoger dan de Container en tekent dus buiten zijn
+  kader; dat is niet vanuit de builder te clippen. De layout beweegt niet meer, en
+  dat is wat je wilt.
+
 **Een widget die door layout-overflow buiten beeld valt is in een
 profile-build volledig STIL — geen gele overflow-streep, niets in
 `logcat`, niets in `dart analyze`. Diagnose: `get_ui_tree`, niet een
@@ -5074,13 +5096,14 @@ minder calls per scherm, niet in Views.
   `copymethartje`, `kanweg/*`) en wacht op P2-7's opruimactie.
 
 
-- **`flutterflowmobiel1` levert `categorie` NIET in één vorm: displays
-  services_1/2/3 geven een **lijst** (`["Kindvriendelijk","Theater"]`),
-  services_4/5/6/7 een **komma-string** (`"Kindvriendelijk, Theater"`).**
-  Gemeten 2026-09-06 op pagina 0 van alle zeven displays. Alles wat over
-  dit veld itereert werkt daardoor op de ene tab wel en op de andere
-  niet. Zie `TASKS.md` P1-45; de nette oplossing zit in de view, niet in
-  de app.
+- **`flutterflowmobiel1` levert `categorie` op ALLE zeven displays als lijst.**
+  Hermeten 2026-09-20 (Amsterdam, pagina 0 van elk display: 209 records, 100 %
+  `list`). Dit vervangt een oudere notitie die beweerde dat services_4 t/m 7 een
+  komma-string gaven — dat was ooit zo, is via de view opgelost (P1-45) en klopt
+  dus niet meer. Gevolg: `getJsonField(item, r'$.categorie').toList()` is op deze
+  displays veilig. Zelfde meting op `flutterflowmobiel_establishment_events`
+  (52 events over 8 zaken): ook altijd een lijst, óók bij één categorie
+  (`['Live/Concert']`).
 
 - **Firebase App Check beschermt alleen Firebase-diensten zelf
   (Firestore/Cloud Functions/Storage), niet de eigen Drupal-backend van

+ 73 - 56
TASKS.md

@@ -50,7 +50,6 @@ Google Play en één doorloop die alleen Bob kan doen.
 | **120** | 12 hardcoded kleuren aan thematokens binden | Alle 12 zijn exact gelijk aan een bestaand token, dus nu onzichtbaar — maar ze lopen niet mee bij een themawijziging. Eigen blok hieronder |
 | ~~117~~ | ~~Kalenderpermissie eruit~~ | ✅ **AF** (Bob 2026-09-20, export-geverifieerd): `READ_CALENDAR`/`WRITE_CALENDAR` én `NSCalendarsUsageDescription` zijn weg; `CAMERA` staat er nog (terecht) |
 | **118** | AdMob EU-consentbericht | ⚠️ Half: de FlutterFlow-toggle staat goed, maar het bericht moet in de **AdMob-console** gepubliceerd zijn. Eigen blok hieronder |
-| **119** | Besluit: App Links voor `https://` | Gedeelde links openen nu altijd de browser, nooit de app. Post-launch keuze |
 
 ---
 #
@@ -77,6 +76,79 @@ verse export — zie de commit van die datum.)*
 
 ---
 
+
+## 🔭 VERSIE 2.0 — na de livegang · niet agenderen vóór release
+
+*Ideeën die af zijn onderzocht maar bewust wachten. Bob 2026-09-20: eerst live,
+dan pas kijken of dit überhaupt de moeite is.*
+
+### 2.0-A · App Links: uitgaanskrant.com-links in de app openen
+
+**Bob's vraag:** "ik kan een lijstje domeinen opgeven — maar hoe weet mijn app wat
+de URL is? een evenement, een horecagelegenheid, een stadspagina?"
+
+**Antwoord: Android geeft de VOLLEDIGE URL aan de app, en de app moet die zelf
+vertalen naar een route.** Dat vertalen is het hele werk; het domeinlijstje bepaalt
+alleen *of* de app aan de beurt komt.
+
+**Daarom NIET `uitgaanskrant.com` registreren.** Twee redenen:
+1. De site-URL's zijn SEO-aliassen zonder nid en zonder type
+   (`/nl/Noord-Holland/Amsterdam/Bimhuis-Amsterdam`). De app kan daar niets mee
+   zonder Drupal om een vertaling te vragen — een extra endpoint erbij.
+2. Je zou **élke** link naar je site de app in trekken: privacybeleid,
+   registratieformulier, zoekpagina's, de hele CMS-kant. Voor alles wat de app niet
+   kent moet je dan een nette terugval bouwen.
+
+**Wel `uitgk.com`.** Dat is jouw eigen korte domein, het wordt alleen gebruikt door
+de deelknop (`event_current_widget.dart:414`) en door `zetInAgenda`
+(`zet_in_agenda.dart:42`), en het heeft één voorspelbare vorm: `/<nid>`.
+
+**Het type is met één API-call te bepalen — gemeten 2026-09-20:**
+
+| | `flutterflow_events.json?nid=` | `flutterflowmobiel_establishment_info.json?nid=` |
+|---|---|---|
+| **222338** (event) | 1 rij, mét `horecagelegenheidnid=75459` | 0 rijen |
+| **75459** (zaak) | 0 rijen | 1 rij |
+
+Dus: één call naar `flutterflow_events.json?nid=X`; komt er een rij uit, dan is het
+een event **en heb je de `horecaid` meteen te pakken** (die heeft `EventCurrent`
+als tweede parameter nodig). Nul rijen → behandel als zaak →
+`HorecagelegenheidCurrent(nid: X)`. Allebei leeg → Home.
+
+**Stadspagina's erbuiten laten.** `PUitgaanPage` wil een `plaats`-tid, en die staat
+in geen enkele URL — dat zou een derde lookup via `plaatsen.json` vergen voor
+weinig winst.
+
+**Twee routes om uit te kiezen:**
+- **A — deel-URL kort houden (`uitgk.com/222338`) + een routerpagina in de app.**
+  Mooiste links. Vergt een pagina met een pad-parameter op rootniveau (`/:nid`),
+  de API-call hierboven en een conditionele navigatie. ⚠️ **Open vraag: kan
+  FlutterFlow een routePath `/:nid` op rootniveau aan zonder te botsen met `/home`,
+  `/favorieten` enz.?** go_router matcht exacte paden eerst, dus het zou moeten
+  kunnen — maar dat is niet gemeten. Eén testpagina + een export geeft uitsluitsel.
+- **B — deel-URL wordt `uitgk.com/eventCurrent?nid=..&horecaid=..`.** Dan matcht
+  go_router het pad meteen en hoeft er in de app **niets** gebouwd te worden (het
+  custom scheme werkt al precies zo). Prijs: lange, lelijke deellinks, plus een
+  redirect-regel op uitgk.com voor wie de app niet heeft.
+
+**Bob 2026-09-20: naar 2.0.** "niet belangrijk voor de livegang, als het überhaupt
+belangrijk is." Terecht — de deelknop werkt al, hij opent alleen de website in
+plaats van de app. Pak dit pas op als blijkt dat mensen gedeelde links vaak volgen.
+
+**Volgorde-afhankelijkheid, en dus hoe dan ook na de launch:**
+`/.well-known/assetlinks.json` op uitgk.com moet de **SHA-256 van het
+Play-app-signing-certificaat** bevatten, en dat certificaat krijg je pas ná de
+eerste upload (Play Console → Setup → App integrity). Vóór die tijd is de
+verificatie niet af te maken.
+
+### 2.0-B · Tab-fetches cachen op het horeca-overzicht
+
+Elke tab-tik doet een **verse** fetch, ook als je terugkeert naar een tab die je al
+bezocht hebt; heen-en-weer klikken tussen zes tabs haalt dus zes keer opnieuw op.
+Een guard ("sla de fetch over als `alleXxx` al gevuld is") lost dat op, maar kost
+een conditie in vijf actieketens — en juist die dialoog is op deze pagina fragiel.
+Alleen doen als het in de praktijk hindert.
+
 ## 🅖 G · GOOGLE PLAY — volledige checklist · Eigenaar: Bob
 
 *Opgesteld 2026-09-19. Account aangemaakt 2026-09-18 als **Organisatie** (Digital
@@ -382,61 +454,6 @@ Dat is AdMob's standaard en prima, maar het loont om er bij G2.5/G2.6 (content
 rating + doelgroep) bewust een waarde bij te kiezen zodat de advertenties passen
 bij wat je bij Play aangeeft.
 
-### 119 · App Links — ontwerp na Bob's vraag van 2026-09-20 · Eigenaar: Bob
-
-**Bob's vraag:** "ik kan een lijstje domeinen opgeven — maar hoe weet mijn app wat
-de URL is? een evenement, een horecagelegenheid, een stadspagina?"
-
-**Antwoord: Android geeft de VOLLEDIGE URL aan de app, en de app moet die zelf
-vertalen naar een route.** Dat vertalen is het hele werk; het domeinlijstje bepaalt
-alleen *of* de app aan de beurt komt.
-
-**Daarom NIET `uitgaanskrant.com` registreren.** Twee redenen:
-1. De site-URL's zijn SEO-aliassen zonder nid en zonder type
-   (`/nl/Noord-Holland/Amsterdam/Bimhuis-Amsterdam`). De app kan daar niets mee
-   zonder Drupal om een vertaling te vragen — een extra endpoint erbij.
-2. Je zou **élke** link naar je site de app in trekken: privacybeleid,
-   registratieformulier, zoekpagina's, de hele CMS-kant. Voor alles wat de app niet
-   kent moet je dan een nette terugval bouwen.
-
-**Wel `uitgk.com`.** Dat is jouw eigen korte domein, het wordt alleen gebruikt door
-de deelknop (`event_current_widget.dart:414`) en door `zetInAgenda`
-(`zet_in_agenda.dart:42`), en het heeft één voorspelbare vorm: `/<nid>`.
-
-**Het type is met één API-call te bepalen — gemeten 2026-09-20:**
-
-| | `flutterflow_events.json?nid=` | `flutterflowmobiel_establishment_info.json?nid=` |
-|---|---|---|
-| **222338** (event) | 1 rij, mét `horecagelegenheidnid=75459` | 0 rijen |
-| **75459** (zaak) | 0 rijen | 1 rij |
-
-Dus: één call naar `flutterflow_events.json?nid=X`; komt er een rij uit, dan is het
-een event **en heb je de `horecaid` meteen te pakken** (die heeft `EventCurrent`
-als tweede parameter nodig). Nul rijen → behandel als zaak →
-`HorecagelegenheidCurrent(nid: X)`. Allebei leeg → Home.
-
-**Stadspagina's erbuiten laten.** `PUitgaanPage` wil een `plaats`-tid, en die staat
-in geen enkele URL — dat zou een derde lookup via `plaatsen.json` vergen voor
-weinig winst.
-
-**Twee routes om uit te kiezen:**
-- **A — deel-URL kort houden (`uitgk.com/222338`) + een routerpagina in de app.**
-  Mooiste links. Vergt een pagina met een pad-parameter op rootniveau (`/:nid`),
-  de API-call hierboven en een conditionele navigatie. ⚠️ **Open vraag: kan
-  FlutterFlow een routePath `/:nid` op rootniveau aan zonder te botsen met `/home`,
-  `/favorieten` enz.?** go_router matcht exacte paden eerst, dus het zou moeten
-  kunnen — maar dat is niet gemeten. Eén testpagina + een export geeft uitsluitsel.
-- **B — deel-URL wordt `uitgk.com/eventCurrent?nid=..&horecaid=..`.** Dan matcht
-  go_router het pad meteen en hoeft er in de app **niets** gebouwd te worden (het
-  custom scheme werkt al precies zo). Prijs: lange, lelijke deellinks, plus een
-  redirect-regel op uitgk.com voor wie de app niet heeft.
-
-**Volgorde-afhankelijkheid, hierom is dit hoe dan ook post-launch:**
-`/.well-known/assetlinks.json` op uitgk.com moet de **SHA-256 van het
-Play-app-signing-certificaat** bevatten, en dat certificaat krijg je pas ná de
-eerste upload (Play Console → Setup → App integrity). Vóór die tijd is de
-verificatie niet af te maken.
-
 ### 65 · Release-build — wat er NOG getest moet worden · Eigenaar: Bob
 
 **De uitgelogde doorloop is af** (2026-09-19, `--release`, `flags=0x0`): 0 FATAL,