utils/sync_settings_ui
Krzysztof kuhy Rudnicki 7096c102cd
Some checks are pending
crdt_sync_dart tests / test (push) Waiting to run
crdt_sync_flutter tests / test (push) Waiting to run
crdt-sync pre-commit / pre-commit (push) Waiting to run
crdt-sync tests / test (push) Waiting to run
dependency freshness / dependencies on newest stable (push) Waiting to run
design_system tests / test (push) Waiting to run
file length / file-length (push) Waiting to run
freedays pre-commit / pre-commit (push) Waiting to run
freedays tests / test (push) Waiting to run
gatelock pre-commit / pre-commit (push) Waiting to run
gatelock tests / test (push) Waiting to run
github_device_auth tests / test (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
music_theory tests / test (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
sync_settings_ui tests / test (push) Waiting to run
web_ui tests / test (push) Waiting to run
Re-point paths for the ~ reorganisation (home-tidy)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
2026-09-11 18:45:55 +02:00
..
lib Fix two long-red CI gates: palette_check path after md rename, file-length in sync_settings_ui 2026-08-28 12:36:41 +02:00
scripts Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:45:55 +02:00
test Fix two long-red CI gates: palette_check path after md rename, file-length in sync_settings_ui 2026-08-28 12:36:41 +02:00
.gitignore Add sync_settings_ui: shared Firebase-only sync settings screen 2026-08-12 23:10:17 +02:00
.pre-commit-config.yaml Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:45:55 +02:00
analysis_options.yaml sync_settings_ui: split sync_settings_screen.dart 382 -> 192 2026-08-22 15:38:58 +02:00
pubspec.yaml Move the two in-repo consumers onto crdt_sync_dart-v0.11.1 2026-08-28 14:08:28 +02:00
README.md Extract the Flutter sync glue into crdt_sync_flutter, and document it 2026-08-22 17:26:34 +02:00

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

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 provides all of them, so the two fit together directly:

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

flutter pub get
flutter analyze
flutter test