# halkyon_app What every Halkyon app (Learn, Todo, Train) is built around, on an instance's `halkyon_base` module: the instances a device keeps an account on, signing in, each person's data opened and closed, and syncing it. Taken from Halkyon Learn, which it was written for, so it behaves as Learn's own did; the texts are in British English, American English and German, and where they name the app, they name yours. Written as the apps are: Dart 3.13's primary constructors, Material from `package:material_ui`, Lucide icons, blocs (`flutter_bloc`), LeanCode's lints. ## What it holds - **Instances** (`lib/src/instance/`): `Instance` (an address as people type it), `InstanceChoice` (those the device keeps an account on, one in use; `FileInstanceStore`), `InstanceStorage` (each instance's people's folders and session key), `InstanceChecker` (does an address answer, where does it keep people's data; `ServerpodInstanceChecker` asks its `instance.basics()`), `InstanceScope`. The screens: `FirstStartScreen` (the build's instance and another, as tiles, `InstanceTile`), `InstanceStep` (an address, checked), `showAccountSwitcher` and `AddAccountScreen`, and where an instance keeps people's data, as a flag and words (`InstanceLocationBuilder`, `InstanceFlag`, `instanceLocationWords`): `EU`, a country or a subdivision (ISO 3166-2, `US-CA`) as its operator says, "Germany (EU)" for a member of the European Union (`europeanUnionMembers`) and "California, United States" for a subdivision, with the most specific flag there is (a few subdivisions have their own, such as Scotland; else the country's). Countries are named by the app's `CountryNames`, subdivisions by Unicode CLDR's names in English and German, which come with the package (`AssetSubdivisionNames`; the package's `tool/subdivision_names.py` writes them). - **Gates** (`lib/src/app/`): `InstanceGate` opens the app's dependencies on the instance in use (`AppDependencies`, handed down by `AppScope`), anew on a switch, the previous ones closed first; `SessionGate` keeps a person signed in, signing in anonymously at a first start and asking how to start once signed out (`StartScreen`); `PersonScope` opens each person's own dependencies and closes them when the person goes. - **Signing in** (`lib/src/auth/`): `AuthRepository` on an `AuthGateway`; `ServerpodAuthGateway` signs in anonymously, with GitHub (the system browser and a loopback address on Linux and Windows, `LoopbackWebAuth`) and with a code by mail, through the instance's `halkyon_base`; `SessionBloc`, `GitHubSignInBloc`, `EmailSignInBloc` (with `showEmailSignInSheet`) and `SignInWaysCubit`; `SignedOutMark`, `SignInAddresses`, `PersonFolders`. - **Sync** (`lib/src/sync/`): `SyncService` (once at start, shortly after local changes, on resume and every few minutes, one sync at a time, counting the changes not on the server yet, `PendingChangesStore`), `AppCompatibility` and `compatibleSync` (the instance's minimum app build, the engine's table check), `SyncStatusBloc`, `syncAndWait`, and the widgets: `SyncStatusCard`, `AppMismatchBanner`, `SyncTroubleBadge`. - **A client of `halkyon_base` alone** (`BaseClient`): to ask an instance about itself, and to sign in as another person than the app's client holds. - **Testing** (`package:halkyon_app/testing.dart`): fakes of every boundary (`FakeAuthGateway`, `FakeInstanceChecker`, the stores in memory), a frame (`testFrame`), `testApp`, and `TestAppDependencies`. ## Using it in an app 1. **The server** includes `halkyon_base` with the nickname `base` (its README), so the app's generated client has `client.modules.base`. 2. **Depend on it** by path, within the repository's workspace, as on `halkyon_ui`: ```yaml dependencies: halkyon_app: path: ../../../packages/halkyon_app ``` 3. **Texts**: add `HalkyonAppLocalizations.delegate` to every `MaterialApp`'s delegates, beside `HalkyonUiLocalizations.delegate` and material_ui's `GlobalMaterialLocalizations.delegates`. 4. **The frame** (`AppFrame`): the app's name and wordmark word, its icon, an example address, its theme, delegates, languages and launch screen, and the two sentences only it can say: what the first start's instance keeps of the person's, and what a switch to another account leaves behind. 5. **The dependencies**: the app's composition root implements `AppDependencies
` (`serverName`, `auth`, `signedOut`, `openPerson`,
`dispose`), its person's dependencies `Disposable`. Its `auth` is an
`AuthRepository` on `ServerpodAuthGateway(client, base:
client.modules.base, callbackScheme: …, appName: …)`; the scheme is the
app's own (`app.halkyon.learn`), registered with each platform and in the
instance's GitHub OAuth app, whose loopback address on Linux and Windows is
`http://127.0.0.1/github-callback` (port 43823 unless given).
6. **The tree**:
```dart
InstanceGate(
frame: frame,
choice: choice,
checker: ServerpodInstanceChecker(app: 'todo'),
countryNames: …,
readLook: …, // the device's theme mode and language
open: Dependencies.create,
app: SessionGate(
look: (context) => …,
app: (person) => PersonApp(person: person), // with PersonScope inside
),
)
```
A person's widgets find their dependencies with
`PersonScope.of