diff --git a/lib/features/home/data/daily_plan_dao.dart b/lib/features/home/data/daily_plan_dao.dart index a635858..6eadf92 100644 --- a/lib/features/home/data/daily_plan_dao.dart +++ b/lib/features/home/data/daily_plan_dao.dart @@ -11,14 +11,42 @@ class DailyPlanDao extends DatabaseAccessor DailyPlanDao(super.attachedDatabase); /// Watch all tasks joined with room name, sorted by nextDueDate ascending. + /// Includes ALL tasks (overdue, today, future) -- filtering is done in the + /// provider layer to avoid multiple queries. Stream> watchAllTasksWithRoomName() { - // TODO: implement - throw UnimplementedError(); + final query = select(tasks).join([ + innerJoin(rooms, rooms.id.equalsExp(tasks.roomId)), + ]); + query.orderBy([OrderingTerm.asc(tasks.nextDueDate)]); + + return query.watch().map((rows) { + return rows.map((row) { + final task = row.readTable(tasks); + final room = row.readTable(rooms); + return TaskWithRoom( + task: task, + roomName: room.name, + roomId: room.id, + ); + }).toList(); + }); } /// Count task completions recorded today. + /// Uses customSelect with readsFrom for proper stream invalidation. Stream watchCompletionsToday({DateTime? today}) { - // TODO: implement - throw UnimplementedError(); + final now = today ?? DateTime.now(); + final startOfDay = DateTime(now.year, now.month, now.day); + final endOfDay = startOfDay.add(const Duration(days: 1)); + + return customSelect( + 'SELECT COUNT(*) AS c FROM task_completions ' + 'WHERE completed_at >= ? AND completed_at < ?', + variables: [ + Variable(startOfDay.millisecondsSinceEpoch ~/ 1000), + Variable(endOfDay.millisecondsSinceEpoch ~/ 1000), + ], + readsFrom: {taskCompletions}, + ).watchSingle().map((row) => row.read('c')); } }