mirror of
https://github.com/kuhyx/wake-alarm.git
synced 2026-11-10 18:07:05 +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
50 lines
2.0 KiB
Dart
50 lines
2.0 KiB
Dart
import 'package:crdt_sync/crdt_sync.dart';
|
|
import 'package:wake_alarm_sync/services/alarm_scheduler.dart';
|
|
import 'package:wake_alarm_sync/services/day_pool_sync.dart';
|
|
import 'package:wake_alarm_sync/services/firebase_backend.dart';
|
|
import 'package:wake_alarm_sync/services/free_day_pool.dart';
|
|
|
|
/// Moves the free-day pool between this phone and every other device.
|
|
///
|
|
/// Firebase only. The alarm record keeps its GitHub mirror because that
|
|
/// fallback is load-bearing for un-migrated installs; this namespace is new
|
|
/// and has no such history, so it gets no second transport.
|
|
///
|
|
/// Every sync ends by handing the merged pool to the native ring path
|
|
/// ([AlarmScheduler.setFreeDays]) — that cache, not the Dart store, is what
|
|
/// decides whether the phone rings, so it must never lag a sync.
|
|
class FreeDaySync {
|
|
/// Creates a syncer; both seams are injectable for tests.
|
|
FreeDaySync({
|
|
Future<RemoteStore?> Function()? openClient,
|
|
AlarmScheduler? scheduler,
|
|
}) : _openClient = openClient ?? openFirebase,
|
|
_scheduler = scheduler ?? AlarmScheduler();
|
|
|
|
final Future<RemoteStore?> Function() _openClient;
|
|
final AlarmScheduler _scheduler;
|
|
|
|
/// Pulls, merges and pushes [pool], then refreshes the native cache.
|
|
///
|
|
/// Never throws; see [syncDayPoolLog]. The native cache is refreshed even
|
|
/// when the sync could not run, so a day marked offline still stands the
|
|
/// phone down.
|
|
Future<String> sync(FreeDayPool pool) => syncDayPoolLog(
|
|
openClient: _openClient,
|
|
deviceId: pool.deviceId,
|
|
pathPrefix: FreeDayPool.pathPrefix,
|
|
filename: FreeDayPool.filename,
|
|
commitMessage: 'freedays: update pool',
|
|
snapshot: pool.snapshot,
|
|
replaceAll: pool.replaceAll,
|
|
publish: () => publishToNative(pool),
|
|
logName: 'FreeDaySync',
|
|
);
|
|
|
|
/// Writes the pool's free dates where `AlarmReceiver` can read them.
|
|
Future<void> publishToNative(FreeDayPool pool) => publishQuietly(
|
|
() => _scheduler.setFreeDays(pool.freeIsoDates()),
|
|
logName: 'FreeDaySync',
|
|
);
|
|
}
|