mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-11 18:14:02 +01:00
739 -> 249 lines. As with note_editor, the ~600-line State class needed
decomposing rather than moving:
capture_draft.dart the note being captured and its write-through
to storage -- the model behind "every keystroke
is already persisted". Lazy row creation stays
here; the screen just logs that it happened.
capture_sync_runner.dart one sync pass, with no BuildContext. This also
de-duplicates the two callers: the manual button
and the background tick ran byte-identical
runSync blocks differing only in the snackbar
and the 'auto' log flag.
capture_status.dart SyncStatusStore (the persisted last outcome) and
describeSyncResult.
capture_app_bar.dart the app bar.
capture_meta_row.dart the priority/status pickers.
capture_status_footer.dart the two status lines.
capture_screen_{widget,sync}.dart
parts, for the same reason as note_editor's.
The mounted checks are preserved exactly, including the one in
SyncStatusStore.restore that must fire AFTER its await rather than before
(writing the notifier post-dispose is the bug it exists to prevent), which
is why it takes a stillLive callback instead of a bool.
Verified: 313 tests pass, analyze clean, every capture file at 100%
coverage. lib/ and bin/ are now down to three files over the cap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
65 lines
2.7 KiB
Dart
65 lines
2.7 KiB
Dart
/// The [CaptureScreen] widget's public surface: its parameters and their
|
|
/// contracts. The state that drives them lives in `capture_screen.dart`.
|
|
///
|
|
/// A `part` rather than a separate library because `createState` returns a
|
|
/// private class, so the widget and its State cannot be split across
|
|
/// libraries.
|
|
part of 'capture_screen.dart';
|
|
|
|
/// The landing screen: an always-focused text box for jotting an idea.
|
|
///
|
|
/// Per the product goal "no interruptions, immediate", text is persisted
|
|
/// to local storage on *every* keystroke. A note row is created lazily on
|
|
/// the first character typed, then updated in place. The "new note" action
|
|
/// finalises the current idea and clears the field for the next one.
|
|
class CaptureScreen extends StatefulWidget {
|
|
/// Creates a [CaptureScreen] backed by [repository].
|
|
const CaptureScreen({
|
|
required this.repository,
|
|
required this.appSettings,
|
|
this.analytics,
|
|
this.httpClient,
|
|
this.localBackup,
|
|
this.firebaseFactory,
|
|
this.stateStore,
|
|
super.key,
|
|
});
|
|
|
|
/// The store the captured note is persisted to on every keystroke.
|
|
final NoteRepository repository;
|
|
|
|
/// App-wide preferences, currently just `advancedMode`: whether the
|
|
/// priority/status row and the routine save/sync status line are shown.
|
|
/// A sync failure is always surfaced regardless of this flag.
|
|
final ValueNotifier<AppSettings> appSettings;
|
|
|
|
/// Interaction-only usage analytics (taps, navigation, sync outcomes —
|
|
/// never note text). Null in tests that don't exercise it, so the prefs
|
|
/// round-trip `logEvent` does on every call never has to be awaited by a
|
|
/// test that didn't ask for it.
|
|
final AnalyticsService? analytics;
|
|
|
|
/// Builds the Firebase backend. Injected so tests can supply a fake, or
|
|
/// null to assert the pre-migration GitHub-only path still works.
|
|
final Future<FirebaseRestClient?> Function()? firebaseFactory;
|
|
|
|
/// Revision cache. Injected so tests need no application-support directory.
|
|
final SyncStateStore? stateStore;
|
|
|
|
/// Injectable HTTP client for the sync path. Production leaves this null
|
|
/// (the GitHubClient creates its own); tests pass a mock so the configured
|
|
/// sync flow can be exercised without real network access.
|
|
final http.Client? httpClient;
|
|
|
|
/// Injectable local-disk backup. Production leaves this null (a platform
|
|
/// file-backed instance is created); tests pass a fake with in-memory IO.
|
|
final LocalBackup? localBackup;
|
|
|
|
/// How long focus must stay lost before a background sync fires. Public so
|
|
/// tests can pump exactly past it.
|
|
static const autoSyncDebounce = Duration(seconds: 5);
|
|
|
|
@override
|
|
State<CaptureScreen> createState() => _CaptureScreenState();
|
|
}
|