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

Taak 97: zoekveld op de provincie-horeca-pagina (Bob gebouwd, Claude geverifieerd)

Zoekveld staat bovenaan de Column (voor de TabBar), On Change doet een
Rebuild Page met FlutterFlow's eigen debounce van 2000 ms, en alle zes de
tabs filteren nu via filterHorecagelegenheden met _model.textController.text
als zoekterm. De Empty List Widgets en de AdBanner uit 95b/96 zijn intact.

⚠️ Twee restpunten, zie 97c en 97d in TASKS.md:
- de binding levert 6x een null-check-operator op
  (HorecagelegenheidoverzichtCall.items(...)!.toList()) omdat het argument
  items non-nullable is. Voor taak 97 stond daar ...?.toList() ?? [] en was
  het null-veilig; nu crasht de pagina bij een mislukte call.
- de Engelse vertaling van de nieuwe hint "Zoek op naam" is leeg.

internationalization.dart gaat hier mee omdat de nieuwe hint-sleutel erin
staat; het bestand bevat ook sleutels van de sessie die parallel werkte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bob 10 часов назад
Родитель
Сommit
9344bb7c6d

+ 127 - 18
lib/flutter_flow/internationalization.dart

@@ -170,6 +170,10 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Wachtwoord vergeten?',
       'en': 'Forgot password?',
     },
+    'pq12hujc': {
+      'nl': 'Nog geen account? Registreren',
+      'en': 'No account yet? Register',
+    },
     'bokhk9vk': {
       'nl': 'Home',
       'en': 'Home',
@@ -246,7 +250,7 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
     },
     'uxy2nfok': {
       'nl': 'Films',
-      'en': 'Moviews',
+      'en': 'Movies',
     },
     'lx77xfrn': {
       'nl': 'Jeugd',
@@ -299,6 +303,10 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
   },
   // HorecagelegenhedenOverzichtProvinciePage
   {
+    'nm6s2mkp': {
+      'nl': 'Zoek op naam',
+      'en': '',
+    },
     'mgbxk04v': {
       'nl': 'Activiteiten',
       'en': 'Activities',
@@ -379,42 +387,56 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Gebruiker',
       'en': 'Agenda',
     },
-    '275gmehq': {
+    'wl9hk4vl': {
       'nl': 'Uitloggen',
       'en': 'Log out',
     },
-    'grngrmt3': {
+    '1kr1j46k': {
       'nl': '',
       'en': '',
     },
-    'pdzmzb1p': {
+    'mj6x0sxf': {
       'nl': 'Mijn profiel',
       'en': 'My Profile',
     },
-    't7deo6w1': {
+    '2e7lik1s': {
       'nl': '',
       'en': '',
     },
-    'ogz7q3xk': {
+    'wxlmmqen': {
       'nl': 'Wachtwoord wijzigen',
       'en': 'Change password',
     },
-    '3t3g8j3w': {
+    'lrkrussh': {
       'nl': '',
       'en': '',
     },
-    'i31b4itp': {
+    'lwnfr9gv': {
       'nl': 'Account verwijderen',
       'en': 'Delete account',
     },
-    '0oyjp8gs': {
+    '0qqcv0w0': {
       'nl': '',
       'en': '',
     },
-    'fbl4ak2y': {
+    'xglkp3tc': {
       'nl': 'Stadsactiviteit aanmaken',
       'en': 'Create city activity',
     },
+    'zxbjvxzq': {
+      'nl':
+          'Met een account bewaar je favoriete gemeenten en gelegenheden, en krijg je een agenda per mail.',
+      'en':
+          'With an account you save your favourite municipalities and venues, and get an agenda by email.',
+    },
+    '1xim8yie': {
+      'nl': 'Account aanmaken',
+      'en': 'Create account',
+    },
+    'svydwydi': {
+      'nl': 'Inloggen',
+      'en': 'Log in',
+    },
     'vpqh55o7': {
       'nl': 'Home',
       'en': 'Home',
@@ -460,6 +482,12 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Wat',
       'en': 'What',
     },
+    'evhqyjou': {
+      'nl':
+          'Geef een korte, herkenbare titel. De omschrijving verschijnt op de detailpagina van de activiteit.',
+      'en':
+          'Give it a short, recognisable title. The description appears on the activity\'s detail page.',
+    },
     'xorq08j5': {
       'nl': 'Titel',
       'en': 'Title',
@@ -480,6 +508,12 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Categorie evenement',
       'en': 'Category',
     },
+    'i0ij4drx': {
+      'nl':
+          'Let op: de categorie bepaalt in welke overzichten je activiteit verschijnt. Kies er minstens een - zonder categorie is je activiteit nergens terug te vinden.',
+      'en':
+          'Note: the category decides which listings your activity appears in. Pick at least one - without a category your activity won\'t show up anywhere.',
+    },
     'or5fd9n1': {
       'nl': 'Selecteer...',
       'en': 'Select...',
@@ -504,6 +538,12 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Wanneer',
       'en': 'When',
     },
+    'e1nwfbwv': {
+      'nl':
+          'De begindatum is verplicht. Vul een einddatum alleen in bij een activiteit die meerdere dagen duurt.',
+      'en':
+          'The start date is required. Only fill in an end date for an activity that runs several days.',
+    },
     'dfa8vusy': {
       'nl': 'Datum',
       'en': 'Date',
@@ -691,9 +731,15 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Wat',
       'en': 'What',
     },
+    'ohgppxt2': {
+      'nl':
+          'Geef een korte, herkenbare titel. De omschrijving verschijnt op de detailpagina van het evenement.',
+      'en':
+          'Give it a short, recognisable title. The description appears on the event\'s detail page.',
+    },
     'vc80d3lh': {
-      'nl': 'Titel',
-      'en': 'Title',
+      'nl': 'Titel *',
+      'en': 'Title *',
     },
     'vu6qv8cj': {
       'nl': 'Titel evenement',
@@ -711,6 +757,12 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Uw Horecagelegenheid',
       'en': 'Your Establishment',
     },
+    'fbkrt89w': {
+      'nl':
+          'Kies de zaak waar het evenement plaatsvindt. Je ziet hier alleen zaken die op jouw account staan.',
+      'en':
+          'Choose the venue where the event takes place. You only see venues linked to your account.',
+    },
     'nhnxstvm': {
       'nl': 'Kies je horecagelegenheid',
       'en': 'Select your establishment',
@@ -735,6 +787,12 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Categorie evenement',
       'en': '',
     },
+    'j68hqlk7': {
+      'nl':
+          'Let op: de categorie bepaalt in welke overzichten je evenement verschijnt. Kies er minstens een - zonder categorie is je evenement nergens terug te vinden.',
+      'en':
+          'Note: the category decides which listings your event appears in. Pick at least one - without a category your event won\'t show up anywhere.',
+    },
     '2hitlrxa': {
       'nl': 'Select...',
       'en': '',
@@ -759,9 +817,15 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Wanneer',
       'en': 'Wanneer',
     },
+    'f8hii0ci': {
+      'nl':
+          'De begindatum is verplicht. Vul een einddatum alleen in bij een evenement dat meerdere dagen duurt.',
+      'en':
+          'The start date is required. Only fill in an end date for an event that runs several days.',
+    },
     'xceonmpt': {
-      'nl': 'Datum',
-      'en': 'Datum',
+      'nl': 'Datum *',
+      'en': 'Date *',
     },
     'nws4h1nz': {
       'nl': 'Datum',
@@ -779,6 +843,12 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Organisatie',
       'en': '',
     },
+    'len3npim': {
+      'nl':
+          'Optioneel. Een website of ticketlink tonen we als knop bij je evenement.',
+      'en':
+          'Optional. A website or ticket link is shown as a button on your event.',
+    },
     'e9n6cj1o': {
       'nl': 'WebsiteURL',
       'en': '',
@@ -799,6 +869,12 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Entree',
       'en': 'Entree',
     },
+    'rj9dgdp7': {
+      'nl':
+          'Laat leeg als er geen entree wordt geheven. Vul de prijs in als bedrag, bijvoorbeeld 7,50.',
+      'en':
+          'Leave empty if there\'s no admission charge. Enter the price as an amount, for example 7.50.',
+    },
     'ht4toe4o': {
       'nl': 'Select...',
       'en': '',
@@ -843,6 +919,12 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Media',
       'en': 'Media',
     },
+    'nvi2k89n': {
+      'nl':
+          'Een logo en meerdere foto\'s. Tik nogmaals op Foto\'s kiezen om er nog een toe te voegen; de vorige blijft staan.',
+      'en':
+          'One logo and several photos. Tap Choose photos again to add another; the previous one stays.',
+    },
     'df4oowbq': {
       'nl': 'Logo kiezen',
       'en': 'Logo kiezen',
@@ -906,6 +988,37 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'en': 'Home',
     },
   },
+  // HorecagelegenhedenOverzichtProvinciePageCopy
+  {
+    'svui455c': {
+      'nl': 'Activiteiten',
+      'en': 'Activities',
+    },
+    'trzvj19f': {
+      'nl': 'Cultuur',
+      'en': 'Culture',
+    },
+    'e9j5xhbl': {
+      'nl': 'Eetgelegenheden',
+      'en': 'Eatery',
+    },
+    'sh4ardkg': {
+      'nl': 'Overnachten',
+      'en': 'Overnight',
+    },
+    'ifwq069y': {
+      'nl': 'Uitgaan',
+      'en': 'Go Out',
+    },
+    'lrb9knvx': {
+      'nl': 'Verhuur, catering',
+      'en': 'Renting Catering',
+    },
+    'sq5foqoj': {
+      'nl': 'Home',
+      'en': 'Home',
+    },
+  },
   // SelectStateDropDownComponent
   {
     'duloakue': {
@@ -1124,10 +1237,6 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
       'nl': 'Mijn Account',
       'en': 'My account',
     },
-    '7qpu1l01': {
-      'nl': 'v0001',
-      'en': 'v0001',
-    },
   },
   // EvenementComponent
   {

+ 17 - 0
lib/horecagelegenhedenoverzicht/horecagelegenheden_overzicht_provincie_page/horecagelegenheden_overzicht_provincie_page_model.dart

@@ -8,9 +8,11 @@ import '/horecagelegenhedenoverzicht/horecagelegenheidoverzicht_kaart/horecagele
 import '/shared/drawer_component/drawer_component_widget.dart';
 import 'dart:ui';
 import '/backend/schema/structs/index.dart';
+import '/flutter_flow/custom_functions.dart' as functions;
 import '/index.dart';
 import 'horecagelegenheden_overzicht_provincie_page_widget.dart'
     show HorecagelegenhedenOverzichtProvinciePageWidget;
+import 'package:easy_debounce/easy_debounce.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_spinkit/flutter_spinkit.dart';
 import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
@@ -63,6 +65,10 @@ class HorecagelegenhedenOverzichtProvinciePageModel
 
   ///  State fields for stateful widgets in this page.
 
+  // State field(s) for TextField widget.
+  FocusNode? textFieldFocusNode;
+  TextEditingController? textController;
+  String? Function(BuildContext, String?)? textControllerValidator;
   // State field(s) for TabBar widget.
   TabController? tabBarController;
   int get tabBarCurrentIndex =>
@@ -101,6 +107,9 @@ class HorecagelegenhedenOverzichtProvinciePageModel
 
   @override
   void dispose() {
+    textFieldFocusNode?.dispose();
+    textController?.dispose();
+
     tabBarController?.dispose();
     headerButtonsComponentModel.dispose();
     drawerComponentModel.dispose();
@@ -173,6 +182,14 @@ class HorecagelegenhedenOverzichtProvinciePageModel
           )
         }.entries,
         widgetStates: {
+          'textFieldText': debugSerializeParam(
+            textController?.text,
+            ParamType.String,
+            link:
+                'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=HorecagelegenhedenOverzichtProvinciePage',
+            name: 'String',
+            nullable: true,
+          ),
           'tabBarCurrentIndex': debugSerializeParam(
             tabBarCurrentIndex,
             ParamType.int,

+ 189 - 28
lib/horecagelegenhedenoverzicht/horecagelegenheden_overzicht_provincie_page/horecagelegenheden_overzicht_provincie_page_widget.dart

@@ -8,7 +8,9 @@ import '/horecagelegenhedenoverzicht/horecagelegenheidoverzicht_kaart/horecagele
 import '/shared/drawer_component/drawer_component_widget.dart';
 import 'dart:ui';
 import '/backend/schema/structs/index.dart';
+import '/flutter_flow/custom_functions.dart' as functions;
 import '/index.dart';
+import 'package:easy_debounce/easy_debounce.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_spinkit/flutter_spinkit.dart';
 import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
@@ -46,6 +48,12 @@ class _HorecagelegenhedenOverzichtProvinciePageWidgetState
     _model = createModel(
         context, () => HorecagelegenhedenOverzichtProvinciePageModel());
 
+    _model.textController ??= TextEditingController()
+      ..addListener(() {
+        debugLogWidgetClass(_model);
+      });
+    _model.textFieldFocusNode ??= FocusNode();
+
     _model.tabBarController = TabController(
       vsync: this,
       length: 6,
@@ -178,6 +186,113 @@ class _HorecagelegenhedenOverzichtProvinciePageWidgetState
           child: Column(
             mainAxisSize: MainAxisSize.max,
             children: [
+              Container(
+                width: double.infinity,
+                child: TextFormField(
+                  controller: _model.textController,
+                  focusNode: _model.textFieldFocusNode,
+                  onChanged: (_) => EasyDebounce.debounce(
+                    '_model.textController',
+                    Duration(milliseconds: 2000),
+                    () async {
+                      safeSetState(() {});
+                    },
+                  ),
+                  autofocus: false,
+                  enabled: true,
+                  obscureText: false,
+                  decoration: InputDecoration(
+                    isDense: true,
+                    labelStyle:
+                        FlutterFlowTheme.of(context).labelMedium.override(
+                              font: GoogleFonts.roboto(
+                                fontWeight: FlutterFlowTheme.of(context)
+                                    .labelMedium
+                                    .fontWeight,
+                                fontStyle: FlutterFlowTheme.of(context)
+                                    .labelMedium
+                                    .fontStyle,
+                              ),
+                              letterSpacing: 0.0,
+                              fontWeight: FlutterFlowTheme.of(context)
+                                  .labelMedium
+                                  .fontWeight,
+                              fontStyle: FlutterFlowTheme.of(context)
+                                  .labelMedium
+                                  .fontStyle,
+                            ),
+                    hintText: FFLocalizations.of(context).getText(
+                      'nm6s2mkp' /* Zoek op naam */,
+                    ),
+                    hintStyle:
+                        FlutterFlowTheme.of(context).labelMedium.override(
+                              font: GoogleFonts.roboto(
+                                fontWeight: FlutterFlowTheme.of(context)
+                                    .labelMedium
+                                    .fontWeight,
+                                fontStyle: FlutterFlowTheme.of(context)
+                                    .labelMedium
+                                    .fontStyle,
+                              ),
+                              letterSpacing: 0.0,
+                              fontWeight: FlutterFlowTheme.of(context)
+                                  .labelMedium
+                                  .fontWeight,
+                              fontStyle: FlutterFlowTheme.of(context)
+                                  .labelMedium
+                                  .fontStyle,
+                            ),
+                    enabledBorder: OutlineInputBorder(
+                      borderSide: BorderSide(
+                        color: Color(0x00000000),
+                        width: 1.0,
+                      ),
+                      borderRadius: BorderRadius.circular(8.0),
+                    ),
+                    focusedBorder: OutlineInputBorder(
+                      borderSide: BorderSide(
+                        color: Color(0x00000000),
+                        width: 1.0,
+                      ),
+                      borderRadius: BorderRadius.circular(8.0),
+                    ),
+                    errorBorder: OutlineInputBorder(
+                      borderSide: BorderSide(
+                        color: FlutterFlowTheme.of(context).error,
+                        width: 1.0,
+                      ),
+                      borderRadius: BorderRadius.circular(8.0),
+                    ),
+                    focusedErrorBorder: OutlineInputBorder(
+                      borderSide: BorderSide(
+                        color: FlutterFlowTheme.of(context).error,
+                        width: 1.0,
+                      ),
+                      borderRadius: BorderRadius.circular(8.0),
+                    ),
+                    filled: true,
+                    fillColor: FlutterFlowTheme.of(context).secondaryBackground,
+                  ),
+                  style: FlutterFlowTheme.of(context).bodyMedium.override(
+                        font: GoogleFonts.roboto(
+                          fontWeight: FlutterFlowTheme.of(context)
+                              .bodyMedium
+                              .fontWeight,
+                          fontStyle:
+                              FlutterFlowTheme.of(context).bodyMedium.fontStyle,
+                        ),
+                        letterSpacing: 0.0,
+                        fontWeight:
+                            FlutterFlowTheme.of(context).bodyMedium.fontWeight,
+                        fontStyle:
+                            FlutterFlowTheme.of(context).bodyMedium.fontStyle,
+                      ),
+                  cursorColor: FlutterFlowTheme.of(context).primaryText,
+                  enableInteractiveSelection: true,
+                  validator:
+                      _model.textControllerValidator.asValidator(context),
+                ),
+              ),
               Expanded(
                 child: Column(
                   children: [
@@ -342,15 +457,21 @@ class _HorecagelegenhedenOverzichtProvinciePageWidgetState
 
                                     return Builder(
                                       builder: (context) {
-                                        final horecagelegenheden =
-                                            (HorecagelegenheidoverzichtCall
+                                        final horecagelegenheden = functions
+                                            .filterHorecagelegenheden(
+                                                HorecagelegenheidoverzichtCall
                                                         .items(
-                                                      staggeredViewHorecagelegenheidoverzichtResponse
-                                                          .jsonBody,
-                                                    )?.toList() ??
-                                                    [])
-                                                .take(1000)
-                                                .toList();
+                                                  staggeredViewHorecagelegenheidoverzichtResponse
+                                                      .jsonBody,
+                                                )!
+                                                    .toList(),
+                                                _model.textController.text,
+                                                '',
+                                                '\$.titel',
+                                                '\$.categorie')
+                                            .toList()
+                                            .take(1000)
+                                            .toList();
                                         if (horecagelegenheden.isEmpty) {
                                           return Center(
                                             child: Image.asset(
@@ -539,12 +660,20 @@ class _HorecagelegenhedenOverzichtProvinciePageWidgetState
                                           return Builder(
                                             builder: (context) {
                                               final horecagelegenheden =
-                                                  (HorecagelegenheidoverzichtCall
-                                                              .items(
+                                                  functions
+                                                      .filterHorecagelegenheden(
+                                                          HorecagelegenheidoverzichtCall
+                                                                  .items(
                                                             staggeredViewHorecagelegenheidoverzichtResponse
                                                                 .jsonBody,
-                                                          )?.toList() ??
-                                                          [])
+                                                          )!
+                                                              .toList(),
+                                                          _model.textController
+                                                              .text,
+                                                          '',
+                                                          '\$.titel',
+                                                          '\$.categorie')
+                                                      .toList()
                                                       .take(1000)
                                                       .toList();
                                               if (horecagelegenheden.isEmpty) {
@@ -764,12 +893,20 @@ class _HorecagelegenhedenOverzichtProvinciePageWidgetState
                                           return Builder(
                                             builder: (context) {
                                               final horecagelegenheden =
-                                                  (HorecagelegenheidoverzichtCall
-                                                              .items(
+                                                  functions
+                                                      .filterHorecagelegenheden(
+                                                          HorecagelegenheidoverzichtCall
+                                                                  .items(
                                                             staggeredViewHorecagelegenheidoverzichtResponse
                                                                 .jsonBody,
-                                                          )?.toList() ??
-                                                          [])
+                                                          )!
+                                                              .toList(),
+                                                          _model.textController
+                                                              .text,
+                                                          '',
+                                                          '\$.titel',
+                                                          '\$.categorie')
+                                                      .toList()
                                                       .take(1000)
                                                       .toList();
                                               if (horecagelegenheden.isEmpty) {
@@ -989,12 +1126,20 @@ class _HorecagelegenhedenOverzichtProvinciePageWidgetState
                                           return Builder(
                                             builder: (context) {
                                               final horecagelegenheden =
-                                                  (HorecagelegenheidoverzichtCall
-                                                              .items(
+                                                  functions
+                                                      .filterHorecagelegenheden(
+                                                          HorecagelegenheidoverzichtCall
+                                                                  .items(
                                                             staggeredViewHorecagelegenheidoverzichtResponse
                                                                 .jsonBody,
-                                                          )?.toList() ??
-                                                          [])
+                                                          )!
+                                                              .toList(),
+                                                          _model.textController
+                                                              .text,
+                                                          '',
+                                                          '\$.titel',
+                                                          '\$.categorie')
+                                                      .toList()
                                                       .take(1000)
                                                       .toList();
                                               if (horecagelegenheden.isEmpty) {
@@ -1215,12 +1360,20 @@ class _HorecagelegenhedenOverzichtProvinciePageWidgetState
                                           return Builder(
                                             builder: (context) {
                                               final horecagelegenheden =
-                                                  (HorecagelegenheidoverzichtCall
-                                                              .items(
+                                                  functions
+                                                      .filterHorecagelegenheden(
+                                                          HorecagelegenheidoverzichtCall
+                                                                  .items(
                                                             staggeredViewHorecagelegenheidoverzichtResponse
                                                                 .jsonBody,
-                                                          )?.toList() ??
-                                                          [])
+                                                          )!
+                                                              .toList(),
+                                                          _model.textController
+                                                              .text,
+                                                          '',
+                                                          '\$.titel',
+                                                          '\$.categorie')
+                                                      .toList()
                                                       .take(1000)
                                                       .toList();
                                               if (horecagelegenheden.isEmpty) {
@@ -1440,12 +1593,20 @@ class _HorecagelegenhedenOverzichtProvinciePageWidgetState
                                           return Builder(
                                             builder: (context) {
                                               final horecagelegenheden =
-                                                  (HorecagelegenheidoverzichtCall
-                                                              .items(
+                                                  functions
+                                                      .filterHorecagelegenheden(
+                                                          HorecagelegenheidoverzichtCall
+                                                                  .items(
                                                             staggeredViewHorecagelegenheidoverzichtResponse
                                                                 .jsonBody,
-                                                          )?.toList() ??
-                                                          [])
+                                                          )!
+                                                              .toList(),
+                                                          _model.textController
+                                                              .text,
+                                                          '',
+                                                          '\$.titel',
+                                                          '\$.categorie')
+                                                      .toList()
                                                       .take(1000)
                                                       .toList();
                                               if (horecagelegenheden.isEmpty) {