// 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! // Set your widget name, define your parameter, and then add the // boilerplate code using the `` button on the right! import 'package:go_router/go_router.dart'; // ⬇⬇⬇ PLAK VANAF HIER ⬇⬇⬇ /// Toont een melding zodra de server onbereikbaar is. /// /// Het widget zelf neemt **geen ruimte** in de layout in (`SizedBox.shrink`): /// de header van dit project zit in een `FlexibleSpaceBar.background` met een /// vaste hoogte, dus een balk die wél ruimte vraagt geeft daar gegarandeerd een /// RenderFlex-overflow. In plaats daarvan gaat de melding via de /// `ScaffoldMessenger` over de pagina heen. Daardoor kan het widget op één /// plek in de gedeelde header staan en werkt het op elke pagina. /// /// 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. 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 createState() => _VerbindingsBannerState(); } class _VerbindingsBannerState extends State { // Statisch, dus gedeeld over alle instanties: bij doorklikken tussen // pagina's wordt niet bij elke opbouw opnieuw een verzoek gedaan, en er // verschijnt nooit meer dan één balk tegelijk. static DateTime? _laatsteCheck; static const Duration _minimaalTussenChecks = Duration(seconds: 20); static bool _balkStaatAl = false; bool _bezig = false; @override void initState() { super.initState(); FFAppState().addListener(_bijStateWijziging); WidgetsBinding.instance.addPostFrameCallback((_) async { await _checkIndienNodig(); _werkBalkBij(); }); } @override void dispose() { FFAppState().removeListener(_bijStateWijziging); super.dispose(); } void _bijStateWijziging() { if (mounted) _werkBalkBij(); } void _werkBalkBij() { final messenger = ScaffoldMessenger.maybeOf(context); if (messenger == null) return; if (!FFAppState().geenVerbinding) { if (_balkStaatAl) { _balkStaatAl = false; messenger.hideCurrentSnackBar(); } return; } if (_balkStaatAl) return; _balkStaatAl = true; messenger .showSnackBar( SnackBar( backgroundColor: FlutterFlowTheme.of(context).primary, // Praktisch oneindig: de balk hoort te blijven staan zolang er // geen verbinding is, niet na een paar seconden te verdwijnen. duration: const Duration(days: 1), content: 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 met uitgaanskrant.com', style: const TextStyle(color: Colors.white, fontSize: 13.0), ), ), ], ), action: SnackBarAction( // Bewust een vast label: een SnackBar bouwt niet opnieuw op, dus // een status-afhankelijke tekst blijft hangen op de stand van het // moment waarop hij getoond werd. label: 'Opnieuw', textColor: Colors.white, onPressed: _check, ), ), ) .closed .then((_) { // Ook als de gebruiker hem zelf wegveegt, mag er later weer één komen. _balkStaatAl = false; }); } Future _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 _check({bool herlaadBijHerstel = true}) async { if (_bezig) return; _bezig = true; _laatsteCheck = DateTime.now(); bool bereikbaar = false; try { bereikbaar = await checkVerbinding(); } finally { _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) { // Neemt bewust geen ruimte in: de melding gaat via de ScaffoldMessenger. return const SizedBox.shrink(); } }