mirror of
https://github.com/kuhyx/wake-alarm.git
synced 2026-11-11 14:47:50 +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.7 KiB
Dart
77 lines
2.7 KiB
Dart
import 'dart:developer' as developer;
|
|
import 'dart:ui' show DartPluginRegistrant;
|
|
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:wake_alarm_sync/services/free_day_pool.dart';
|
|
import 'package:wake_alarm_sync/services/free_day_sync.dart';
|
|
import 'package:wake_alarm_sync/services/sick_day_pool.dart';
|
|
import 'package:wake_alarm_sync/services/sick_day_sync.dart';
|
|
|
|
/// Channel `PoolSyncEngine.kt` listens on for `done`.
|
|
const poolSyncChannelName = 'com.kuhy.wake_alarm_sync/poolsync';
|
|
|
|
/// Pulls both day pools and rewrites both native ring-path caches.
|
|
///
|
|
/// The two run side by side: the pre-alarm sync may only have Doze's short
|
|
/// network window. Silent, and never throws -- each failure is logged and
|
|
/// swallowed, and an unreadable pool leaves the cache as it was (the alarm
|
|
/// rings on anything it cannot read).
|
|
Future<void> refreshDayPools({
|
|
Future<FreeDayPool> Function()? openFree,
|
|
Future<SickDayPool> Function()? openSick,
|
|
FreeDaySync? freeSync,
|
|
SickDaySync? sickSync,
|
|
}) async {
|
|
Future<void> guarded(String pool, Future<void> Function() run) async {
|
|
try {
|
|
await run();
|
|
} on Exception catch (e, stack) {
|
|
developer.log(
|
|
'$pool pool unavailable: $e',
|
|
name: 'WakeAlarmSync',
|
|
error: e,
|
|
stackTrace: stack,
|
|
);
|
|
}
|
|
}
|
|
|
|
await Future.wait([
|
|
guarded('free-day', () async {
|
|
final pool = await (openFree ?? FreeDayPool.open)();
|
|
await (freeSync ?? FreeDaySync()).sync(pool);
|
|
}),
|
|
guarded('sick-day', () async {
|
|
final pool = await (openSick ?? SickDayPool.open)();
|
|
await (sickSync ?? SickDaySync()).sync(pool);
|
|
}),
|
|
]);
|
|
}
|
|
|
|
/// The pre-alarm headless engine's whole job: [refreshDayPools], then say
|
|
/// `done` -- whatever happened, or the native side keeps the engine (and
|
|
/// the broadcast it holds open) until its timeout.
|
|
///
|
|
/// Started natively by `PoolSyncReceiver` (`poolSyncMain` in `main.dart`)
|
|
/// in the evening and shortly before the alarm, so a day marked on the PC
|
|
/// reaches the ring path without the app being opened.
|
|
Future<void> runHeadlessPoolSync({
|
|
Future<void> Function()? refresh,
|
|
MethodChannel? channel,
|
|
}) async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
// A non-`main` entrypoint does not register Dart-side plugin
|
|
// implementations (path_provider, secure storage) by itself.
|
|
DartPluginRegistrant.ensureInitialized();
|
|
try {
|
|
await (refresh ?? refreshDayPools)();
|
|
} finally {
|
|
try {
|
|
await (channel ?? const MethodChannel(poolSyncChannelName))
|
|
.invokeMethod<void>('done');
|
|
} on Object catch (e) {
|
|
developer.log('pool-sync done not delivered: $e', name: 'WakeAlarmSync');
|
|
}
|
|
}
|
|
}
|