import 'dart:async'; import 'package:halkyon_app/l10n/halkyon_app_localizations.dart'; import 'package:halkyon_app/src/app/app_frame.dart'; import 'package:halkyon_app/src/app/app_scope.dart'; import 'package:halkyon_app/src/auth/model/auth_status.dart'; import 'package:material_ui/material_ui.dart'; /// Opens [person]'s dependencies (`AppDependencies.openPerson`), shows /// [child] with them, and disposes them when it goes away. `SessionGate` /// gives every person a new `PersonScope`. class const PersonScope({ /// Whose dependencies these are. required final SignedIn person, /// What the person sees. required final Widget child, super.key, }) extends StatefulWidget { /// The dependencies of the person signed in above [context], as the app's /// own type [P] (`PersonScope.of(context)`). static P of

(BuildContext context) { final scope = context .getInheritedWidgetOfExactType<_PersonDependenciesScope>(); assert(scope != null, 'No PersonScope above this widget.'); return scope!.dependencies as P; } @override State createState() => _PersonScopeState(); } class _PersonScopeState() extends State { Future? _opening; @override void didChangeDependencies() { super.didChangeDependencies(); _opening ??= AppScope.of(context).openPerson(widget.person); } @override void dispose() { unawaited( _opening?.then( (dependencies) => dependencies.dispose(), // Opening failed and said so on screen; there is nothing to close. onError: (Object _) {}, ), ); super.dispose(); } @override Widget build(BuildContext context) => FutureBuilder( future: _opening, builder: (context, snapshot) => switch (snapshot) { AsyncSnapshot(:final data?) => _PersonDependenciesScope( dependencies: data, child: widget.child, ), AsyncSnapshot(hasError: true) => Scaffold( body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(HalkyonAppLocalizations.of(context).personDataFailed), const SizedBox(height: 16), FilledButton( onPressed: () => setState(() { _opening = AppScope.of(context).openPerson(widget.person); }), child: Text(HalkyonAppLocalizations.of(context).tryAgain), ), ], ), ), ), _ => AppFrameScope.of(context).launchScreen, }, ); } class const _PersonDependenciesScope({ required final Disposable dependencies, required super.child, }) extends InheritedWidget { @override bool updateShouldNotify(_PersonDependenciesScope oldWidget) => dependencies != oldWidget.dependencies; }