- CalendarDao: filter all 6 task queries (watchTasksForDate, watchTasksForDateInRoom, watchOverdueTasks, watchOverdueTasksInRoom, getTaskCount, getTaskCountInRoom) by isActive=true - DailyPlanDao: filter all 3 queries (watchAllTasksWithRoomName, getOverdueAndTodayTaskCount, getOverdueTaskCount) by isActive=true - RoomsDao: filter watchRoomWithStats task query by isActive=true - Update migration test: add schema_v3.dart, test v1->v3 and v2->v3 paths - Update database_test schemaVersion assertion to expect 3 - Fix test helpers in home_screen_test and task_list_screen_test to pass isActive=true
130 lines
3.8 KiB
Dart
130 lines
3.8 KiB
Dart
import 'package:drift/drift.dart';
|
|
|
|
import '../../../core/database/database.dart';
|
|
|
|
part 'rooms_dao.g.dart';
|
|
|
|
/// Stats for a room including task counts and cleanliness ratio.
|
|
class RoomWithStats {
|
|
final Room room;
|
|
final int totalTasks;
|
|
final int dueTasks;
|
|
final int overdueCount;
|
|
final double cleanlinessRatio;
|
|
|
|
const RoomWithStats({
|
|
required this.room,
|
|
required this.totalTasks,
|
|
required this.dueTasks,
|
|
required this.overdueCount,
|
|
required this.cleanlinessRatio,
|
|
});
|
|
}
|
|
|
|
@DriftAccessor(tables: [Rooms, Tasks, TaskCompletions])
|
|
class RoomsDao extends DatabaseAccessor<AppDatabase> with _$RoomsDaoMixin {
|
|
RoomsDao(super.attachedDatabase);
|
|
|
|
/// Watch all rooms ordered by sortOrder.
|
|
Stream<List<Room>> watchAllRooms() {
|
|
return (select(rooms)..orderBy([(r) => OrderingTerm.asc(r.sortOrder)]))
|
|
.watch();
|
|
}
|
|
|
|
/// Watch all rooms with computed task stats.
|
|
///
|
|
/// Cleanliness ratio = (totalTasks - overdueCount) / totalTasks.
|
|
/// 1.0 when no tasks are overdue, 0.0 when all are overdue.
|
|
/// Rooms with no tasks have ratio 1.0.
|
|
Stream<List<RoomWithStats>> watchRoomWithStats({DateTime? today}) {
|
|
final now = today ?? DateTime.now();
|
|
final todayDateOnly = DateTime(now.year, now.month, now.day);
|
|
|
|
return watchAllRooms().asyncMap((roomList) async {
|
|
final stats = <RoomWithStats>[];
|
|
for (final room in roomList) {
|
|
final taskList = await (select(tasks)
|
|
..where(
|
|
(t) => t.roomId.equals(room.id) & t.isActive.equals(true),
|
|
))
|
|
.get();
|
|
|
|
final totalTasks = taskList.length;
|
|
var overdueCount = 0;
|
|
var dueTasks = 0;
|
|
|
|
for (final task in taskList) {
|
|
final dueDate = DateTime(
|
|
task.nextDueDate.year,
|
|
task.nextDueDate.month,
|
|
task.nextDueDate.day,
|
|
);
|
|
if (dueDate.isBefore(todayDateOnly) ||
|
|
dueDate.isAtSameMomentAs(todayDateOnly)) {
|
|
dueTasks++;
|
|
}
|
|
if (dueDate.isBefore(todayDateOnly)) {
|
|
overdueCount++;
|
|
}
|
|
}
|
|
|
|
final ratio =
|
|
totalTasks == 0 ? 1.0 : (totalTasks - overdueCount) / totalTasks;
|
|
|
|
stats.add(RoomWithStats(
|
|
room: room,
|
|
totalTasks: totalTasks,
|
|
dueTasks: dueTasks,
|
|
overdueCount: overdueCount,
|
|
cleanlinessRatio: ratio,
|
|
));
|
|
}
|
|
return stats;
|
|
});
|
|
}
|
|
|
|
/// Insert a new room. Returns the auto-generated id.
|
|
Future<int> insertRoom(RoomsCompanion room) => into(rooms).insert(room);
|
|
|
|
/// Update an existing room. Returns true if a row was updated.
|
|
Future<bool> updateRoom(Room room) => update(rooms).replace(room);
|
|
|
|
/// Delete a room and cascade to its tasks and completions.
|
|
Future<void> deleteRoom(int roomId) {
|
|
return transaction(() async {
|
|
// Get all task IDs for this room
|
|
final taskList = await (select(tasks)
|
|
..where((t) => t.roomId.equals(roomId)))
|
|
.get();
|
|
|
|
// Delete completions for each task
|
|
for (final task in taskList) {
|
|
await (delete(taskCompletions)
|
|
..where((c) => c.taskId.equals(task.id)))
|
|
.go();
|
|
}
|
|
|
|
// Delete tasks
|
|
await (delete(tasks)..where((t) => t.roomId.equals(roomId))).go();
|
|
|
|
// Delete room
|
|
await (delete(rooms)..where((r) => r.id.equals(roomId))).go();
|
|
});
|
|
}
|
|
|
|
/// Reorder rooms by updating sortOrder for each room in the list.
|
|
Future<void> reorderRooms(List<int> roomIds) {
|
|
return transaction(() async {
|
|
for (var i = 0; i < roomIds.length; i++) {
|
|
await (update(rooms)..where((r) => r.id.equals(roomIds[i])))
|
|
.write(RoomsCompanion(sortOrder: Value(i)));
|
|
}
|
|
});
|
|
}
|
|
|
|
/// Get a single room by its id.
|
|
Future<Room> getRoomById(int id) {
|
|
return (select(rooms)..where((r) => r.id.equals(id))).getSingle();
|
|
}
|
|
}
|