|
|
@@ -44,10 +44,10 @@ Google Play en één doorloop die alleen Bob kan doen.
|
|
|
| **P1-17** | Vertalingen | ✅ **Rond voor de app** (2026-09-20): 0 van de 218 gerenderde sleutels mist nog Engels. Alleen de vier lege-lijst-teksten op `mijnProfiel` blijven over — dat zijn parameterwaarden, geen i18n-sleutels |
|
|
|
| **Drupal** | taak 56-restant · taak 28/109 | Cron-description op "xx days" ✅ gedaan · events zonder categorie gaat via de importer |
|
|
|
| **Bij livegang** | Schakelaars en opruimklussen | Eigen blok hieronder |
|
|
|
-| **115** | AdBanner verplaatsen op `PUitgaanPage` | Onder de slider, bóven zoekveld/datum/chips. Eigen blok hieronder |
|
|
|
-| **116** | AdBanner springt bij het laden | Oorzaak gevonden in de gegenereerde widget; fix is een vaste hoogte. Eigen blok hieronder |
|
|
|
-| **117** | Kalenderpermissie eruit | De app heeft 'm niet nodig; scheelt een permissie in de Play-listing. Eigen blok hieronder |
|
|
|
-| **118** | AdMob EU-consentbericht | De app roept UMP al aan, maar het bericht moet in de AdMob-console gepubliceerd zijn. Eigen blok hieronder |
|
|
|
+| ~~115~~ | ~~AdBanner verplaatsen~~ | ✅ **AF** (Bob 2026-09-20, export-geverifieerd): volgorde is nu slider → banner → filterbalk → lijst |
|
|
|
+| **116** | AdBanner springt bij het laden | ✅ Container + responsive hoogte staat goed. ⚠️ Eén restpunt: de oude `Padding(top 15)` zit nú **binnen** die Container en eet 15 van de 50 dp |
|
|
|
+| ~~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 |
|
|
|
|
|
|
---
|
|
|
@@ -251,88 +251,45 @@ bij inschrijving.
|
|
|
**Route wanneer het zover is:** FlutterFlow kan ook voor iOS bouwen, dus een Mac
|
|
|
is niet strikt nodig. Punt 5 en 6 zijn het echte werk; de rest is administratie.
|
|
|
|
|
|
-### 115 · AdBanner verplaatsen op `PUitgaanPage` · Eigenaar: Bob
|
|
|
-
|
|
|
-**Wens (Bob 2026-09-20):** de banner onder de slider en **boven** het zoekveld,
|
|
|
-de datumkiezer en de choicechips.
|
|
|
-
|
|
|
-**Stand nu** (verse export 2026-09-20, `lib/uitgaanspaginas/p_uitgaan_page/p_uitgaan_page_widget.dart:164-230`),
|
|
|
-body-`Column` met vier kinderen:
|
|
|
-
|
|
|
-1. `PUitgaanSliderComponent` — Visibility `!FFAppState().zoekOpen`
|
|
|
-2. `Expanded > FilterBalkComponent` — zoekveld, datum, chips
|
|
|
-3. `Padding(top 15) > FlutterFlowAdBanner` ← moet naar plek 2
|
|
|
-4. `Expanded > Padding > Container > PUitgaantabelKaartComponent`
|
|
|
-
|
|
|
-**Route: twee sleepacties.** Een drop op een container-rij landt altijd op
|
|
|
-**positie 0**, dus in omgekeerde volgorde slepen:
|
|
|
-
|
|
|
-1. Klap alle vier de kinderen in (chevrons), selecteer de body-`Column`-rij één
|
|
|
- keer en druk `Escape` — een sleep landt alleen als de doelrij vooraf
|
|
|
- geselecteerd is.
|
|
|
-2. Sleep de **`Padding`-rij met de AdBanner** op de **`Column`-rij**
|
|
|
- → `[banner, slider, filterbalk, lijst]`.
|
|
|
-3. Sleep de **slider-rij** op de **`Column`-rij**
|
|
|
- → `[slider, banner, filterbalk, lijst]` ✅
|
|
|
-
|
|
|
-Eén sleep per keer, met een verse `zoom` op de boom ertussen (de rijen
|
|
|
-verschuiven). De Visibility-conditie op de slider overleeft een sleep.
|
|
|
-
|
|
|
-**Let op:** de twee horeca-overzichtspagina's hebben hun banner **onderaan** de
|
|
|
-Column staan. Die is niet meeverplaatst — apart besluit als je ze gelijk wilt
|
|
|
-trekken.
|
|
|
-
|
|
|
-### 116 · AdBanner "opent groot en wordt dan klein" · Eigenaar: Bob
|
|
|
-
|
|
|
-**Geen AdMob-kwestie — het zit in `lib/flutter_flow/flutter_flow_ad_banner.dart`
|
|
|
-(gegenereerd, dus niet lokaal te repareren).** Vóór het laden rendert die widget
|
|
|
-een zwarte `Container` **zonder eigen hoogte** met een laadtekst erin; die tekst
|
|
|
-is extra lang zolang `showsTestAd: true` (er komt een waarschuwingsalinea bij).
|
|
|
-Op 411 dp is dat ruwweg 150 dp hoog. Zodra de banner binnen is wordt de Container
|
|
|
-exact zo hoog als de banner (~50 dp). Vandaar de sprong — en de `Expanded`-blokken
|
|
|
-eromheen krimpen en groeien mee, dus de hele lijst verspringt.
|
|
|
-
|
|
|
-Twee dingen volgen daaruit: het wordt **vanzelf minder** zodra *Show Test Ads*
|
|
|
-uit gaat (kortere laadtekst), en het verdwijnt **niet** vanzelf — bij een
|
|
|
-uitblijvende fill blijft die placeholder gewoon staan.
|
|
|
-
|
|
|
-**Fix: geef de banner een gereserveerde hoogte.**
|
|
|
-- Rechtsklik de AdBanner → **Wrap Widget → Container**, geen Fill Color.
|
|
|
-- Op die Container **Height** als **Responsive Value**: `50 / 50 / 90 / 90`.
|
|
|
- Dat volgt Google's anchored-adaptive-hoogtes (<400 dp → 32, 400-720 → 50,
|
|
|
- >720 → 90); op een tablet wil de banner dus echt 90.
|
|
|
-- **Ad Banner Dimensions leeg laten** (= adaptive). Dat is bewust anders dan de
|
|
|
- twee horeca-pagina's, die `width: schermbreedte, height: 50` hebben staan: dat
|
|
|
- is een *custom* AdSize en die vult AdMob beduidend slechter dan een
|
|
|
- standaard/adaptive formaat. Nameten zodra er echte advertenties draaien.
|
|
|
-
|
|
|
-**Terugvaloptie als de Responsive-Value-dialoog tegenwerkt:** vaste Height 50 en
|
|
|
-accepteren dat de tabletbanner 40 dp krapper staat dan hij wil.
|
|
|
-
|
|
|
-### 117 · Kalenderpermissie uit het manifest · Eigenaar: Bob
|
|
|
-
|
|
|
-**De app vraagt `READ_CALENDAR` en `WRITE_CALENDAR` aan zonder ze te gebruiken.**
|
|
|
-Nagemeten 2026-09-20:
|
|
|
-- `zet_in_agenda.dart:51` gebruikt `Add2Calendar.addEvent2Cal(...)`. Dat is de
|
|
|
- **intent**-route (`ACTION_INSERT`) en die vraagt het toestel om de agenda-app te
|
|
|
- openen — daar is geen enkele permissie voor nodig.
|
|
|
-- De plugin declareert ze zélf niet: `~/.pub-cache/.../add_2_calendar-3.0.1/android/
|
|
|
- src/main/AndroidManifest.xml` is een **leeg** manifest.
|
|
|
-- Ze komen dus uit **App Settings → Permissions** (aangezet bij taak 98) en staan
|
|
|
- in de export op `android/app/src/main/AndroidManifest.xml:8-9`.
|
|
|
-
|
|
|
-**Waarom het uitmaakt:** Play toont "Agenda" bij de app-permissies, en dat is een
|
|
|
-van de dingen waar mensen op afhaken bij een uitgaansapp. Bovendien scheelt het een
|
|
|
-rij in het Data safety-formulier (G2.7).
|
|
|
-
|
|
|
-**Doen:** App Settings → Permissions → **Calendar uit** → verse export → de twee
|
|
|
-regels moeten uit het manifest zijn → daarna de agendaknop op `EventCurrent` één
|
|
|
-keer testen op een echt toestel (de AVD's kunnen dit niet, hun AOSP-kalender is
|
|
|
-kapot — zie `CLAUDE.md`).
|
|
|
-
|
|
|
-⚠️ **Bij de iOS-ronde terugzetten.** Op iOS gebruikt `add_2_calendar` EventKit en
|
|
|
-daar is de permissie + `NSCalendarsUsageDescription` wél nodig. Nu Android-only is
|
|
|
-dat geen bezwaar.
|
|
|
+### ~~115~~ · ✅ AdBanner verplaatst — AF (2026-09-20)
|
|
|
+
|
|
|
+Verse export bevestigt de body-`Column` van `PUitgaanPage`:
|
|
|
+`[slider (if !zoekOpen), Container > AdBanner, Expanded > FilterBalkComponent,
|
|
|
+Expanded > lijst]`. Precies de gevraagde volgorde.
|
|
|
+
|
|
|
+### 116 · AdBanner-hoogte — ⚠️ één restpunt · Eigenaar: Bob
|
|
|
+
|
|
|
+**Gedaan en geverifieerd:** de `Container` staat er met `height` als Responsive
|
|
|
+Value `50 / 50 / 90 / 90`, en de AdBanner heeft **geen** eigen width/height meer
|
|
|
+(dus adaptive, zoals bedoeld). De layout springt hiermee niet meer.
|
|
|
+
|
|
|
+⚠️ **Restpunt dat ik over het hoofd zag toen ik het recept gaf:** de oude
|
|
|
+`Padding(top: 15)` die om de banner zat, zit nu **binnen** die nieuwe Container.
|
|
|
+De Container geeft 50 dp, de padding pakt daar 15 van af, dus de banner houdt er
|
|
|
+**35** over terwijl hij er 50 wil. Constraints winnen van een gewenste hoogte, dus
|
|
|
+de advertentie wordt aan de onderkant afgeknepen — zonder foutmelding, en met test
|
|
|
+ads makkelijk over het hoofd te zien.
|
|
|
+
|
|
|
+**Kies er één:**
|
|
|
+- **Padding op 0** (de banner staat nu toch al los onder de slider), of
|
|
|
+- **hoogte op `65 / 65 / 105 / 105`** als je die 15 dp witruimte erboven wilt houden.
|
|
|
+
|
|
|
+🔸 Los daarvan blijft de zwarte laadtekst van `FlutterFlowAdBanner` hoger dan de
|
|
|
+Container en tekent dus even buiten zijn kader. Dat is inherent aan de gegenereerde
|
|
|
+widget en niet vanuit de builder te clippen; met test ads laadt hij snel genoeg om
|
|
|
+het niet te merken. De layout zelf beweegt niet meer, en dat was het doel.
|
|
|
+
|
|
|
+### ~~117~~ · ✅ Kalenderpermissie eruit — AF (2026-09-20)
|
|
|
+
|
|
|
+Bob heeft Calendar uitgezet in App Settings → Permissions. Verse export bevestigt:
|
|
|
+`android/app/src/main/AndroidManifest.xml` heeft nog **vier** permissies
|
|
|
+(`INTERNET`, `CAMERA`, `READ_EXTERNAL_STORAGE`, `WRITE_EXTERNAL_STORAGE`) en
|
|
|
+`ios/Runner/Info.plist` nog **twee** usage descriptions (Camera, PhotoLibrary).
|
|
|
+`READ_CALENDAR`/`WRITE_CALENDAR` en `NSCalendarsUsageDescription` zijn weg.
|
|
|
+
|
|
|
+Rest: **de agendaknop op `EventCurrent` één keer testen op een echt toestel**
|
|
|
+(de AVD's kunnen dit niet). En bij een latere iOS-ronde de permissie terugzetten —
|
|
|
+daar gebruikt `add_2_calendar` wél EventKit.
|
|
|
|
|
|
### 118 · AdMob: is het EU-consentbericht gepubliceerd? · Eigenaar: Bob
|
|
|
|
|
|
@@ -349,20 +306,72 @@ advertenties (lagere opbrengst), en Google kan de serving beperken.
|
|
|
voor de app en op **Gepubliceerd** zetten. Daarna bij de eerste release-test
|
|
|
controleren dat het scherm ook echt verschijnt bij een verse installatie.
|
|
|
|
|
|
-### 119 · Besluit: App Links voor `https://uitgaanskrant.com` · Eigenaar: Bob
|
|
|
+⚠️ **Niet te verwarren met de FlutterFlow-toggle.** Bob liet 2026-09-20 zien dat
|
|
|
+*App Settings → AdMob → "Show GDPR Consent Dialog at App Launch"* aan staat — dat
|
|
|
+is de **app**-kant en die was al goed (die toggle genereert juist de
|
|
|
+`adMobRequestConsent()`-aanroep in `main.dart`). De ontbrekende helft zit op
|
|
|
+**admob.google.com**, niet in FlutterFlow. Zonder gepubliceerd bericht vraagt de
|
|
|
+app netjes om een formulier, krijgt er geen, en gaat stil verder.
|
|
|
+
|
|
|
+🔸 Terzijde uit diezelfde screenshot: *Ad content filtering* staat op **Unset**.
|
|
|
+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
|
|
|
|
|
|
-Het manifest heeft één intent-filter, op het **custom scheme**
|
|
|
-`uitgaanskrant://uitgaanskrant.com` (`AndroidManifest.xml:47-52`). Er is géén
|
|
|
-filter voor `https://`. Gevolg: een uitgaanskrant.com-link die iemand in WhatsApp
|
|
|
-of een mail aantikt opent **altijd de browser**, nooit de app — ook de link die de
|
|
|
-deelknop zelf verstuurt (`https://uitgk.com/<nid>`).
|
|
|
+**Bob's vraag:** "ik kan een lijstje domeinen opgeven — maar hoe weet mijn app wat
|
|
|
+de URL is? een evenement, een horecagelegenheid, een stadspagina?"
|
|
|
|
|
|
-Dat is nu geen fout, maar wel een gemiste kans zodra de app live staat. Het vergt
|
|
|
-een `assetlinks.json` op de domeinen plus een tweede intent-filter, en dus een
|
|
|
-bewust besluit. **Post-launch, geen blokker.**
|
|
|
+**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.
|
|
|
|
|
|
-(Terzijde: `android:autoVerify="true"` staat nu op het custom-scheme-filter en doet
|
|
|
-daar niets — autoVerify geldt alleen voor http/https. Onschadelijk.)
|
|
|
+**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
|
|
|
|
|
|
@@ -648,6 +657,63 @@ werkelijkheid gewoon events van vandaag waren die al begonnen waren — precies
|
|
|
het `>= -2 uur`-filter hoort weg te laten. Staat ook al in `CLAUDE.md`; ik trapte
|
|
|
er alsnog in.
|
|
|
|
|
|
+### Taak 115 · Autofill: wachtwoordmanager op de loginpagina · Eigenaar: Claude (Bob plant een losse sessie)
|
|
|
+
|
|
|
+**Doel:** de gebruiker zijn inloggegevens door Android/iOS laten opslaan en
|
|
|
+invullen, zodat opnieuw inloggen twee tikken kost. De app slaat bewust géén
|
|
|
+wachtwoord op — dat blijft bij het besturingssysteem.
|
|
|
+
|
|
|
+**Context:** sessies zijn sinds 2026-09-20 een jaar geldig (zie `CLAUDE.md`),
|
|
|
+dus dit is comfort, geen noodzaak. Los oppakken, niet meeliften op ander werk.
|
|
|
+
|
|
|
+**Stap 1 — invullen (FlutterFlow-property, laag risico).**
|
|
|
+Pagina `login`, beide `TextFormField`s:
|
|
|
+
|
|
|
+| veld | herkenbaar aan | Auto Fill Hint |
|
|
|
+|---|---|---|
|
|
|
+| gebruikersnaam | `obscureText: false`, regel ~227 in de export | `username` |
|
|
|
+| wachtwoord | `obscureText: !_model.passwordFieldVisibility`, regel ~402 | `password` |
|
|
|
+
|
|
|
+Zit in **Properties Panel → Additional Properties → Auto Fill Hint** (toggle
|
|
|
+aan, dan de optie kiezen). Kies `username` en **niet** `email`: Drupal 7's
|
|
|
+`user/login` accepteert standaard alleen de gebruikersnaam.
|
|
|
+
|
|
|
+**Stap 2 — opslaan aanbieden (custom action, hier zit het risico).**
|
|
|
+Alleen hints is niet genoeg: het OS vraagt pas "wachtwoord opslaan?" na
|
|
|
+`TextInput.finishAutofillContext()`. FlutterFlow genereert die aanroep niet en
|
|
|
+documenteert hem niet. Nieuwe custom action `autofillAfronden`, zonder
|
|
|
+argumenten, aan te hangen **ná** een geslaagde `drupalLogin`:
|
|
|
+
|
|
|
+```dart
|
|
|
+import 'package:flutter/services.dart';
|
|
|
+
|
|
|
+Future autofillAfronden() async {
|
|
|
+ TextInput.finishAutofillContext();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**Open vraag:** werkt dit zonder een `AutofillGroup` om beide velden heen?
|
|
|
+FlutterFlow genereert die niet zichtbaar, en Android is daar in Flutter
|
|
|
+historisch kieskeurig in. Lukt het niet, dan is de enige route een custom widget
|
|
|
+dat het hele loginformulier vervangt — dat is een flinke ingreep en waarschijnlijk
|
|
|
+niet de moeite waard voor puur comfort.
|
|
|
+
|
|
|
+**⚠️ Testen kan NIET op de emulators.** De tablet-AVD heet
|
|
|
+`Medium_Tablet_no-google`: geen Play Services, dus geen Google Password Manager.
|
|
|
+Dit moet op Bob's fysieke Xiaomi, met een profile-build.
|
|
|
+
|
|
|
+**Terugdraaien** (per stap, beide onafhankelijk):
|
|
|
+1. *Stap 1:* Auto Fill Hint-toggle op beide velden weer uit. In een verse export
|
|
|
+ verdwijnt dan `autofillHints:` uit `lib/login/login/login_widget.dart` —
|
|
|
+ controleer met `grep -c autofillHints lib/login/login/login_widget.dart`,
|
|
|
+ hoort **0** te zijn.
|
|
|
+2. *Stap 2:* de actie loskoppelen van de loginknop (Actions-tab → ⋮ op de
|
|
|
+ actie-node → *Delete Action*) en daarna de custom action zelf weggooien.
|
|
|
+ Controle: `grep -rc finishAutofillContext lib/` hoort **0** te geven.
|
|
|
+
|
|
|
+Geen van beide stappen raakt de sessie-afhandeling, `drupalLogin` of App State,
|
|
|
+dus terugdraaien kan niet stukmaken wat nu werkt.
|
|
|
+
|
|
|
## 📚 Referentie — geen taak, wél lezen vóór je iets opnieuw onderzoekt
|
|
|
|
|
|
#
|