import 'package:flutter/widgets.dart'; import 'package:halkyon_app/src/auth/data/auth_repository.dart'; import 'package:halkyon_app/src/auth/data/signed_out_mark.dart'; import 'package:halkyon_app/src/auth/model/auth_status.dart'; import 'package:halkyon_app/src/files/file_saver.dart'; import 'package:halkyon_app/src/password/data/password_repository.dart'; /// What can be closed once it is no longer needed: an app's dependencies on /// an instance, or a person's. abstract interface class Disposable() { /// Closes it; nothing of it is used afterwards. Future dispose(); } /// What this package needs of an app's dependencies on one instance (its /// composition root), which `InstanceGate` opens for the instance in use and /// [AppScope] hands down. An app's own class implements it beside its /// features' repositories. abstract interface class AppDependencies

() implements Disposable { /// The instance's name as people know it (its host), for messages about /// it. String get serverName; /// Who is signed in, and signing in and out. AuthRepository get auth; /// Whether the person here signed out, so the app asks how to start. SignedOutMark get signedOut; /// Signing in with a password and TOTP, signing up, getting back in, and /// what keeps an account (ADR 0017). PasswordRepository get passwords; /// Keeps a file the app made where the person chooses (a recovery phrase, /// recovery codes, an app's exports). FileSaver get fileSaver; /// Where the source of what the instance runs is, as it names it (its /// basics, halkyon_base's): both licences require offering it to the /// people who use the instance, which About does (`showAppAbout`). Future sourceCodeUrl(); /// Opens the dependencies of [person], once the previous person's have /// closed; `PersonScope` disposes them when the person goes. Future

openPerson(SignedIn person); } /// Hands an app's [dependencies] on the instance in use down the widget /// tree; `InstanceGate` puts it above the app. class const AppScope({ /// The app's dependencies. required final AppDependencies dependencies, required super.child, super.key, }) extends InheritedWidget { /// The dependencies above [context], as the app's own type [D] /// (`AppScope.of(context)`), or as [AppDependencies] where /// that is all that is needed. /// /// Doesn't register [context] for rebuilds: the dependencies of one app run /// never change. static D of>(BuildContext context) { final scope = context.getInheritedWidgetOfExactType(); assert(scope != null, 'No AppScope above this widget.'); return scope!.dependencies as D; } @override bool updateShouldNotify(AppScope oldWidget) => dependencies != oldWidget.dependencies; }