Просмотр исходного кода

TASKS.md: P1-7 bijgewerkt (Tab 1 laad-crash + drupalRequest-crash gefixt en geverifieerd, Tab 3 anonieme-API-call-bug gevonden, tekst-overflow + ontbrekend header/UX-login-indicator genoteerd) + nieuwe login-crash afgerond; CLAUDE.md: JDK/Gradle-snap-update-patroon, Action-Flow-Editor per-tab-actions + Copy-Action-Chain-dubbele-variabele-valkuil, drupalRequest-return-contract-wijziging

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
bob 4 недель назад
Родитель
Сommit
4a12ffd1ad
2 измененных файлов с 188 добавлено и 17 удалено
  1. 74 0
      CLAUDE.md
  2. 114 17
      TASKS.md

+ 74 - 0
CLAUDE.md

@@ -241,6 +241,26 @@ export PATH="/home/bob/fvm/bin:$HOME/.pub-cache/bin:$PATH" && /home/bob/Projects
 - **De `export PATH=...` prefix is verplicht** — Bash draait
 - **De `export PATH=...` prefix is verplicht** — Bash draait
   niet-interactief, `~/.bashrc` wordt niet geladen. Zonder prefix
   niet-interactief, `~/.bashrc` wordt niet geladen. Zonder prefix
   faalt het script stil ("fvm: command not found" — geen harde error).
   faalt het script stil ("fvm: command not found" — geen harde error).
+- **Gradle-build faalt plots met `Error resolving plugin [id:
+  'dev.flutter.flutter-plugin-loader' ...] > <versienummer>` +
+  een "restricted method"-warning erboven: check eerst welke Java
+  Flutter gebruikt, niet de code.** Bevestigd 2026-08-17: Android
+  Studio update zichzelf via snap automatisch, en de nieuwste
+  snap-revisie bundelt een steeds nieuwere JBR (ingebouwde Java) —
+  Flutter kiest bij het bouwen altijd "de JDK van de nieuwste Android
+  Studio-installatie" als eerste prioriteit. Gradle 8.12 (dit project)
+  kan niet overweg met Java 24+, en het versienummer achteraan die
+  foutmelding is precies de Java-versie van die nieuwe JBR (bv.
+  `25.0.2`) — een afgekapte/vervormde foutmelding, geen echte
+  plugin-versie-mismatch. **Vaste fix, één keer nodig, overleeft een
+  export (globale Flutter-CLI-instelling, geen projectbestand):**
+  ```
+  fvm flutter config --jdk-dir=/usr/lib/jvm/java-17-openjdk-amd64
+  ```
+  (systeem-Java 17 is stabiel, geen snap-auto-update-risico). Check bij
+  twijfel welke JDK's beschikbaar zijn met
+  `ls /snap/android-studio/*/jbr/bin/java` (elke revisie los te
+  aanroepen met `-version`) en `readlink -f /snap/android-studio/current`.
 - Interactief script (device-run + hot-restart-loop) → Bash met
 - Interactief script (device-run + hot-restart-loop) → Bash met
   `run_in_background: true`. Volg tot minimaal "All done!" én
   `run_in_background: true`. Volg tot minimaal "All done!" én
   idealiter een succesvolle app-launch (`Launching lib/main.dart...`,
   idealiter een succesvolle app-launch (`Launching lib/main.dart...`,
@@ -741,6 +761,44 @@ her-select van de node bevestigt de opgeslagen waarde.
   met een "voeg widget toe"-knop — het is gewoon de bestaande
   met een "voeg widget toe"-knop — het is gewoon de bestaande
   tab-label-node, aanklikbaar als elke andere tree-rij.
   tab-label-node, aanklikbaar als elke andere tree-rij.
 
 
+**Per-tab "On Tap"-logica van een `TabBar` (bv. data ophalen bij het
+wisselen van tab) leeft op de individuele `Tab`-node, niet op de
+`TabBar` zelf.** Gevonden 2026-08-17: de `TabBar`-node heeft zelf ook
+een Actions-tab met een "Action Flow Editor", maar díe biedt alleen
+generieke gestures (On Double Tap/On Long Press/On Tab Change) — leeg
+tenzij je het zelf instelt. De bestaande, al werkende per-tab-fetch
+zat in werkelijkheid op elke losse `Tab`-node (bv. `TabPersAgenda`) se­
+lecteren → Actions-tab → "On Tap: N actions". FlutterFlow bundelt deze
+losse per-tab-acties in de export tot één `onTap: (i) async { [...][i]() }`
+op de gegenereerde `TabBar`. **Praktisch gevolg:** zo'n per-tab-actie
+vuurt **nooit** voor de al-actieve standaardtab bij page-load (`onTap`
+reageert alleen op een echte tik) — heb je ook data nodig zodra de
+pagina opent, voeg dan **apart** een "On Page Load"-trigger toe op de
+Scaffold (zelfde als bij een gewone pagina) met dezelfde actieketen.
+- **Snelste manier om die actieketen te dupliceren: rechtsklik op de
+  eerste actie van de bestaande per-tab-flow → "Copy Action Chain" →
+  ga naar de nieuwe On-Page-Load-flow → "Paste Action(s)".** Werkt
+  betrouwbaar, maar **let op deze valkuil:** als de gekopieerde
+  actieketen een Custom Action met een "Action Output Variable Name"
+  bevat (bv. `drupalRequest`'s resultaat), plakt FlutterFlow die
+  variabele met **exact dezelfde naam** als een **nieuw, apart**
+  model-veld — dat geeft in de export een echte Dart-compile-error
+  ("`X` is already declared in this scope", 2x gedeclareerd in
+  `..._model.dart`). Build faalt dan pas bij de eerstvolgende
+  `flutter run`/`export-code`, niet zichtbaar in de builder-UI zelf
+  (geen foutmelding daar). **Fix meteen ná het plakken:** open de
+  geplakte Custom-Action-node → scroll (of klap "method"/eerste
+  argument dicht om ruimte te maken, zie de rechterpaneel-clipping-
+  notitie hieronder) naar **"Action Output Variable Name"** → geef 'm
+  een unieke naam → ga naar de vólgende actie in dezelfde geplakte
+  keten die deze variabele gebruikt (bv. een "Update Page State") →
+  klik het Value-veld → potlood-icoon → Source **"Action Outputs"** →
+  kies de net-hernoemde variabele opnieuw (de oude referentie blijft
+  anders naar de verwijderde/foutieve naam wijzen). **Altijd
+  verifiëren met een verse export + `flutter analyze`** vóór je
+  opnieuw deployt — dit patroon is 2x in dezelfde sessie misgegaan
+  voordat de fix duidelijk was.
+
 **Meerdere acties na elkaar op één trigger (bv. eerst App State
 **Meerdere acties na elkaar op één trigger (bv. eerst App State
 opruimen, dán navigeren) instellen via de "Action Flow Editor", niet
 opruimen, dán navigeren) instellen via de "Action Flow Editor", niet
 door in het compacte Actions-paneel te blijven scrollen.** Na de eerste
 door in het compacte Actions-paneel te blijven scrollen.** Na de eerste
@@ -1096,6 +1154,22 @@ exacte veldnaam+type-specificatie (kost hem seconden per veld).
   `itemCount: 0` op, niet per se de `null`-jsonBody-crash die hier de
   `itemCount: 0` op, niet per se de `null`-jsonBody-crash die hier de
   kern van het probleem was.
   kern van het probleem was.
 
 
+- **Custom action `drupalRequest` (`lib/custom_code/actions/drupal_request.dart`)
+  geeft sinds 2026-08-17 bij elke fout (non-2xx, timeout, exception)
+  een lege `[]` terug, niet meer een `{'success': false, ...}`-map.**
+  Root cause was een crash op Favorieten (zie `TASKS.md`): aanroepende
+  widget-code doet altijd blind `.toList()` op het resultaat, en
+  `.toList()` op een Map bestaat niet (`NoSuchMethodError`). Er bleek
+  nergens in de app een consument die de oude `success`/`statusCode`/
+  `body`-velden van de foutmap daadwerkelijk uitlas (gecheckt vóór de
+  wijziging), dus dit is veilig gewijzigd voor alle 3 huidige
+  gebruiksplekken (`favorieten_widget.dart` x2, `lib/kanweg/`). **Bij
+  een nieuwe aanroep van `drupalRequest` toevoegen:** ga ervan uit dat
+  je bij een fout een lege lijst terugkrijgt, geen foutdetails — wil je
+  die wél (bv. om een eigen foutmelding te tonen), dan moet de
+  functie-contract opnieuw aangepast worden en alle bestaande
+  aanroepers gecontroleerd.
+
 - **API-call `cache: true` werkt functioneel correct** — `ApiCallOptions`
 - **API-call `cache: true` werkt functioneel correct** — `ApiCallOptions`
   (`lib/backend/api_requests/api_manager.dart`) `extends Equatable` met
   (`lib/backend/api_requests/api_manager.dart`) `extends Equatable` met
   `params`/`headers` in de `props`-lijst, dus de in-memory `_apiCache`
   `params`/`headers` in de `props`-lijst, dus de in-memory `_apiCache`

+ 114 - 17
TASKS.md

@@ -1,6 +1,25 @@
 # Uitgaanskrant — takenlijst
 # Uitgaanskrant — takenlijst
 
 
-**Deze sessie (2026-08-17, zelfstandig, code-only — geen browser-tab-
+**Deze sessie (2026-08-17 avond, live pair-sessie met Bob op
+emulator-5554):** begon met een Gradle-buildfout bij Bob's eigen
+`ff-run-fvm.sh`-run — root cause: Android Studio was diezelfde dag
+automatisch geüpdatet naar een snap-revisie met **Java 25** als
+ingebouwde JBR, en Gradle 8.12 (dit project) kan daar niet mee overweg.
+Fix: `fvm flutter config --jdk-dir=/usr/lib/jvm/java-17-openjdk-amd64`
+(globale Flutter-CLI-instelling, geen projectbestand — overleeft een
+export). Zie ook `CLAUDE.md` voor het herbruikbare patroon. Daarna
+login getest en **2 nieuwe crash-bugs gevonden + gefixt** (zie de
+afgeronde blokken bij P1-18 en P1-7 hieronder) en een 3e, nog niet
+gefixte bug gevonden op Favorieten-tab 3 (zie P1-7 "Nog open").
+**Belangrijk voor de volgende sessie:** ik heb tijdens het redeployen
+zelf 2x een bouwfout veroorzaakt (dubbele variabele-declaratie na
+"Copy Action Chain") — beide keren zelf gevonden via `flutter analyze`
+vóór het Bob bereikte, maar zie de nieuwe `CLAUDE.md`-notitie over dit
+patroon vóórdat je dit trucje nog eens gebruikt.
+
+---
+
+**Vorige sessie (2026-08-17 overdag, zelfstandig, code-only — geen browser-tab-
 groep gevonden bij sessiestart, dus aangenomen dat Bob niet actief
 groep gevonden bij sessiestart, dus aangenomen dat Bob niet actief
 achter zijn scherm zat en geen builder-UI geprobeerd):** begonnen met
 achter zijn scherm zat en geen builder-UI geprobeerd):** begonnen met
 `ff-session-check.sh` (schoon) + een verse `flutterflow export-code`
 `ff-session-check.sh` (schoon) + een verse `flutterflow export-code`
@@ -600,6 +619,35 @@ Het losse debug-dialoogje (AlertDialog "melding" met de rauwe JSON) is
 blijven staan — niet meegenomen in deze fix, kan later nog opgeruimd
 blijven staan — niet meegenomen in deze fix, kan later nog opgeruimd
 worden als cosmetische bijvangst. Uit deze lijst verwijderd.)*
 worden als cosmetische bijvangst. Uit deze lijst verwijderd.)*
 
 
+*(Nieuwe, andere login-crash gevonden + afgerond 2026-08-17 avond —
+Claude, builder + live logcat-diagnose op emulator-5554. Dit was géén
+regressie van P1-18 hierboven, maar een nog niet eerder gevonden
+tweede bug op dezelfde knop: ná een geslaagde `drupalLogin`-aanroep
+haalde de knop's "Inloggen"-actie **nogmaals** en **overbodig** de
+sessievelden uit het resultaat via losse JSON-Path-bindingen
+(`$.user.uid`, `$.user.name`, `$.user.mail`) — maar `drupalLogin`
+retourneert die velden plat (`uid`/`name`/`mail`, geen `user`-object),
+dus alle drie gaven `null`. Voor de 2 String-velden onschuldig
+(`null.toString()` → tekst "null"), maar `userUid` is `int`-getypeerd
+in App State → een `null` daarin toekennen crashte de app **stil**
+(geen rode foutmelding, gewoon geen "Succesvol ingelogd!"-melding en
+geen reactie op de knop) vóórdat de succes-snackbar ooit getoond kon
+worden. **Root cause was sowieso overbodige code:** `drupalLogin`
+(`lib/custom_code/actions/drupal_login.dart`) zet deze velden al zelf
+correct en veilig in App State (met `int.tryParse(...) ?? 0` voor
+uid) vóórdat het resultaat teruggegeven wordt. **Fix:** de 6
+redundante "Update App State"-acties op de knop's on-tap-flow
+(Action Flow Editor) volledig verwijderd — de knop doet nu alleen nog
+`drupalLogin` aanroepen en op basis van `resultDrupalLogin != null`
+de juiste snackbar tonen. Bevestigd via verse export
+(`login_widget.dart` bevat de `getJsonField(..., $.user.*)`-blokken
+niet meer) en live op emulator-5554 (inloggen met gebruikersnaam geeft
+nu de "Succesvol ingelogd!"-snackbar). **Bijvangst, zelfde diagnose:**
+inloggen met e-mailadres i.p.v. gebruikersnaam geeft terecht "Inloggen
+mislukt" — Drupal's `user/login.json` accepteert kennelijk geen
+e-mailadres als username. Geen bug, maar wel een open feature-vraag
+aan Bob als e-mail-login gewenst is.)*
+
 *(P1-1 volledig afgerond 2026-08-10 avond — Bob, builder, alle 4
 *(P1-1 volledig afgerond 2026-08-10 avond — Bob, builder, alle 4
 sub-punten bevestigd via verse export: `HomeUitgaanSliderComponent`
 sub-punten bevestigd via verse export: `HomeUitgaanSliderComponent`
 (= P0-1), `PUitgaanSliderComponent`, `EvenementComponent`,
 (= P0-1), `PUitgaanSliderComponent`, `EvenementComponent`,
@@ -984,20 +1032,68 @@ lokale/UI-kant + look&feel oppakken zolang die niet op Drupal wacht.
      wijziging, geen quick win.
      wijziging, geen quick win.
   Geen van beide is deze sessie uitgevoerd (buiten scope voor
   Geen van beide is deze sessie uitgevoerd (buiten scope voor
   code-only werk, en vraagt eerst een ontwerpkeuze van Bob).
   code-only werk, en vraagt eerst een ontwerpkeuze van Bob).
-- **Tab 1 "Persoonlijke agenda"** (events in favoriete gemeente(n)) —
-  **uitgezocht (2026-08-14, Claude, code-audit): geen nieuwe Drupal-call
-  nodig, bestaande calls volstaan al.** `UitgaanstabelCall`/
-  `UitgaanSliderCall` (`api_calls.dart`) accepteren allebei al een
-  `townid`-parameter (nu gebruikt door `PUitgaantabelKaartComponent`/
-  `PUitgaanSliderComponent` voor de huidige gekozen gemeente) — exact
-  wat hier nodig is. Bouwplan: loop over `favorieteGemeenteIds` (App
-  State, al gevuld zodra Tab 2 ooit favorieten heeft) en roep
-  `UitgaanstabelCall` per gemeente-id aan, resultaten samenvoegen tot
-  1 lijst (of simpeler: hergebruik `PUitgaantabelKaartComponent` als los
-  blok per favoriete gemeente, met een kopje erboven = gemeentenaam).
-  Geen Drupal-wijziging nodig — wel afhankelijk van Tab 2's
-  favoriet-toggle-UI (zie hierboven), want zonder die blijft
-  `favorieteGemeenteIds` altijd leeg.
+- **Tab 1 "Persoonlijke agenda" — bleek al gebouwd (niet door deze
+  lijst gedekt, `TASKS.md` liep achter), en kreeg 2026-08-17 avond
+  2 bugfixes (Claude, builder, bevestigd via verse export +
+  `flutter analyze` + live op emulator-5554):**
+  1. De data-fetch (`drupalRequest` POST naar
+     `.../favorieten_agenda.json`) hing aan de `TabBar`'s `onTap`
+     op de `Tab`-node zelf (zie `CLAUDE.md`) — die vuurt alléén bij
+     een echte tik, dus **nooit** voor de al-actieve standaardtab bij
+     page-load. Fix: Scaffold's eigen **"On Page Load"**-trigger
+     toegevoegd met dezelfde actieketen (via rechtsklik op de
+     bestaande `TabPersAgenda`-Tab-node → Actions → "Copy Action
+     Chain" → nieuwe On-Page-Load-trigger → "Paste Action(s)") — let
+     op de `CLAUDE.md`-notitie over de dubbele-variabele-valkuil die
+     dit trucje veroorzaakt, dat moest ik zelf nog corrigeren.
+  2. Los daarvan crashte de pagina stil (`NoSuchMethodError: Map heeft
+     geen 'toList'`) zodra de call een niet-2xx-respons kreeg, omdat
+     de custom action `drupalRequest`
+     (`lib/custom_code/actions/drupal_request.dart`) bij een fout een
+     `{'success': false, ...}`-Map teruggaf terwijl de aanroepende
+     code altijd blind `.toList()` erop aanriep. Fix: alle 3
+     foutpaden in `drupal_request.dart` (non-2xx, timeout, exception)
+     geven nu `[]` terug i.p.v. een map — bevestigd via verse export.
+     **Live bevestigd:** `favorieten_agenda.json` geeft momenteel nog
+     een **404** terug (Bob kijkt hier zelf naar, zie boven) — de tab
+     blijft nu netjes leeg i.p.v. te crashen.
+- **Nieuw gevonden, nog niet gefixt (2026-08-17 avond, Claude,
+  code-audit): Tab 3 "Favoriete Gelegenheden" roept zijn API-call
+  altijd anoniem aan.** [favorieten_widget.dart:362](lib/favorieten/favorieten_widget.dart:362)
+  — `FavorietenAgendaCall.call()` wordt zonder argumenten aangeroepen,
+  terwijl de call zelf `sessionName`/`sessionId`-parameters verwacht
+  die in de Cookie-header horen
+  (`'{{session_name}}={{sessid}}'` in `api_calls.dart:34`). Zonder die
+  twee gaat de aanroep altijd **zonder sessie** naar Drupal → een
+  ListTile met letterlijk **"null"** als titel i.p.v. de favoriete
+  horeca-gelegenheden, ook als je wél bent ingelogd. **Fix (builder):**
+  ListView selecteren → Backend Query-icoon (database) →
+  `FavorietenAgenda`-call openklappen → `sessionName` = Set from
+  Variable → `FFAppState().userSessionname`, `sessionId` = Set from
+  Variable → `FFAppState().userSessionid`.
+- **Nieuw gevonden, cosmetisch (2026-08-17 avond): tekst-overflow op
+  Tab 2 en Tab 3's beschrijvingsregel.** De `Text`-widgets "De
+  gemeentes die je hebt gemarkeerd..." (key `o7pt2vls`,
+  [favorieten_widget.dart:332](lib/favorieten/favorieten_widget.dart:332))
+  en de vergelijkbare op Tab 3 lopen zichtbaar van het scherm af (geen
+  wrap, geen horizontale padding op de omringende `Column`).
+- **Nieuw gevonden, structureel (2026-08-17 avond): de hele
+  Favorieten-pagina mist een header/drawer.** Geen "☰"-menu, geen
+  terugknop — de pagina begint direct bij de `TabBar`, enige uitweg is
+  Android's systeem-terugknop. Bovendien zijn alle 4 tab-labels
+  afgekapt op telefoonformaat ("Persoon…", "Favoriete…" x2,
+  "Gebruike…") — de `TabBar` is te smal voor 4 volledige labels.
+  Vraagt een structurele aanpassing (Scaffold met AppBar/Drawer zoals
+  andere pagina's, of kortere tab-labels/kleiner lettertype), geen
+  quick fix.
+- **Nieuw gevonden, UX-gat (2026-08-17 avond): nergens in de app is
+  zichtbaar dát je bent ingelogd**, behalve als je zelf naar
+  Favorieten-tab 4 navigeert. De drawer's "Mijn Account"-item opent
+  altijd het kale login-formulier, ook met een actieve sessie — geen
+  check op `FFAppState().userSessionid`. Sluit aan bij Bob's eigen
+  wens (2026-08-17): gebruikersnaam + uitlog-knop + link naar
+  Favorieten zichtbaar maken zodra ingelogd, bv. in de drawer i.p.v.
+  het statische "Login"/"Mijn Account"-item.
 - **"Gebruiker"-tab, "Uitloggen"-knop afgerond (2026-08-15, Claude,
 - **"Gebruiker"-tab, "Uitloggen"-knop afgerond (2026-08-15, Claude,
   builder, bevestigd via verse export + `flutter analyze`: 0 errors).**
   builder, bevestigd via verse export + `flutter analyze`: 0 errors).**
   `favorieten_widget.dart` heeft nu een 4e tab "Gebruiker" (via TabBar's
   `favorieten_widget.dart` heeft nu een 4e tab "Gebruiker" (via TabBar's
@@ -1008,10 +1104,11 @@ lokale/UI-kant + look&feel oppakken zolang die niet op Drupal wacht.
   `userMail`), Action 2 = Navigate To Login met "Allow Back Navigation"
   `userMail`), Action 2 = Navigate To Login met "Allow Back Navigation"
   uit (genereert `context.goNamed(...)` i.p.v. `pushNamed`, dus geen
   uit (genereert `context.goNamed(...)` i.p.v. `pushNamed`, dus geen
   terugknop-pad naar de net-verlaten sessie). **Nog open, zelfde
   terugknop-pad naar de net-verlaten sessie). **Nog open, zelfde
-  tab:** "Wachtwoord wijzigen" en "Account verwijderen" (zie Bob's
+  tab:** geen gebruikersnaam zichtbaar (zie UX-gat hierboven),
+  "Wachtwoord wijzigen" en "Account verwijderen" (zie Bob's
   beslissing 3 hieronder — account verwijderen heeft mogelijk
   beslissing 3 hieronder — account verwijderen heeft mogelijk
   AVG-implicaties aan Drupal-kant en is een App-Store-vereiste, zie
   AVG-implicaties aan Drupal-kant en is een App-Store-vereiste, zie
-  daar) — deze twee zijn niet meegenomen, eigen vervolgtaak.
+  daar) — deze zijn niet meegenomen, eigen vervolgtaak.
 - **Open vraag aan Bob (blokkeert de Drupal-sync van favorieten):**
 - **Open vraag aan Bob (blokkeert de Drupal-sync van favorieten):**
   bestaat er al een Drupal-endpoint om een favoriet (horeca of gemeente)
   bestaat er al een Drupal-endpoint om een favoriet (horeca of gemeente)
   toe te voegen/verwijderen voor een ingelogde gebruiker (bv.
   toe te voegen/verwijderen voor een ingelogde gebruiker (bv.