From f4272d01b9d2797cb743156bae9c305c4b916b42 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Fri, 14 Aug 2026 23:09:24 +0200 Subject: [PATCH] Route todo's snackbars through the shared showToast/showError The package shipped feedback helpers while todo still had a private _showSnack and a raw SnackBar in note_editor -- exactly the duplication the extraction was meant to end, left live in a repo that had just adopted the package. Two deliberate behaviour changes come with it: the duration goes 2s -> 3s for toasts and 5s for errors (an error the user missed is an error they will hit again), and messages now replace rather than queue, since a queued snackbar describes an action the user moved on from seconds ago. No test asserted on either, and the one snackbar assertion in the suite checks that capture is *not* interrupted by one, which still holds. Failures now read as failures: the mode-switch rejection in note_editor and a failed sync in capture_screen use showError, while a successful sync and the not-configured hint stay neutral toasts. Spending the danger hue on routine confirmations is how a real failure becomes invisible. Verified: flutter analyze clean, 308 tests pass at 100% coverage (1964/1964). The release APK built and installed, but on-device re-verification could not complete: the 23:00 night curfew removed the package ~80ms after install, because dev.kuhy.todo is in the focus-mode day WHITELIST but not NIGHT_WHITELIST. Enforcer working as designed, not an app fault -- reverify after 05:00. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01XS1m7b1piBtAL22USLW6jL --- lib/ui/capture_screen.dart | 2 ++ lib/ui/capture_screen_sync.dart | 16 ++++++++++++---- lib/ui/note_editor.dart | 11 ++++------- pubspec.yaml | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/ui/capture_screen.dart b/lib/ui/capture_screen.dart index 58b75e2..956c1d2 100644 --- a/lib/ui/capture_screen.dart +++ b/lib/ui/capture_screen.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:crdt_sync/crdt_sync.dart'; +import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:todo/analytics/analytics_event.dart'; @@ -221,6 +222,7 @@ class _CaptureScreenState extends State outcome.ok ? 'Synced: ${outcome.detail}' : 'Sync failed: ${outcome.detail}', + isError: !outcome.ok, ); } finally { if (mounted) setState(() => _syncing = false); diff --git a/lib/ui/capture_screen_sync.dart b/lib/ui/capture_screen_sync.dart index e369ad7..96bc22a 100644 --- a/lib/ui/capture_screen_sync.dart +++ b/lib/ui/capture_screen_sync.dart @@ -64,11 +64,19 @@ extension _CaptureSyncBehaviour on _CaptureScreenState { ); } - void _showSnack(String message) { + /// Shows transient feedback, if this screen is still mounted. + /// + /// Delegates to the shared helpers so the styling and the + /// replace-don't-queue behaviour match every other app; [isError] picks + /// the danger hue and the longer duration, because an error the user + /// missed is an error they will hit again. + void _showSnack(String message, {bool isError = false}) { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(message), duration: const Duration(seconds: 2)), - ); + if (isError) { + showError(context, message); + } else { + showToast(context, message); + } } /// Reloads the persisted last-sync outcome so the status line survives a diff --git a/lib/ui/note_editor.dart b/lib/ui/note_editor.dart index e16a25f..bc70c16 100644 --- a/lib/ui/note_editor.dart +++ b/lib/ui/note_editor.dart @@ -1,3 +1,4 @@ +import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:todo/data/note.dart'; @@ -111,13 +112,9 @@ class _NoteEditorState extends State { case NoteEditorMode.guided: // raw -> guided: only if the edited text still fits the template. if (!_doc.tryAdoptGuided()) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - "Text doesn't match the template — staying in raw", - ), - duration: Duration(seconds: 2), - ), + showError( + context, + "Text doesn't match the template — staying in raw", ); return; } diff --git a/pubspec.yaml b/pubspec.yaml index 9ecbcb2..f9fe5c4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.23+1 +version: 1.0.24+1 environment: sdk: ^3.12.2