mirror of
https://github.com/kuhyx/wake-alarm.git
synced 2026-11-10 19:27:02 +01:00
- Sick days screen (own name, sick icon, cat-2 fill): tap today or a later day to mark it sick, tap again to clear; past days inert. Writes the sickdays wire format (state sick/cleared + actor, one HLC per write) to sickdays-sync/devices via crdt_sync syncLog. - Mutual exclusion in both pickers: each syncs the other pool on open and refuses a date it holds, naming the pool; an unreadable pool refuses all. - Native SickDays cache (fail closed via DayCache); AlarmReceiver skips the ring with reason "sick_day" (no markFired, no ring_started); StickCheck verdict sick_day, streak skips sick days; stakes card says so. - Pre-alarm pool sync: allow-while-idle alarm at 21:00 and A-30 (request code 1006) runs a headless engine (poolSyncMain) that pulls both pools from RTDB and rewrites both native caches, so a PC mark arrives with the app closed. The ring decision stays a cache read. - JVM unit tests (JUnit 4.13.2) for DayCache, RingDecision, PoolSyncSchedule, StickCheck; Dart tests; Dart->Python interop check. pylint hook skipped: verify.py imports sickdays, not in the hook env until the sickdays-v0.1.0 tag exists; run by hand in a sickdays venv (10.00/10). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xfj1sxKH9VBPqpcAni8Jry
77 lines
2.3 KiB
Dart
77 lines
2.3 KiB
Dart
import 'dart:developer' as developer;
|
|
|
|
import 'package:crdt_sync/crdt_sync.dart';
|
|
|
|
/// One pull/merge/push tick for a day pool (free days, sick days), then a
|
|
/// refresh of that pool's native ring-path cache.
|
|
///
|
|
/// Shared by `FreeDaySync` and `SickDaySync`, which differ only in where
|
|
/// the log lives and which cache it feeds. Firebase only: neither namespace
|
|
/// ever had a GitHub mirror.
|
|
///
|
|
/// Returns a status line for the screen. Never throws: this also runs
|
|
/// unattended (app launch, the pre-alarm sync), where a dead network must
|
|
/// degrade to a message. [publish] runs whatever happened, so a day marked
|
|
/// offline still reaches the ring path.
|
|
Future<String> syncDayPoolLog({
|
|
required Future<RemoteStore?> Function() openClient,
|
|
required String deviceId,
|
|
required String pathPrefix,
|
|
required String filename,
|
|
required String commitMessage,
|
|
required Log Function() snapshot,
|
|
required Future<void> Function(Log merged) replaceAll,
|
|
required Future<void> Function() publish,
|
|
required String logName,
|
|
}) async {
|
|
final RemoteStore? client;
|
|
try {
|
|
client = await openClient();
|
|
} on Object catch (error, stackTrace) {
|
|
developer.log(
|
|
'could not open Firebase',
|
|
name: logName,
|
|
error: error,
|
|
stackTrace: stackTrace,
|
|
);
|
|
await publish();
|
|
return 'Error: $error';
|
|
}
|
|
if (client == null) {
|
|
await publish();
|
|
return 'Not synced — connect Firebase in Settings.';
|
|
}
|
|
try {
|
|
final merged = await syncLog(
|
|
client: client,
|
|
deviceId: deviceId,
|
|
pathPrefix: pathPrefix,
|
|
filename: filename,
|
|
localLog: snapshot(),
|
|
encode: logToJson,
|
|
decode: logFromJson,
|
|
commitMessage: commitMessage,
|
|
);
|
|
await replaceAll(merged);
|
|
return 'Synced ✓';
|
|
} on Exception catch (e) {
|
|
return 'Error: $e';
|
|
} finally {
|
|
await publish();
|
|
}
|
|
}
|
|
|
|
/// Runs [write] (a native-cache write) and swallows a missing platform:
|
|
/// widget tests and probe entry points have no channel, the Dart pool is
|
|
/// still correct, and the cache is rewritten on the next sync anyway.
|
|
Future<void> publishQuietly(
|
|
Future<void> Function() write, {
|
|
required String logName,
|
|
}) async {
|
|
try {
|
|
await write();
|
|
} on Object catch (error) {
|
|
developer.log('native cache not written: $error', name: logName);
|
|
}
|
|
}
|