Explorar el Código

Sessie afgesloten: inzichten naar CLAUDE.md, code naar snippets/

CLAUDE.md:
- De "paneel schrijft niets weg"-notitie genuanceerd: dat is Claude-specifiek,
  niet iets in de paginadata. Bob zette op diezelfde pagina Max Items van 25
  naar 1000 en dat kwam gewoon door. Vuistregel: overdragen, niet concluderen
  dat het onmogelijk is.
- App State en rebuilds vastgelegd: setters roepen geen notifyListeners aan
  (alleen update() doet dat) en widgets lezen via de singleton, niet via
  context.watch. Een Visibility-conditie werkt daarom niet voor een widget op
  een ander scherm; een custom widget met AnimatedBuilder wel.
- Recept om offline-gedrag te testen op een emulator, inclusief het herstel.
- Een APK bouwen uit een losse exportmap vereist setsid, anders sterft Gradle
  met de achtergrond-call mee.
- Bob's besluit vastgelegd: geen favorietenhartje op de horeca-overzichtskaart
  (te veel load), favoriet maken loopt via de detailpagina.

TASKS.md: afgehandelde punten verwijderd (hartje-bevinding, de limiet van 25),
verbindingsmelding gemarkeerd als "Bob - bezig".

snippets/: de twee custom-code-bestanden bewaard buiten lib/, zodat ze een
export overleven en niet in /tmp verdwijnen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bob hace 1 día
padre
commit
906aa37ab7
Se han modificado 5 ficheros con 276 adiciones y 76 borrados
  1. 65 0
      CLAUDE.md
  2. 14 76
      TASKS.md
  3. 17 0
      snippets/LEESMIJ.md
  4. 47 0
      snippets/check_verbinding.dart.txt
  5. 133 0
      snippets/verbindings_banner.dart.txt

+ 65 - 0
CLAUDE.md

@@ -1912,6 +1912,14 @@ in de tree maakte geen verschil.
   pogingen aan de dialoog. Zet één triviale waarde in datzelfde paneel en
   draai een export. Komt die ook niet door, dan is de dialoog niet je
   probleem en heeft doorproberen geen enkele zin.
+- ⚠️ **ACHTERHAALD per 2026-09-13: dit is CLAUDE-specifiek, niet iets in de
+  paginadata.** Bob heeft op diezelfde pagina (`...OverzichtCurrent`) `Max
+  Items` van 25 naar 1000 gezet en dat kwam gewoon door in de export
+  (`.take(1000)`). De blokkade zit dus in de browser-automation, niet in het
+  project. **Praktisch gevolg: loopt een paneel voor Claude vast, draag het dan
+  over aan Bob in plaats van te concluderen dat het onmogelijk is** — de
+  triviale-waarde-test hierboven blijft nuttig, maar de uitkomst betekent
+  alleen "Claude komt er niet bij".
 - **`Duplicate Page` herstelt het NIET** (getest 2026-09-10): de verse
   kopie erft de blokkade een-op-een — zelfde ingreep, zelfde uitkomst,
   6× `.take(25)` in de export. De blokkade zit dus niet in de opgeslagen
@@ -1986,6 +1994,56 @@ 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.
 
+**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:
+- De setters in `app_state.dart` roepen **géén** `notifyListeners()` aan; alleen
+  `FFAppState().update(() { ... })` doet dat.
+- En dat helpt op zichzelf nog niet: widgets lezen App State via de **singleton**
+  `FFAppState().veld`, niet via `context.watch`. `main.dart` zet er wel een
+  `ChangeNotifierProvider` omheen, maar niemand abonneert zich erop. De rebuild
+  komt in de praktijk altijd van de `safeSetState(() {})` die FlutterFlow ná een
+  Update-App-State-actie in diezelfde widget zet.
+- **Gevolg:** een Visibility-conditie op een App State-veld werkt prima binnen
+  het scherm dat de waarde zelf zet, maar **niet** voor een widget elders (een
+  balk in de gedeelde header bijvoorbeeld) — die evalueert pas opnieuw als er
+  toevallig iets anders een rebuild veroorzaakt.
+- **Werkend patroon daarvoor:** een **Custom Widget** dat zelf luistert met
+  `AnimatedBuilder(animation: FFAppState(), builder: ...)` — `FFAppState` is een
+  `ChangeNotifier`, dus dat mag rechtstreeks. Gecombineerd met `update()` in de
+  custom action reageert zo'n widget direct. Zie `VerbindingsBanner` /
+  `checkVerbinding` als werkend voorbeeld.
+- Een custom widget kan de huidige pagina herladen met
+  `context.pushReplacement(GoRouterState.of(context).uri.toString())` (import
+  `package:go_router/go_router.dart`, werkt gewoon in custom code). Doe dat
+  **nooit** vanuit `initState`/een automatische check — de pagina bouwt het
+  widget dan opnieuw op en je hebt een herlaadlus.
+
+**Offline-gedrag testen op een emulator, zonder de app aan te passen:**
+```
+adb -s <device> shell svc wifi disable && adb -s <device> shell svc data disable
+adb -s <device> shell am force-stop com.uitgaanskrant.app
+adb -s <device> logcat -c   # altijd legen, anders lees je oude regels
+adb -s <device> shell monkey -p com.uitgaanskrant.app -c android.intent.category.LAUNCHER 1
+```
+en achteraf `svc wifi enable` + `svc data enable`. Controleer met
+`dumpsys connectivity | grep "Active default network"` (die zegt `none` als het
+echt uit staat). **Vergeet het herstel niet** — een volgende sessie vindt anders
+een emulator zonder netwerk en zoekt de fout in de app.
+
+**Een APK bouwen vanuit een losse exportmap overleeft een achtergrond-Bash-call
+alleen met `setsid`.** Een gewone `run_in_background`-aanroep van
+`fvm flutter build apk` meldt "exit 0" terwijl Gradle nog draait, en laat geen
+APK achter. Wat wel werkt (zelfde truc als bij het FIFO-recept elders):
+```
+setsid bash -c 'cd /tmp/ff-checkN && /home/bob/fvm/bin/fvm flutter build apk --profile' \
+  < /dev/null > /tmp/ff-checkN/build.log 2>&1 & disown
+```
+en daarna in een aparte call wachten met
+`until ls .../app-profile.apk >/dev/null 2>&1; do sleep 20; done`. Reken op 5-8
+minuten. Installeren met `adb install -r`; dat is los van `flutter run` en
+verstoort dus geen draaiende sessie van iemand anders.
+
 **`getJsonField` geeft bij ÉÉN match de waarde zelf en bij MEERDERE een lijst —
 daar hangt half het project op, en het verklaart de meeste "soms een string,
 soms een lijst"-verrassingen.** De implementatie staat in
@@ -3201,6 +3259,13 @@ maakte dat er geen exposed datumfilter bestond.
     slaat de auto-invulling gewoon over (geen crash), en moet de
     gebruiker de plaats 1x zelf uit de (al correct beperkte) dropdown
     kiezen.
+- **Geen favorietenhartje op de horeca-OVERZICHTSkaart — Bob's besluit
+  2026-09-13: "geeft te veel load".** Favoriet maken loopt uitsluitend via de
+  **detailpagina** (`HorecagelegenheidCurrent`); op Favorieten tab 3 staan dus
+  bewust geen hartjes en ontvolgen gaat via doorklikken naar de zaak. Het hartje
+  stond er ooit wel (het sneuvelde toen Copy3 productie werd) — niet
+  terugbouwen, en `favorieteHorecaNids` hoort daarom op precies één plek in de
+  levende code voor te komen.
 - Favorieten/login zijn P0. Backend-endpoint bestaat al; Drupal 7
   views die de respons voeden hebben soms nog aanpassing nodig.
 - **Fout-/leeg-afhandeling bij API-calls: het "geen enkele

+ 14 - 76
TASKS.md

@@ -1,11 +1,16 @@
 ## ▶ Nu aan de beurt (stand 2026-09-13)
 
-### 🔧 Verbindingsmelding in de header — code klaar, bouwstappen voor Bob
+### 🔧 Verbindingsmelding in de header — Eigenaar: Bob — bezig (2026-09-13)
 
 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).
+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
@@ -18,9 +23,8 @@ 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).
 
-**De twee bestanden** staan in de chat van 2026-09-13 als download. Plak steeds
-alleen wat ónder de `// DO NOT REMOVE`-regel staat; de importkop genereert
-FlutterFlow zelf.
+Plak steeds alleen wat ónder de `// DO NOT REMOVE`-regel staat; de importkop
+genereert FlutterFlow zelf.
 - **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,
@@ -122,19 +126,16 @@ gelezen.
 
 <details><summary>Oorspronkelijke bevinding (2026-09-13, vóór de fix)</summary>
 
-**A · Tab 6 "Verhuur, catering" is niet meegemigreerd — en kapt content af.
-17 van de 42 Amsterdamse zaken zijn onbereikbaar.**
+**A · Tab 6 "Verhuur, catering" is niet meegemigreerd naar de gefilterde
+route.** (Het afkappen op 25 is opgelost; drie punten staan nog open.)
 Op `horecagelegenhedenOverzichtCurrent` bouwen vijf tabs hun lijst via
 `functions.filterHorecagelegenheden(_model.alleX.toList(), ...)`. De zesde
 (Verhuur, catering) doet het nog op de oude manier: een eigen Backend Query
 plus `getJsonField(jsonBody, r'$').toList().take(25)`. Gevolgen, op volgorde
 van ernst:
-1. ✅ **OPGELOST 2026-09-13 (Bob): `.take(25)` staat nu op `.take(1000)`** —
-   exportgeverifieerd. De 42 Amsterdamse verhuur/catering-zaken komen nu
-   allemaal door. **Belangrijke bijvangst: het Generate Dynamic Children-paneel
-   schrijft in Bob's browser dus wél weg op deze pagina** — de blokkade die in
-   `CLAUDE.md` staat is Claude-specifiek, niet iets in de opgeslagen
-   paginadata.
+1. ✅ *(De limiet van 25 is 2026-09-13 door Bob opgelost: `.take(1000)`,
+   exportgeverifieerd. Daarmee bleek ook dat het Generate Dynamic
+   Children-paneel voor Bob gewoon wegschrijft — dat staat nu in `CLAUDE.md`.)*
 2. **Geen zoekveld** op deze tab — dit is het bekende "5 van de 6"-restpunt
    uit P2-6, nu exact gelokaliseerd.
 3. ⚠️ **Crasht bij een netwerkfout — nu HARD BEWEZEN, en het raakt meer dan
@@ -161,69 +162,6 @@ gevolg: er is content die een gebruiker niet kan zien.**
 
 </details>
 
-**B · ✅ AFGEHANDELD — geen hartje op het horecakaartje, Bob's besluit
-2026-09-13: "geeft te veel load".** Het favorietenhartje op de
-horeca-OVERZICHTSkaart is inderdaad verdwenen (gesneuveld in commit `7094b43`,
-taak 18, toen Copy3 productie werd), maar dat blijft zo — **niet terugbouwen**.
-Favoriet maken loopt voortaan uitsluitend via de detailpagina; op Favorieten
-tab 3 staan dus bewust geen hartjes en ontvolgen gaat via doorklikken naar de
-zaak. P1-7's tekst is hierop gecorrigeerd.
-*(Restje, cosmetisch en zonder haast: de parameter `nid` wordt nog steeds aan
-`HorecagelegenheidoverzichtKaart` doorgegeven maar nergens meer gelezen — het
-overblijfsel van het verwijderde hartje. De pagina gebruikt zijn eigen `nid`
-voor de tap-navigatie, dus er is niets stuk.)*
-
-**C · Hetzelfde crashpatroon staat ook op HOME — de startpagina van de app.**
-Nadat bevinding A's punt 3 hard bewezen was, projectbreed gezocht naar
-`getJsonField(x, pad).toList()` zónder de `isList`-vlag. In **levende** code
-(dus zonder `kanweg/`, `_copy*` en `_orgineel*`) staan 11 plekken. Na filteren
-op wat een gebruiker echt kan bereiken blijven er vier over:
-
-| plek | pad | bereikbaar via |
-|---|---|---|
-| `home_uitgaan_slider_component_widget.dart:161` | `$` | **Home — de startpagina** |
-| `p_uitgaan_slider_component_widget.dart:158` | `$` | P-Uitgaan-pagina |
-| `horecagelegenheden_overzicht_current_widget.dart:1643` | `$` | horeca-overzicht, tab 6 |
-| `home_uitgaantabel_kaart_component_widget.dart:651` | `$.categorie` | Home-tabs (per kaart) |
-
-De zes treffers in `horecagelegenheden_overzicht_provincie_page` tellen
-nauwelijks mee: die pagina staat wel in `nav.dart` maar **geen enkele knop
-navigeert ernaartoe** (alleen via deep-link te bereiken). En
-`SliderUitgaanComponentSmallCurrent` heeft nul gebruikers.
-
-**Wat er gebeurt:** `ApiManager` vangt elke exception af en levert dan
-`ApiCallResponse(null, {}, -1, ...)` — de Future slaagt dus, de `FutureBuilder`
-bouwt door, en `getJsonField(null, r'$')` geeft `null` waarop `.toList()`
-crasht. In een **profile**-build is dat volledig stil: geen rood scherm, geen
-overflow-streep, niets in `dart analyze` — alleen een grijs/leeg vlak, en
-volgens het bekende patroon verdwijnt alles eronder in dezelfde `Column` mee.
-
-✅ **Live nagemeten op de telefoon-emulator (2026-09-13, eigen profile-build,
-`svc wifi disable` + `svc data disable`) — het gebeurt echt, en Home ziet er
-kapot uit.** In `logcat` staat exact één regel:
-`NoSuchMethodError: The method 'toList' was called on null.` Op het scherm:
-- waar de slider hoort staat een **groot grijs blok** (beeldvullend, ± een
-  derde van het scherm);
-- **de hele tabinhoud eronder is leeg** — wit, geen kaarten;
-- **geen enkele melding**: geen "geen verbinding", geen retry-knop, geen icoon.
-De app crasht dus niet wég (het proces blijft draaien, de tabbalk werkt), maar
-Home is niet van een stukgelopen scherm te onderscheiden. Screenshots van
-online vs. offline zijn 2026-09-13 in de chat gedeeld.
-
-**Oordeel: dit hoort vóór livegang gefixt.** Niet omdat er zonder netwerk data
-zou moeten zijn, maar omdat de eerste indruk bij een haperende verbinding een
-grijs vlak zonder uitleg is — en dat is precies het scenario "gebruiker opent de
-app in de trein". Slechts één exceptie per start, dus het is één plek per
-scherm, geen sleepnet.
-
-**De fix, als die nodig blijkt,** is dezelfde route die de vijf horeca-tabs al
-namen: niet rechtstreeks uit de Backend Query lezen, maar via een custom action
-die `[]` teruggeeft bij een mislukte call (`fetchAlleHorecagelegenheden` is het
-werkende voorbeeld, zie `!response.succeeded → break`). Een goedkopere variant
-voor alleen de sliders: de `Generate Dynamic Children`-binding een
-**"Is List"**-transform geven, want `getJsonField(..., true)` levert altijd een
-lijst.
-
 **Wat de audit NIET vond (nagemeten, zodat niemand het nog eens doet):**
 - **Het P1-15-patroon is projectbreed schoon.** Alle 16 `launchURL`-aanroepen
   in levende code hangen achter een guard op de **rauwe** waarde, niet op een

+ 17 - 0
snippets/LEESMIJ.md

@@ -0,0 +1,17 @@
+# Snippets
+
+Custom code die via de FlutterFlow Custom Code-editor ingevoerd moet worden.
+Staat hier als `.txt` zodat `flutter analyze` en de export er niets mee doen —
+deze map ligt bewust buiten `lib/` en overleeft daarom een `export-code`.
+
+Plak bij het invoeren alleen wat **onder** de `// DO NOT REMOVE`-regel staat;
+de importkop genereert FlutterFlow zelf.
+
+- `check_verbinding.dart.txt` — Custom **Action** `checkVerbinding`,
+  Return Type Boolean, geen argumenten.
+- `verbindings_banner.dart.txt` — Custom **Widget** `VerbindingsBanner`,
+  parameters `width` (double, optioneel), `height` (double, optioneel),
+  `tekst` (String, optioneel).
+
+Beide horen bij de verbindingsmelding in de header; de bouwstappen staan in
+`TASKS.md`.

+ 47 - 0
snippets/check_verbinding.dart.txt

@@ -0,0 +1,47 @@
+// Automatic FlutterFlow imports
+import '/backend/schema/structs/index.dart';
+import '/flutter_flow/flutter_flow_theme.dart';
+import '/flutter_flow/flutter_flow_util.dart';
+import 'index.dart'; // Imports other custom actions
+import '/flutter_flow/custom_functions.dart'; // Imports custom functions
+import 'package:flutter/material.dart';
+// Begin custom action code
+// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
+
+import 'dart:async';
+import 'package:http/http.dart' as http;
+
+/// Kijkt of de server bereikbaar is en zet App State `geenVerbinding`.
+/// Geeft true terug als de verbinding in orde is.
+///
+/// Bewust een HEAD-request op de site-root: die levert 0 bytes body op en
+/// antwoordt in ongeveer 60 ms, dus dit is verwaarloosbaar naast de gewone
+/// data-calls. We kijken alleen of de server antwoordt, niet wat hij zegt.
+Future<bool> checkVerbinding() async {
+  final basis = FFAppState().apiBaseUrl.trim().isEmpty
+      ? 'https://uitgaanskrant.com'
+      : FFAppState().apiBaseUrl.trim();
+
+  bool bereikbaar;
+  try {
+    final response = await http
+        .head(Uri.parse(basis))
+        .timeout(const Duration(seconds: 6));
+    // Elke echte HTTP-reactie betekent dat we de server hebben bereikt.
+    // Alleen een 5xx rekenen we als 'niet bruikbaar'.
+    bereikbaar = response.statusCode < 500;
+  } catch (_) {
+    // Geen netwerk, DNS-fout, timeout, certificaatfout: allemaal 'geen verbinding'.
+    bereikbaar = false;
+  }
+
+  final nieuweWaarde = !bereikbaar;
+  if (FFAppState().geenVerbinding != nieuweWaarde) {
+    // update() roept notifyListeners() aan; zonder dat merkt de banner niets.
+    FFAppState().update(() {
+      FFAppState().geenVerbinding = nieuweWaarde;
+    });
+  }
+
+  return bereikbaar;
+}

+ 133 - 0
snippets/verbindings_banner.dart.txt

@@ -0,0 +1,133 @@
+// Automatic FlutterFlow imports
+import '/backend/schema/structs/index.dart';
+import '/flutter_flow/flutter_flow_theme.dart';
+import '/flutter_flow/flutter_flow_util.dart';
+import 'index.dart'; // Imports other custom widgets
+import '/custom_code/actions/index.dart'; // Imports custom actions
+import '/flutter_flow/custom_functions.dart'; // Imports custom functions
+import 'package:flutter/material.dart';
+// Begin custom widget code
+// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
+
+import 'package:go_router/go_router.dart';
+
+/// Balkje dat zichzelf toont zodra de server onbereikbaar is.
+///
+/// Waarom een custom widget en geen Text met een Visibility-conditie: de
+/// widgets in dit project lezen App State via de singleton `FFAppState()`,
+/// niet via `context.watch`. Een gewone conditie zou dus pas opnieuw
+/// evalueren als er toevallig iets anders een rebuild veroorzaakt. Dit
+/// widget luistert zelf naar FFAppState en verschijnt daardoor direct.
+class VerbindingsBanner extends StatefulWidget {
+  const VerbindingsBanner({
+    super.key,
+    this.width,
+    this.height,
+    this.tekst,
+  });
+
+  final double? width;
+  final double? height;
+  final String? tekst;
+
+  @override
+  State<VerbindingsBanner> createState() => _VerbindingsBannerState();
+}
+
+class _VerbindingsBannerState extends State<VerbindingsBanner> {
+  // Gedeeld over alle instanties: bij het doorklikken tussen pagina's wordt
+  // niet bij elke opbouw opnieuw een verzoek gedaan.
+  static DateTime? _laatsteCheck;
+  static const Duration _minimaalTussenChecks = Duration(seconds: 20);
+
+  bool _bezig = false;
+
+  @override
+  void initState() {
+    super.initState();
+    WidgetsBinding.instance.addPostFrameCallback((_) => _checkIndienNodig());
+  }
+
+  Future<void> _checkIndienNodig() async {
+    final vorige = _laatsteCheck;
+    if (vorige != null &&
+        DateTime.now().difference(vorige) < _minimaalTussenChecks) {
+      return;
+    }
+    await _check(herlaadBijHerstel: false);
+  }
+
+  /// [herlaadBijHerstel] staat alleen aan bij een tik van de gebruiker.
+  /// Automatisch herladen zou een lus opleveren: de pagina bouwt het widget
+  /// opnieuw op, dat checkt weer, enzovoort.
+  Future<void> _check({bool herlaadBijHerstel = true}) async {
+    if (_bezig) return;
+    if (mounted) setState(() => _bezig = true);
+    _laatsteCheck = DateTime.now();
+    bool bereikbaar = false;
+    try {
+      bereikbaar = await checkVerbinding();
+    } finally {
+      if (mounted) setState(() => _bezig = false);
+    }
+    if (bereikbaar && herlaadBijHerstel && mounted) {
+      // De FutureBuilders op deze pagina zijn al klaar met een mislukte
+      // respons; alleen de balk weghalen laat een leeg scherm achter.
+      // Daarom de huidige route opnieuw opbouwen, zodat de data alsnog laadt.
+      final huidigePad = GoRouterState.of(context).uri.toString();
+      context.pushReplacement(huidigePad);
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return AnimatedBuilder(
+      animation: FFAppState(),
+      builder: (context, _) {
+        if (!FFAppState().geenVerbinding) {
+          // Neemt geen ruimte in zolang alles in orde is.
+          return const SizedBox.shrink();
+        }
+        return Material(
+          color: Colors.transparent,
+          child: InkWell(
+            onTap: () => _check(),
+            child: Container(
+              width: widget.width ?? double.infinity,
+              height: widget.height,
+              color: FlutterFlowTheme.of(context).primary,
+              padding:
+                  const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
+              child: Row(
+                mainAxisSize: MainAxisSize.max,
+                children: [
+                  const Icon(Icons.cloud_off, color: Colors.white, size: 18.0),
+                  const SizedBox(width: 8.0),
+                  Expanded(
+                    child: Text(
+                      widget.tekst ??
+                          'Geen verbinding — tik om het opnieuw te proberen',
+                      style: const TextStyle(
+                        color: Colors.white,
+                        fontSize: 13.0,
+                      ),
+                    ),
+                  ),
+                  if (_bezig)
+                    const SizedBox(
+                      width: 14.0,
+                      height: 14.0,
+                      child: CircularProgressIndicator(
+                        strokeWidth: 2.0,
+                        color: Colors.white,
+                      ),
+                    ),
+                ],
+              ),
+            ),
+          ),
+        );
+      },
+    );
+  }
+}