Browse Source

Verbindingsmelding af: getest op een verse export van de echte staat

Bob's versie gebouwd en gedraaid op de telefoon-emulator (export uit
FlutterFlow, niet een nabouw). Online: geen melding, hamburger zichtbaar, 0
render-fouten. Offline: rode balk met Opnieuw, 0 render-fouten, 0 toList-crashes.
Na netwerk terug plus een tik: balk weg en Home volledig hersteld.

De 20x20 Container die FlutterFlow eist is in een Row onschadelijk - die kost
alleen horizontale ruimte.

CLAUDE.md: twee valkuilen vastgelegd. De header zit in een
FlexibleSpaceBar.background met vaste hoogte, dus een Column-wrap om de
knoppen-Row geeft niet alleen een overflow maar laat ook stil de hamburger
verdwijnen op alle elf pagina's. En de Custom Code-editor controleert eigen
imports niet: pas Gradle struikelt erover.

Resteert: het widget staat nog niet op de twee aanmaakpagina's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bob 1 day ago
parent
commit
030dd8f28e
2 changed files with 72 additions and 148 deletions
  1. 28 0
      CLAUDE.md
  2. 44 148
      TASKS.md

+ 28 - 0
CLAUDE.md

@@ -1994,6 +1994,34 @@ method`** — dat is het snelste bewijs. Reken er bij elk nieuw
 lijst-achtig veld op dat je de vorm eerst even met `curl` controleert
 vóór je erop bouwt.
 
+**De gedeelde header zit in een `FlexibleSpaceBar.background` met een VASTE
+hoogte — wrap de knoppen-Row daar nooit in een Column.** Bevestigd 2026-09-13 op
+`HeaderButtonsComponent` (staat op 11 pagina's). `Align > Row` krijgt van die
+FlexibleSpaceBar netjes ±74 px opgelegd. Zet je er een `Column` omheen, dan
+geeft die zijn kinderen **onbegrensde** hoogte op de hoofdas: de Row neemt zijn
+natuurlijke ±200 px en je krijgt `A RenderFlex overflowed by 166 pixels`.
+**Het stille deel is erger dan de melding: de hamburgerknop verdwijnt dan uit
+de header op álle pagina's, en dáár zegt de log niets over** — je ziet het
+alleen op een screenshot. Wil je iets aan de header toevoegen, doe het dan als
+kind ván de bestaande Row, en geef het geen vaste hoogte.
+- Zelfde reden: FlutterFlow zet standaard een Container met `width`/`height` om
+  een custom widget. In een **Row** is dat onschadelijk (kost alleen
+  horizontale ruimte, 20×20 werkt prima); in een **Column** binnen die 74 px
+  eet de hoogte de ruimte van de knoppen op.
+- Werkend patroon voor een melding die op elke pagina moet kunnen verschijnen:
+  een custom widget dat zelf `SizedBox.shrink()` rendert en de melding via de
+  **`ScaffoldMessenger`** toont (zie `VerbindingsBanner` in `snippets/`). Neemt
+  geen layout-ruimte in, dus het kan overal staan zonder iets te breken.
+
+**Eigen imports in Custom Code worden door de editor NIET gecontroleerd.**
+Bevestigd 2026-09-13: een custom action zonder
+`import 'package:http/http.dart' as http;` slaat gewoon op, de builder meldt
+niets en het Issues-paneel blijft schoon — pas de **Gradle-build** faalt met
+`Error: Undefined name 'http'`. Plak bij het invoeren dus alles onder de
+`// DO NOT REMOVE`-regel, inclusief de importregels die daar direct onder
+staan. (Getest: `dart:async` is niet nodig, `Future`/`timeout` komen via de
+FlutterFlow-imports; `go_router` in een custom *widget* evenmin.)
+
 **App State wijzigen laat de UI NIET vanzelf opnieuw bouwen — cruciaal zodra
 iets op meerdere schermen moet reageren.** Uitgezocht 2026-09-13 bij de
 verbindingsmelding:

+ 44 - 148
TASKS.md

@@ -1,151 +1,47 @@
 ## ▶ Nu aan de beurt (stand 2026-09-13)
 
-### 🔧 Verbindingsmelding in de header — Eigenaar: Bob — bezig (2026-09-13)
-
-⚠️ **Observatie Claude 2026-09-13 ±20:08 (verse export van 20:02, profile-build
-op de telefoon-emulator): de header is volledig LEEG — geen hamburger, geen
-logo, online én offline.** `home_widget.dart` is byte-identiek aan de
-nulmeting; alleen `header_buttons_component_widget.dart` verschilt: de oude
-`Align > Row` zit nu in een `Column(mainAxisSize: max)` met daaronder een
-`SizedBox(200×40) > VerbindingsBanner`. Vermoedelijke oorzaak: in die Column
-krijgt de Row een **onbegrensde hoogte** (Home zet het component als
-`FlexibleSpaceBar.background` in een `PreferredSize(50)`-AppBar), en met het
-200×200-logo erin gaat dat in een profile-build stil op zwart. Geen fout in
-`logcat`, `dart analyze` 0 errors — het is een layout-exceptie tijdens de
-build. Suggestie: Column op **Main Axis Size = Min**, en de Row een vaste
-hoogte geven (of het logo begrenzen); daarna even op een toestel kijken.
-Kan ook zijn dat dit een tussenstand is die je al gezien hebt.
-
-Bob's keuze 2026-09-13: niet elke pagina aanpassen, maar **één melding in de
-header**, gevoed door een App State-vlag die de app zelf zet. Claude heeft de
-custom code geschreven en live getest op emulator-5556 (eigen profile-build,
-banner tijdelijk in `home_widget.dart` geprikt); **Bob voert de builder-stappen
-zelf uit.**
-
-📄 **De code staat in de repo: `snippets/check_verbinding.dart.txt` en
-`snippets/verbindings_banner.dart.txt`** (buiten `lib/`, dus een export raakt ze
-niet aan). Zie `snippets/LEESMIJ.md`.
-
-⚠️ **Waarom dit een Custom WIDGET is en geen Text met een Visibility-conditie.**
-De widgets in dit project lezen App State via de singleton `FFAppState()`, niet
-via `context.watch`. `main.dart` zet er wel een `ChangeNotifierProvider`
-omheen, maar niemand abonneert zich. Een Visibility-conditie op een App State-
-bool zou dus pas opnieuw evalueren als er toevallig iets ánders een rebuild
-veroorzaakt — de balk verschijnt dan niet of veel te laat. Het widget luistert
-zelf via `AnimatedBuilder(animation: FFAppState())`. Om dezelfde reden zet de
-action de vlag met `FFAppState().update(...)` en niet met een kale toewijzing:
-**alleen `update()` roept `notifyListeners()` aan** (de setters in
-`app_state.dart` doen dat niet).
-
-Plak alles onder de `// DO NOT REMOVE`-regel — **inclusief de eigen importregel
-die daar direct onder staat** (er staat een `⬇ PLAK VANAF HIER ⬇`-markering).
-De FlutterFlow-importkop erbóven genereert de builder zelf.
-
-⚠️ **Valkuil, 2026-09-13 aan den lijve:** zonder
-`import 'package:http/http.dart' as http;` slaat de Custom Code-editor de action
-gewoon op en meldt de builder **niets** — maar de Gradle-build faalt met
-`Error: Undefined name 'http'`. De editor controleert eigen imports dus niet.
-Het widget heeft dit probleem niet: `go_router` komt daar ook via de
-FlutterFlow-imports binnen (getest, compileert met én zonder).
-- **Custom Action `checkVerbinding`** — één HEAD-request op de site-root.
-  Gemeten: HTTP 200, **0 bytes, 57 ms** (tegenover 34 KB / 1,3 s voor een gewone
-  data-call), dus verwaarloosbaar. Een 401/404 telt als bereikbaar; alleen 5xx,
-  timeouts en netwerkfouten zetten de vlag. Return Type **Boolean**, geen
-  argumenten.
-- **Custom Widget `VerbindingsBanner`** — parameters `width`, `height`, `tekst`
-  (alle drie optioneel; **leeg laten**). Het widget rendert zelf **niets**
-  (`SizedBox.shrink`) en toont de melding via de **`ScaffoldMessenger`** over de
-  pagina heen — daardoor kan het in de vaste-hoogte-header staan zonder iets te
-  breken. Throttlet de automatische check op **max. 1 per 20 seconden over alle
-  pagina's samen**, en herlaadt bij een geslaagde tik op "Opnieuw" de huidige
-  route zodat de data alsnog binnenkomt.
-
-**Stappen in de builder:**
-1. App Values → App State → `+ Add App State Variable`: naam **`geenVerbinding`**,
-   type **Boolean**, initial **false**, **Persisted uit**. Dit moet er zijn vóór
-   stap 2, anders kan de action niet opslaan.
-2. Custom Code → `+` → **Action** → naam `checkVerbinding` → body plakken →
-   Return Type Boolean → **Ctrl+S**.
-3. Custom Code → `+` → **Widget** → naam `VerbindingsBanner` → body plakken →
-   de drie parameters aanmaken → **Ctrl+S**.
-4. `HeaderButtonsComponent` openen en het widget **als laatste kind in de
-   bestaande `Row`** zetten (Build-tab → Elements → zoeken op
-   `VerbindingsBanner` → naar het canvas slepen). Laat `width`, `height` én
-   `tekst` **leeg**.
-5. Vier pagina's hebben géén `HeaderButtonsComponent`: `mijnProfiel`,
-   `wachtwoordVergeten`, `stadsactiviteitAanmaken`, `uitgaansevenementAanmaken`.
-   Op de twee **aanmaakpagina's** is de melding wel zinvol — daar het widget
-   ergens in de bestaande layout zetten (het neemt toch geen ruimte in).
-6. Testen: `adb -s <device> shell svc wifi disable` + `svc data disable`, app
-   herstarten, daarna weer `enable`.
-
-🛑 **Twee valkuilen die 2026-09-13 allebei toegeslagen hebben — lees dit vóór
-stap 4.**
-
-**(a) Wrap de Row NIET in een Column.** Dat was Claude's eerste instructie en hij
-is fout. De header zit in een `FlexibleSpaceBar.background` met een **vaste
-hoogte van 74 px**; `Align > Row` krijgt die 74 px netjes opgelegd. Zet je er een
-`Column` omheen, dan geeft die zijn kinderen **onbegrensde** hoogte op de
-hoofdas: de knoppen-Row neemt dan zijn natuurlijke ±200 px en je krijgt
-`A RenderFlex overflowed by 166 pixels`. **Erger nog, en dit meldt niets: de
-hamburgerknop verdwijnt dan uit de header op alle elf pagina's.** Alleen de
-overflow staat in de log; de verdwenen knop zie je pas op een screenshot.
-Omdat het widget geen ruimte inneemt, is een Column ook nergens voor nodig —
-gewoon in de bestaande Row.
-
-**(b) Laat FlutterFlow geen Container met vaste maten om het widget zetten.**
-De builder vult standaard `width: 200, height: 40` in. Die 40 px eet in een
-header van 74 px de ruimte van de knoppen op, en op 200 px breedte wrapt de
-meldingstekst naar meerdere regels. **Maak beide velden leeg.**
-
-✅ **Alle drie de paden nagemeten op de emulator met de definitieve opstelling
-(widget in de Row, geen Container):** offline → **0** render-fouten, hamburger
-gewoon zichtbaar, rode balk onderin met "Opnieuw"; netwerk terug + tik → balk
-weg en Home **volledig hersteld** (slider met kaarten, tabs gevuld), opnieuw 0
-fouten. Screenshots staan in de chat.
-
-⚠️ **Wat de banner NIET oplost:** het grijze blok op Home blijft staan, want dat
-blok ís de gecrashte widget (bevinding C hieronder). De banner maakt het alleen
-verklaarbaar in plaats van kapot. De vier crashplekken blijven dus een aparte
-taak.
-
-### ✅ Bevinding C · offline-crash op Home/P-Uitgaan-slider — AFGEROND 2026-09-13 (Claude, builder + live offline-test); restpunt tab 6 voor Bob
-
-**Wat er gedaan is (exportgeverifieerd, `dart analyze` 0 errors):**
-- Op `HomeSlider`, `UitgaanSlider` en `Horecagelegenheidoverzicht` (API Calls →
-  Response & Test) een JSON Path **`items` = `$[:]`, Is List aan** toegevoegd →
-  `static List? items(dynamic response)` in `api_calls.dart`.
-- Generate Dynamic Children van de Carousel op `HomeUitgaanSliderComponent` en
-  `PUitgaanSliderComponent` herbonden naar **Predefined Path → items**. De
-  export genereert nu `(XCall.items(jsonBody)?.toList() ?? []).take(12)` in
-  plaats van `getJsonField(jsonBody, r'$').toList()` — null-veilig bij een
-  mislukte call (`jsonBody == null`), bij een foutpagina-object én bij `[]`.
-  Bij een fout toont de slider gewoon zijn bestaande lege-lijst-afbeelding en
-  blijven de tabs eronder staan; Bob's verbindingsbanner erboven zegt waarom.
-
-**Terugdraaien bij calamiteit (per component één dialoog):** Carousel
-selecteren → Generate Dynamic Children (4e icoontje) → klik op de Value-tekst
-(niet het potlood) → dialoog: Available Options **"JSON Path"** → JSON Path
-**`$`** → tweede Available Options **"No Further Changes"** → Confirm → Save
-in het rechterpaneel. Dat is exact de oude binding. Nulmeting-export van vóór
-alle wijzigingen: `/tmp/ff-checkN0`. De drie `items`-paths mogen blijven
-staan; ongebruikt doen ze niets.
-
-**Live getest op de telefoon-emulator (profile-build van de verse export,
-`svc wifi/data disable`):** geen `NoSuchMethodError` meer in de log; de slider
-toont offline het logo (lege-lijst-fallback) en de tabs eronder blijven staan
-met hún lege-staat-logo. Online: slider met kaarten, tabs gevuld, log schoon.
-⚠️ Let op bij een eigen test: een `export-code` zónder `--include-assets` mist
-`logo800px.png`, en dan zie je alsnog een grijs blok dat níét van deze bug is
-(zie `CLAUDE.md`).
-
-**Nog open, voor Bob:** `horecagelegenhedenOverzichtCurrent` tab 6 (Verhuur,
-catering), `StaggeredView` → Generate Dynamic Children → zelfde herbinding
-naar **Predefined Path → items** (de path staat al op de call). Dat paneel
-schrijft in Claude's browser op die pagina niet weg. De zes treffers op
-`horecagelegenhedenOverzichtProvinciePage` en die op
-`SliderUitgaanComponentSmallCurrent` blijven bewust liggen: geen enkele knop
-navigeert daarheen / nul gebruikers.
+### ✅ Verbindingsmelding in de header — AF (2026-09-13, Bob + Claude)
+
+Gebouwd en live geverifieerd op de telefoon-emulator met een **verse export van
+de echte FlutterFlow-staat** (dus niet een nabouw). Alle drie de paden:
+
+| situatie | resultaat |
+|---|---|
+| online | geen melding, hamburger zichtbaar, **0** render-fouten |
+| offline | rode balk onderin met wolkje + "Opnieuw", **0** render-fouten, **0** `toList`-crashes |
+| netwerk terug + tik op "Opnieuw" | balk weg, Home **volledig hersteld** (slider + tabs gevuld), 0 fouten |
+
+**Hoe het in elkaar zit**, voor als het ooit aangepast moet worden:
+- App State **`geenVerbinding`** (Boolean, niet persisted).
+- Custom Action **`checkVerbinding`** — HEAD op de site-root (200, 0 bytes,
+  ±57 ms), zet de vlag via `FFAppState().update(...)`.
+- Custom Widget **`VerbindingsBanner`** — rendert zelf `SizedBox.shrink()` en
+  toont de melding via de `ScaffoldMessenger`. Staat als laatste kind in de
+  `Row` van `HeaderButtonsComponent`, in een Container van 20×20 (FlutterFlow
+  eist maten; in een Row kost dat alleen 20 px horizontaal en dat is
+  onschadelijk — **in een Column zou een hoogte wél schadelijk zijn**).
+- De code staat in `snippets/` en overleeft daar een export.
+
+⚠️ **Twee valkuilen die hier zijn opgetreden — relevant zodra er nóg iets aan
+de header toegevoegd wordt:**
+1. **Wrap de knoppen-Row NOOIT in een Column.** De header zit in een
+   `FlexibleSpaceBar.background` met een **vaste hoogte van 74 px**;
+   `Align > Row` krijgt die keurig opgelegd, maar een `Column` geeft zijn
+   kinderen **onbegrensde** hoogte — de Row neemt dan zijn natuurlijke ±200 px
+   en je krijgt `RenderFlex overflowed by 166 pixels`. **En stiller maar erger:
+   de hamburgerknop verdwijnt dan uit de header op alle elf pagina's, zonder
+   enige melding in de log.**
+2. **Eigen imports in Custom Code worden niet gecontroleerd door de editor.**
+   `checkVerbinding` heeft `import 'package:http/http.dart' as http;` nodig,
+   direct onder de `// DO NOT REMOVE`-regel. Zonder die regel slaat de editor
+   gewoon op en meldt niets — pas de Gradle-build faalt met
+   `Error: Undefined name 'http'`.
+
+📌 **Nog niet gedaan:** het widget staat alleen in `HeaderButtonsComponent`, dus
+niet op `mijnProfiel`, `wachtwoordVergeten`, `stadsactiviteitAanmaken` en
+`uitgaansevenementAanmaken`. Op de twee **aanmaakpagina's** is het wel zinvol
+(een formulier verzenden zonder netwerk) — daar het widget ergens in de
+bestaande layout zetten, het neemt toch geen ruimte in.
 
 ### 🐞 Nieuw gevonden 2026-09-13 (Claude, code-audit op verse export)
 
@@ -4755,7 +4651,7 @@ en `/node/217916` redirect naar
 `/nl/Noord-Holland/Enkhuizen/Café-de-Vriendschap/2026/TEST-app-Claude-13sep-niet-echt`.
 **Testnode 217916 mag weg (Bob).**
 
-⚠️ **Bevinding 1 — tijd verschuift 2 uur (Drupal-kant, Bob).** De app stuurde
+⚠️ **Bevinding 1 — tijd verschuift 2 uur (Drupal-kant, Bob). Kant-en-klare patch: `snippets/drupal-datum-tijdzone.md`.** De app stuurde
 `"datum_start":"2026-09-25 20:20:00"` (lokale tijd, zie logcat), maar de views
 én de publieke pagina tonen **22:20**. Drupal leest de string dus als UTC en
 rendert in Europe/Amsterdam (+2 in de zomer). Fix in
@@ -4765,7 +4661,7 @@ DateTimeZone('Europe/Amsterdam'))` → naar UTC), of afspreken dat de app UTC
 stuurt. Drupal-kant is netter: dan blijven oudere/andere clients ook goed.
 Geldt vermoedelijk ook voor `stadsactiviteiten/create`.
 
-**Bevinding 2 — cosmetisch (builder, Claude kan dit):** het Datum-veld toont
+**Bevinding 2 — cosmetisch (builder) — Claude bezig 2026-09-13 ±20:45:** het Datum-veld toont
 na kiezen de rauwe `2026-09-25 20:20:00.000`. De Text-binding van dat veld
 door een `dateTimeFormat` halen (bv. `d MMM yyyy, HH:mm`) — alleen de weergave,
 `datumVoorApi` blijft de bron voor het verzenden.