Files
ingtrakapp/lib/widgets/skip_build_when_covered.dart
T
2026-09-10 17:23:07 +02:00

64 lines
1.7 KiB
Dart

/// Skips building while another route covers this one, then rebuilds on pop.
library;
import 'package:flutter/material.dart';
/// Shared observer — register on [MaterialApp.navigatorObservers].
final RouteObserver<ModalRoute<void>> appRouteObserver =
RouteObserver<ModalRoute<void>>();
/// Builds via [builder] only when this route is not covered by a pushed page.
///
/// Only [PageRoute]s count as covering (via [RouteAware]). Modal bottom sheets
/// and dialogs must not tear down the subtree — async flows started from Home
/// (e.g. compose widget → name → options) need a mounted context between steps.
class SkipBuildWhenCovered extends StatefulWidget {
const SkipBuildWhenCovered({
super.key,
required this.builder,
this.placeholder = const SizedBox.expand(),
});
final WidgetBuilder builder;
final Widget placeholder;
@override
State<SkipBuildWhenCovered> createState() => _SkipBuildWhenCoveredState();
}
class _SkipBuildWhenCoveredState extends State<SkipBuildWhenCovered>
with RouteAware {
var _covered = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final route = ModalRoute.of(context);
if (route is PageRoute) {
appRouteObserver.subscribe(this, route);
}
}
@override
void dispose() {
appRouteObserver.unsubscribe(this);
super.dispose();
}
@override
void didPushNext() {
if (!_covered) setState(() => _covered = true);
}
@override
void didPopNext() {
if (_covered) setState(() => _covered = false);
}
@override
Widget build(BuildContext context) {
if (_covered) return widget.placeholder;
return widget.builder(context);
}
}