| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- // 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<VerbindingsBanner> createState() => _VerbindingsBannerState();
- }
- class _VerbindingsBannerState extends State<VerbindingsBanner> {
- // 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<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;
- _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();
- }
- }
|