Browse Source

Add HeaderButtonsComponent: standard reusable header buttons (drawer + back)

Extracted the drawer/back IconButton row from PUitgaanPage's and login's
AppBar into a shared component so future pages/edits don't duplicate it.
The AppBar's logo/background slot stays per-page (FlutterFlow's native
AppBar-background widget type can't be componentized). Applied to
PUitgaanPage and login as the first two pages using the new component.
Verified: builds and runs cleanly on emulator-5554.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
bob 1 month ago
parent
commit
b79360db46

+ 4 - 4
ios/Runner.xcodeproj/project.pbxproj

@@ -44,8 +44,8 @@
 		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
 		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
-		6436409C27A31CD500820AF7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		6436409027A31CD300820AF7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		6436409C27A31CD100820AF7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		6436409A27A31CD100820AF7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -225,8 +225,8 @@
 		6436409C27A31CD800820AF7 /* InfoPlist.strings */ = {
 			isa = PBXVariantGroup;
 			children = (
-				6436409C27A31CD500820AF7 /* nl */,
-				6436409027A31CD300820AF7 /* en */,
+				6436409C27A31CD100820AF7 /* nl */,
+				6436409A27A31CD100820AF7 /* en */,
 			);
 			name = InfoPlist.strings;
 			sourceTree = "<group>";

+ 41 - 0
lib/components/header_buttons_component_model.dart

@@ -0,0 +1,41 @@
+import '/flutter_flow/flutter_flow_icon_button.dart';
+import '/flutter_flow/flutter_flow_theme.dart';
+import '/flutter_flow/flutter_flow_util.dart';
+import '/flutter_flow/flutter_flow_widgets.dart';
+import 'dart:ui';
+import 'header_buttons_component_widget.dart' show HeaderButtonsComponentWidget;
+import 'package:flutter/material.dart';
+import 'package:flutter_spinkit/flutter_spinkit.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:provider/provider.dart';
+
+class HeaderButtonsComponentModel
+    extends FlutterFlowModel<HeaderButtonsComponentWidget> {
+  final Map<String, DebugDataField> debugGeneratorVariables = {};
+  final Map<String, DebugDataField> debugBackendQueries = {};
+  final Map<String, FlutterFlowModel> widgetBuilderComponents = {};
+  @override
+  void initState(BuildContext context) {}
+
+  @override
+  void dispose() {}
+
+  @override
+  WidgetClassDebugData toWidgetClassDebugData() => WidgetClassDebugData(
+        generatorVariables: debugGeneratorVariables.entries,
+        backendQueries: debugBackendQueries.entries,
+        componentStates: {
+          ...widgetBuilderComponents.map(
+            (key, value) => MapEntry(
+              key,
+              value.toWidgetClassDebugData(),
+            ),
+          ),
+        }.withoutNulls.entries,
+        link:
+            'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd/tab=uiBuilder&page=HeaderButtonsComponent',
+        searchReference:
+            'reference=OhZIZWFkZXJCdXR0b25zQ29tcG9uZW50UABaFkhlYWRlckJ1dHRvbnNDb21wb25lbnQ=',
+        widgetClassName: 'HeaderButtonsComponent',
+      );
+}

+ 135 - 0
lib/components/header_buttons_component_widget.dart

@@ -0,0 +1,135 @@
+import '/flutter_flow/flutter_flow_icon_button.dart';
+import '/flutter_flow/flutter_flow_theme.dart';
+import '/flutter_flow/flutter_flow_util.dart';
+import '/flutter_flow/flutter_flow_widgets.dart';
+import 'dart:ui';
+import 'package:flutter/material.dart';
+import 'package:flutter_spinkit/flutter_spinkit.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:provider/provider.dart';
+import 'header_buttons_component_model.dart';
+export 'header_buttons_component_model.dart';
+
+/// Standaard header-knoppen (drawer + terug) voor herbruik op alle pagina's
+class HeaderButtonsComponentWidget extends StatefulWidget {
+  const HeaderButtonsComponentWidget({super.key});
+
+  @override
+  State<HeaderButtonsComponentWidget> createState() =>
+      _HeaderButtonsComponentWidgetState();
+}
+
+class _HeaderButtonsComponentWidgetState
+    extends State<HeaderButtonsComponentWidget> with RouteAware {
+  late HeaderButtonsComponentModel _model;
+
+  @override
+  void setState(VoidCallback callback) {
+    super.setState(callback);
+    _model.onUpdate();
+  }
+
+  @override
+  void initState() {
+    super.initState();
+    _model = createModel(context, () => HeaderButtonsComponentModel());
+  }
+
+  @override
+  void dispose() {
+    routeObserver.unsubscribe(this);
+
+    _model.maybeDispose();
+
+    super.dispose();
+  }
+
+  @override
+  void didUpdateWidget(HeaderButtonsComponentWidget oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    _model.widget = widget;
+  }
+
+  @override
+  void didChangeDependencies() {
+    super.didChangeDependencies();
+    final route = DebugModalRoute.of(context);
+    if (route != null) {
+      routeObserver.subscribe(this, route);
+    }
+    debugLogGlobalProperty(context);
+  }
+
+  @override
+  void didPopNext() {
+    if (mounted && DebugFlutterFlowModelContext.maybeOf(context) == null) {
+      setState(() => _model.isRouteVisible = true);
+      debugLogWidgetClass(_model);
+    }
+  }
+
+  @override
+  void didPush() {
+    if (mounted && DebugFlutterFlowModelContext.maybeOf(context) == null) {
+      setState(() => _model.isRouteVisible = true);
+      debugLogWidgetClass(_model);
+    }
+  }
+
+  @override
+  void didPop() {
+    _model.isRouteVisible = false;
+  }
+
+  @override
+  void didPushNext() {
+    _model.isRouteVisible = false;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    DebugFlutterFlowModelContext.maybeOf(context)
+        ?.parentModelCallback
+        ?.call(_model);
+
+    return Align(
+      alignment: AlignmentDirectional(0.0, 0.0),
+      child: Row(
+        mainAxisSize: MainAxisSize.max,
+        children: [
+          FlutterFlowIconButton(
+            borderRadius: 8.0,
+            buttonSize: 40.0,
+            fillColor: Color(0xFFB50808),
+            icon: Icon(
+              Icons.dehaze_outlined,
+              color: FlutterFlowTheme.of(context).info,
+              size: 24.0,
+            ),
+            onPressed: () async {
+              Scaffold.of(context).openDrawer();
+            },
+          ),
+          Padding(
+            padding: EdgeInsetsDirectional.fromSTEB(4.0, 0.0, 0.0, 0.0),
+            child: FlutterFlowIconButton(
+              borderColor: Color(0x00FF0000),
+              borderRadius: 30.0,
+              borderWidth: 1.0,
+              buttonSize: 50.0,
+              fillColor: Color(0xFFB50808),
+              icon: Icon(
+                Icons.arrow_back_outlined,
+                color: Colors.white,
+                size: 30.0,
+              ),
+              onPressed: () async {
+                context.pop();
+              },
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 8 - 1
lib/login/login/login_model.dart

@@ -1,4 +1,4 @@
-import '/flutter_flow/flutter_flow_icon_button.dart';
+import '/components/header_buttons_component_widget.dart';
 import '/flutter_flow/flutter_flow_theme.dart';
 import '/flutter_flow/flutter_flow_util.dart';
 import '/flutter_flow/flutter_flow_widgets.dart';
@@ -27,6 +27,8 @@ class LoginModel extends FlutterFlowModel<LoginWidget> {
   String? Function(BuildContext, String?)? passwordFieldTextControllerValidator;
   // Model for drawerComponent component.
   late DrawerComponentModel drawerComponentModel;
+  // Model for HeaderButtonsComponent component.
+  late HeaderButtonsComponentModel headerButtonsComponentModel;
 
   final Map<String, DebugDataField> debugGeneratorVariables = {};
   final Map<String, DebugDataField> debugBackendQueries = {};
@@ -35,6 +37,8 @@ class LoginModel extends FlutterFlowModel<LoginWidget> {
   void initState(BuildContext context) {
     passwordFieldVisibility = false;
     drawerComponentModel = createModel(context, () => DrawerComponentModel());
+    headerButtonsComponentModel =
+        createModel(context, () => HeaderButtonsComponentModel());
 
     debugLogWidgetClass(this);
   }
@@ -48,6 +52,7 @@ class LoginModel extends FlutterFlowModel<LoginWidget> {
     passwordFieldTextController?.dispose();
 
     drawerComponentModel.dispose();
+    headerButtonsComponentModel.dispose();
   }
 
   @override
@@ -75,6 +80,8 @@ class LoginModel extends FlutterFlowModel<LoginWidget> {
         componentStates: {
           'drawerComponentModel (drawerComponent)':
               drawerComponentModel?.toWidgetClassDebugData(),
+          'headerButtonsComponentModel (HeaderButtonsComponent)':
+              headerButtonsComponentModel?.toWidgetClassDebugData(),
           ...widgetBuilderComponents.map(
             (key, value) => MapEntry(
               key,

+ 10 - 67
lib/login/login/login_widget.dart

@@ -1,4 +1,4 @@
-import '/flutter_flow/flutter_flow_icon_button.dart';
+import '/components/header_buttons_component_widget.dart';
 import '/flutter_flow/flutter_flow_theme.dart';
 import '/flutter_flow/flutter_flow_util.dart';
 import '/flutter_flow/flutter_flow_widgets.dart';
@@ -144,72 +144,15 @@ class _LoginWidgetState extends State<LoginWidget> with RouteAware {
             automaticallyImplyLeading: false,
             actions: [],
             flexibleSpace: FlexibleSpaceBar(
-              title: Align(
-                alignment: AlignmentDirectional(0.0, 0.0),
-                child: Row(
-                  mainAxisSize: MainAxisSize.max,
-                  children: [
-                    FlutterFlowIconButton(
-                      borderRadius: 8.0,
-                      buttonSize: 40.0,
-                      fillColor: Color(0xFFB50808),
-                      icon: Icon(
-                        Icons.dehaze_outlined,
-                        color: FlutterFlowTheme.of(context).info,
-                        size: 24.0,
-                      ),
-                      onPressed: () async {
-                        scaffoldKey.currentState!.openDrawer();
-                      },
-                    ),
-                    Padding(
-                      padding:
-                          EdgeInsetsDirectional.fromSTEB(4.0, 0.0, 0.0, 0.0),
-                      child: FlutterFlowIconButton(
-                        borderColor: Color(0x00FF0000),
-                        borderRadius: 30.0,
-                        borderWidth: 1.0,
-                        buttonSize: 50.0,
-                        fillColor: Color(0xFFB50808),
-                        icon: Icon(
-                          Icons.arrow_back_outlined,
-                          color: Colors.white,
-                          size: 30.0,
-                        ),
-                        onPressed: () async {
-                          context.pop();
-                        },
-                      ),
-                    ),
-                  ],
-                ),
-              ),
-              background: Align(
-                alignment: AlignmentDirectional(0.0, 0.0),
-                child: Padding(
-                  padding: EdgeInsetsDirectional.fromSTEB(60.0, 0.0, 5.0, 0.0),
-                  child: ClipRRect(
-                    borderRadius: BorderRadius.circular(8.0),
-                    child: Image.asset(
-                      'assets/images/logo800px.png',
-                      width: () {
-                        if (MediaQuery.sizeOf(context).width <
-                            kBreakpointSmall) {
-                          return 150.0;
-                        } else if (MediaQuery.sizeOf(context).width <
-                            kBreakpointMedium) {
-                          return 225.0;
-                        } else if (MediaQuery.sizeOf(context).width <
-                            kBreakpointLarge) {
-                          return 350.0;
-                        } else {
-                          return 400.0;
-                        }
-                      }(),
-                      fit: BoxFit.fitWidth,
-                    ),
-                  ),
-                ),
+              background: wrapWithModel(
+                model: _model.headerButtonsComponentModel,
+                updateCallback: () => safeSetState(() {}),
+                child: Builder(builder: (_) {
+                  return DebugFlutterFlowModelContext(
+                    rootModel: _model.rootModel,
+                    child: HeaderButtonsComponentWidget(),
+                  );
+                }),
               ),
               centerTitle: true,
               expandedTitleScale: 1.0,

+ 8 - 1
lib/uitgaanspaginas/p_uitgaan_page/p_uitgaan_page_model.dart

@@ -1,5 +1,5 @@
+import '/components/header_buttons_component_widget.dart';
 import '/flutter_flow/flutter_flow_ad_banner.dart';
-import '/flutter_flow/flutter_flow_icon_button.dart';
 import '/flutter_flow/flutter_flow_theme.dart';
 import '/flutter_flow/flutter_flow_util.dart';
 import '/flutter_flow/flutter_flow_widgets.dart';
@@ -18,6 +18,8 @@ class PUitgaanPageModel extends FlutterFlowModel<PUitgaanPageWidget> {
 
   // Model for drawerComponent component.
   late DrawerComponentModel drawerComponentModel;
+  // Model for HeaderButtonsComponent component.
+  late HeaderButtonsComponentModel headerButtonsComponentModel;
   // Model for PUitgaanSliderComponent component.
   late PUitgaanSliderComponentModel pUitgaanSliderComponentModel;
   // Model for UitgaantabelKaartComponent component.
@@ -29,6 +31,8 @@ class PUitgaanPageModel extends FlutterFlowModel<PUitgaanPageWidget> {
   @override
   void initState(BuildContext context) {
     drawerComponentModel = createModel(context, () => DrawerComponentModel());
+    headerButtonsComponentModel =
+        createModel(context, () => HeaderButtonsComponentModel());
     pUitgaanSliderComponentModel =
         createModel(context, () => PUitgaanSliderComponentModel());
     uitgaantabelKaartComponentModel =
@@ -40,6 +44,7 @@ class PUitgaanPageModel extends FlutterFlowModel<PUitgaanPageWidget> {
   @override
   void dispose() {
     drawerComponentModel.dispose();
+    headerButtonsComponentModel.dispose();
     pUitgaanSliderComponentModel.dispose();
     uitgaantabelKaartComponentModel.dispose();
   }
@@ -73,6 +78,8 @@ class PUitgaanPageModel extends FlutterFlowModel<PUitgaanPageWidget> {
         componentStates: {
           'drawerComponentModel (drawerComponent)':
               drawerComponentModel?.toWidgetClassDebugData(),
+          'headerButtonsComponentModel (HeaderButtonsComponent)':
+              headerButtonsComponentModel?.toWidgetClassDebugData(),
           'pUitgaanSliderComponentModel (PUitgaanSliderComponent)':
               pUitgaanSliderComponentModel?.toWidgetClassDebugData(),
           'uitgaantabelKaartComponentModel (UitgaantabelKaartComponent)':

+ 10 - 37
lib/uitgaanspaginas/p_uitgaan_page/p_uitgaan_page_widget.dart

@@ -1,5 +1,5 @@
+import '/components/header_buttons_component_widget.dart';
 import '/flutter_flow/flutter_flow_ad_banner.dart';
-import '/flutter_flow/flutter_flow_icon_button.dart';
 import '/flutter_flow/flutter_flow_theme.dart';
 import '/flutter_flow/flutter_flow_util.dart';
 import '/flutter_flow/flutter_flow_widgets.dart';
@@ -131,42 +131,15 @@ class _PUitgaanPageWidgetState extends State<PUitgaanPageWidget>
             flexibleSpace: FlexibleSpaceBar(
               title: Align(
                 alignment: AlignmentDirectional(0.0, 0.0),
-                child: Row(
-                  mainAxisSize: MainAxisSize.max,
-                  children: [
-                    FlutterFlowIconButton(
-                      borderRadius: 8.0,
-                      buttonSize: 40.0,
-                      fillColor: Color(0xFFB50808),
-                      icon: Icon(
-                        Icons.dehaze_outlined,
-                        color: FlutterFlowTheme.of(context).info,
-                        size: 24.0,
-                      ),
-                      onPressed: () async {
-                        scaffoldKey.currentState!.openDrawer();
-                      },
-                    ),
-                    Padding(
-                      padding:
-                          EdgeInsetsDirectional.fromSTEB(4.0, 0.0, 0.0, 0.0),
-                      child: FlutterFlowIconButton(
-                        borderColor: Color(0x00FF0000),
-                        borderRadius: 30.0,
-                        borderWidth: 1.0,
-                        buttonSize: 50.0,
-                        fillColor: Color(0xFFB50808),
-                        icon: Icon(
-                          Icons.arrow_back_outlined,
-                          color: Colors.white,
-                          size: 30.0,
-                        ),
-                        onPressed: () async {
-                          context.pop();
-                        },
-                      ),
-                    ),
-                  ],
+                child: wrapWithModel(
+                  model: _model.headerButtonsComponentModel,
+                  updateCallback: () => safeSetState(() {}),
+                  child: Builder(builder: (_) {
+                    return DebugFlutterFlowModelContext(
+                      rootModel: _model.rootModel,
+                      child: HeaderButtonsComponentWidget(),
+                    );
+                  }),
                 ),
               ),
               background: Align(