mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 20:07:18 +01:00
`crdt_sync` is pure Dart so it can run from CLI tools and headless systemd jobs, which means it takes closures instead of depending on flutter_secure_storage and google_sign_in. Every Flutter app then wrote the same ~390 lines to supply them, and five apps ended up carrying near-identical copies of firebase_backend.dart. Those copies drifted. `todo` gained an opt-out flag and a seeded-session path that home_inventory and wake_alarm never received, so the same bug was fixed in one copy and left live in the others -- which is the actual cost being paid here, not the line count. This package owns that glue once: the keystore adapter, the persisted per-install device id, the account store and a one-call bootstrap. A new app needs a SyncApp const and `openSync(kApp)`. The wrapper routes are a parameter rather than a constant, because todo's copy hardcoded its own `~/.config/todo/firebase_auth.json`. An extraction only one app could adopt would be worse than the copies. Also documents what made this hard to find: crdt_sync_dart's README covered only the *old* GitHub transport and never mentioned the Firebase surface at all, and sync_settings_ui -- a complete drop-in settings screen -- had no README whatsoever. The five existing apps stay on their copies and on crdt_sync_dart-v0.10.0. Migration is forward-only and those fallbacks are load-bearing; converging them is a separate task, and the README says so. 35 tests, 100% line coverage, no suppressions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CFSGeWxHPY5rHUGrPqhcmG
81 lines
2.6 KiB
Markdown
81 lines
2.6 KiB
Markdown
# sync_settings_ui
|
|
|
|
The shared **Sync settings** screen: Firebase sign-in (email/password or
|
|
Google one-tap), Disconnect, a live status line, and an optional Backup
|
|
section. Reused across every one of kuhy's Flutter apps that syncs, so the
|
|
screen behaves identically everywhere and is fixed in one place.
|
|
|
|
Generalized from the near-identical `_connectFirebase` / `_connectGoogle` /
|
|
`_disconnectFirebase` / `_load` logic that had been duplicated into every
|
|
app's settings screen.
|
|
|
|
## Install
|
|
|
|
```yaml
|
|
dependencies:
|
|
sync_settings_ui:
|
|
git:
|
|
url: https://github.com/kuhyx/utils
|
|
ref: sync_settings_ui-v0.1.0
|
|
path: sync_settings_ui
|
|
```
|
|
|
|
## Usage
|
|
|
|
This package **never touches `flutter_secure_storage` or `google_sign_in`
|
|
itself** — every keystore read/write and every platform sign-in arrives as an
|
|
already-built closure. [`crdt_sync_flutter`](../crdt_sync_flutter) provides
|
|
all of them, so the two fit together directly:
|
|
|
|
```dart
|
|
import 'package:crdt_sync_flutter/crdt_sync_flutter.dart';
|
|
import 'package:sync_settings_ui/sync_settings_ui.dart';
|
|
|
|
SyncSettingsScreen(
|
|
accountLoader: () => loadAccount(),
|
|
accountSaver: saveAccount,
|
|
accountClearer: clearAccount,
|
|
sessionProbe: () => isSyncConfigured(kApp),
|
|
firebaseFactory: () => openSync(kApp),
|
|
googleFirebaseFactory: () => signInWithGoogle(
|
|
kApp,
|
|
tokenFetcher: googleIdToken, // the app's own google_sign_in call
|
|
),
|
|
googleAvailable: googleSignInSupported,
|
|
backup: BackupSlot(label: 'notes', export: _export, import: _import),
|
|
)
|
|
```
|
|
|
|
Pass `backup: null` to omit the Backup section entirely.
|
|
|
|
## What it gets right, so you don't re-derive it
|
|
|
|
**"Connected" means the session probe says so** — never that a factory
|
|
returned a non-null client. `FirebaseSyncController` returns a
|
|
`FirebaseConnectResult` carrying a six-case outcome:
|
|
|
|
| Outcome | Meaning |
|
|
|---|---|
|
|
| `connected` | Signed in, and the probe confirms a live session. |
|
|
| `rejected` | The credentials were refused. |
|
|
| `cancelled` | The user dismissed the picker. |
|
|
| `signedInButNotPersisted` | Sign-in worked; nothing durable was stored. |
|
|
| `wrongAccount` | Authenticated as a uid the rules do not allow. |
|
|
| `failed` | Anything else. |
|
|
|
|
`signedInButNotPersisted` and `wrongAccount` exist because both looked
|
|
identical to success from the call site and both produced a device that
|
|
appeared connected and synced nothing.
|
|
|
|
**The Google button is double-gated** on `supportsGoogle && googleAvailable`,
|
|
so a button that cannot possibly succeed is never rendered — a visible control
|
|
that always reports "cancelled" is worse than no control.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
flutter pub get
|
|
flutter analyze
|
|
flutter test
|
|
```
|