mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-10 20:27:01 +01:00
Hide priority/status/template/mode chrome and routine sync-status text behind a Firebase-synced "Enable advanced" setting (default off); remove the Capture title and Save button in favor of autosave + a plain reset icon; sort notes by priority then recency; add interaction-only usage analytics buffered locally and flushed to Firebase alongside note sync. Code review (self + follow-up verification pass) found and fixed 3 real bugs during this work: a widget-key placement bug that discarded an in-progress draft when advancedMode was toggled mid-typing, a data-loss bug in the analytics buffer's flush-and-clear logic under concurrent cap-eviction, and two spots where an expired/wrong-account Firebase session (FirebaseAuthError) escaped a narrower catch clause and would have failed an otherwise-successful sync pass. Also fixes an unrelated pre-existing test-isolation bug in wrapper_server_test.dart, which was reading the real ~/.config/todo/firebase_auth.json instead of a test-scoped path. 320 tests, 100% line coverage on all touched files (one pre-existing, out-of-scope 5-line gap in settings_screen.dart unrelated to this change). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 lines
1.7 KiB
Dart
52 lines
1.7 KiB
Dart
/// A single, structured analytics event.
|
|
///
|
|
/// Interaction-only by construction: [params] holds enum values, counts,
|
|
/// durations and booleans — never note text or other free-form user input.
|
|
/// Callers are trusted to uphold that; see `analytics_service.dart` for the
|
|
/// full policy.
|
|
class AnalyticsEvent {
|
|
/// Creates an [AnalyticsEvent] with the given [name], [params] and
|
|
/// [timestamp].
|
|
const AnalyticsEvent({
|
|
required this.name,
|
|
required this.timestamp,
|
|
this.params = const {},
|
|
});
|
|
|
|
/// Short, stable event identifier, e.g. `'screen_view'`, `'sort_changed'`.
|
|
final String name;
|
|
|
|
/// When the event happened.
|
|
final DateTime timestamp;
|
|
|
|
/// Structured parameters. Values must be JSON-encodable primitives
|
|
/// (String, num, bool, or null) — never note text.
|
|
final Map<String, Object?> params;
|
|
|
|
/// Serializes to a JSON-encodable map for local buffering and the
|
|
/// Firebase flush.
|
|
Map<String, Object?> toJson() => {
|
|
'name': name,
|
|
'timestamp': timestamp.toIso8601String(),
|
|
'params': params,
|
|
};
|
|
|
|
/// Reconstructs an [AnalyticsEvent] from [toJson]'s output. Returns null
|
|
/// for a malformed entry (e.g. a buffer corrupted by a previous crash)
|
|
/// rather than throwing — analytics must never crash capture.
|
|
static AnalyticsEvent? tryFromJson(Object? json) {
|
|
if (json is! Map) return null;
|
|
final name = json['name'];
|
|
final timestamp = DateTime.tryParse('${json['timestamp']}');
|
|
final params = json['params'];
|
|
if (name is! String || timestamp == null) return null;
|
|
return AnalyticsEvent(
|
|
name: name,
|
|
timestamp: timestamp,
|
|
params: params is Map
|
|
? Map<String, Object?>.from(params)
|
|
: const <String, Object?>{},
|
|
);
|
|
}
|
|
}
|