timetracker/lib/features/timer/domain/timer_notifier.dart
2026-08-03 21:51:48 +02:00

99 lines
2.8 KiB
Dart

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:timetrack/core/database/app_database.dart' as db;
import 'package:timetrack/features/entries/data/drift_entries_repository.dart';
import 'package:timetrack/features/entries/domain/time_entry.dart' as domain;
import 'package:timetrack/features/projects/data/project_mapper.dart';
import 'package:timetrack/features/projects/domain/project.dart';
import 'package:timetrack/features/timer/domain/timer_state.dart';
part 'timer_notifier.g.dart';
@riverpod
class TimerNotifier extends _$TimerNotifier {
@override
TimerState build() {
_restoreFromDb();
return const TimerState.idle();
}
Future<void> _restoreFromDb() async {
final repo = ref.read(timeEntriesRepositoryProvider);
final active = await repo.getActiveEntry();
if (active == null) return;
final projectRow = await ref
.read(db.appDatabaseProvider)
.projectsDao
.getById(active.projectId);
if (projectRow == null) return;
state = TimerState.running(
entryId: active.id,
startTime: active.startTime,
project: projectRow.toDomain(),
note: active.note,
);
}
Future<void> start(Project project, {String? note}) async {
if (state is TimerRunning) await stop();
final repo = ref.read(timeEntriesRepositoryProvider);
final now = DateTime.now();
final id = await repo.create(domain.TimeEntry(
id: 0,
projectId: project.id,
startTime: now,
tags: const [],
createdAt: now,
note: note,
));
state = TimerState.running(
entryId: id,
startTime: now,
project: project,
note: note,
);
}
Future<void> stop() async {
final running = state;
if (running is! TimerRunning) return;
final now = DateTime.now();
final repo = ref.read(timeEntriesRepositoryProvider);
final current = await repo.getActiveEntry();
if (current != null) {
await repo.update(current.copyWith(
endTime: now,
durationSeconds: now.difference(running.startTime).inSeconds,
));
}
state = const TimerState.idle();
}
Future<void> discard() async {
final running = state;
if (running is! TimerRunning) return;
await ref.read(timeEntriesRepositoryProvider).delete(running.entryId);
state = const TimerState.idle();
}
void updateNote(String note) {
final running = state;
if (running is! TimerRunning) return;
state = running.copyWith(note: note);
_persistNote(running.entryId, note);
}
Future<void> _persistNote(int entryId, String note) async {
final repo = ref.read(timeEntriesRepositoryProvider);
final entry = await repo.getActiveEntry();
if (entry != null) {
await repo.update(entry.copyWith(note: note));
}
}
}