import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../core/providers.dart'; class AutoRefresh extends ConsumerStatefulWidget { const AutoRefresh({super.key, required this.location, required this.child}); final String location; final Widget child; static const pollEvery = Duration(seconds: 60); static const gap = Duration(seconds: 30); static const resumeGap = Duration(seconds: 30); @override ConsumerState createState() => _AutoRefreshState(); } class _AutoRefreshState extends ConsumerState with WidgetsBindingObserver { Timer? _poll, _cool, _resumeCool; static const _lists = ['/results', '/shops', '/orders', '/users']; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); _poll = Timer.periodic(AutoRefresh.pollEvery, (_) => _onPoll()); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); _poll?.cancel(); _cool?.cancel(); _resumeCool?.cancel(); super.dispose(); } bool get _onList => _lists.contains(widget.location); bool get _visible { final s = WidgetsBinding.instance.lifecycleState; return s == null || s == AppLifecycleState.resumed; } // False while a sheet or dialog sits on top of the screen. bool get _uncovered => ModalRoute.of(context)?.isCurrent ?? true; bool get _signedIn => ref.read(sessionProvider) != null; void _reload() => ref.read(dataVersionProvider.notifier).bump(); void _onPoll() { if (_cool != null || !_visible || !_signedIn || !_uncovered || widget.location != '/orders') { return; } _reload(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state != AppLifecycleState.resumed) return; if (_resumeCool != null || !_signedIn || !_onList || !_uncovered) return; _reload(); _resumeCool = Timer(AutoRefresh.resumeGap, () => _resumeCool = null); } @override Widget build(BuildContext context) { // Every reload, whoever started it, restarts the quiet period. ref.listen(dataVersionProvider, (_, _) { _cool?.cancel(); _cool = Timer(AutoRefresh.gap, () => _cool = null); }); return widget.child; } }