import '../../about/external/data/LiveSession.dart'; import '../../about/external/initial/RoutineLogRequest.dart'; import '../../about/internal/application/RoutineRun.dart'; import '../../configs/NotificationServiceConfig.dart'; import '../parent/ParentViewModel.dart'; import 'ConnectRoutineRunner.dart'; class ViewRoutineRunner extends ParentViewModel { ConnectRoutineRunner connection; ViewRoutineRunner(super.context, this.connection); /// Mirrors the current phase into the ongoing notification, through the /// same [LiveSession] shape the single-task runner uses. void publishRun(RoutineRun run) { LocalNotificationEngine.showSessionNotification(LiveSession( commitmentId: run.chain.id ?? "", title: run.phase.rest ? "Rest" : run.phase.step.title, goalTitle: run.chain.title, startedAt: run.startedAt, accumulatedSeconds: run.phaseElapsed(), resumedAt: run.running ? DateTime.now() : null, requiredSeconds: run.phase.seconds, backgroundedCount: run.backgroundedCount, )); } void clearRun() { LocalNotificationEngine.cancelSessionNotification(); } /// Held or broken, the run is always logged — a broken chain goes in as /// partial at the step it broke on. void log(RoutineRun run) async { if (!await hasNetwork(() => log(run))) return; showLoading("Recording"); try { await getDataManager().logRoutineChainEntry(RoutineLogRequest( routineId: run.chain.id ?? "", startedAt: run.startedAt.toIso8601String(), elapsedSeconds: run.elapsedSeconds(), completedSteps: run.chain.completedSteps, totalSteps: run.chain.steps.length, breakIndex: run.breakIndex, backgroundedCount: run.backgroundedCount, skippedCount: run.skippedCount, ).toJson()); clearRun(); closeLoading(); connection.onLogged(run.chain.complete); } catch (e) { handleError(e, () => log(run), () => dismissError(), "Retry"); } } }