104 lines
3.4 KiB
Dart
104 lines
3.4 KiB
Dart
import 'package:drift/drift.dart';
|
|||
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
|
import '../database/app_database.dart';
|
||
|
|
import 'database_provider.dart';
|
||
|
|
|
||
|
|
// ── All entries stream ────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
final moodEntriesProvider = StreamProvider.autoDispose<List<MoodEntry>>((ref) {
|
||
|
|
return ref.watch(moodDaoProvider).watchAllEntries();
|
||
|
|
});
|
||
|
|
|
||
|
|
// ── Entries for a specific day ────────────────────────────────────────────────
|
||
|
|
|
||
|
|
final moodEntriesForDayProvider =
|
||
|
|
StreamProvider.autoDispose.family<List<MoodEntry>, DateTime>((ref, day) {
|
||
|
|
return ref.watch(moodDaoProvider).watchEntriesForDay(day);
|
||
|
|
});
|
||
|
|
|
||
|
|
// ── Daily averages for calendar heatmap ──────────────────────────────────────
|
||
|
|
|
||
|
|
final dailyAveragesProvider = FutureProvider.autoDispose
|
||
|
|
.family<Map<DateTime, double>, ({DateTime start, DateTime end})>(
|
||
|
|
(ref, range) =>
|
||
|
|
ref.watch(moodDaoProvider).getDailyAverages(range.start, range.end),
|
||
|
|
);
|
||
|
|
|
||
|
|
// ── Selected day (drives calendar + day detail) ───────────────────────────────
|
||
|
|
|
||
|
|
class SelectedDay extends Notifier<DateTime> {
|
||
|
|
@override
|
||
|
|
DateTime build() => DateTime.now();
|
||
|
|
|
||
|
|
void select(DateTime day) {
|
||
|
|
state = DateTime(day.year, day.month, day.day);
|
||
|
|
}
|
||
|
|
|
||
|
|
void selectToday() {
|
||
|
|
final now = DateTime.now();
|
||
|
|
state = DateTime(now.year, now.month, now.day);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
final selectedDayProvider =
|
||
|
|
NotifierProvider.autoDispose<SelectedDay, DateTime>(SelectedDay.new);
|
||
|
|
|
||
|
|
// ── Mood entry notifier (create / update / delete) ────────────────────────────
|
||
|
|
|
||
|
|
class MoodEntryNotifier extends Notifier<AsyncValue<void>> {
|
||
|
|
@override
|
||
|
|
AsyncValue<void> build() => const AsyncData(null);
|
||
|
|
|
||
|
|
Future<void> addEntry({
|
||
|
|
required int moodLevel,
|
||
|
|
String? note,
|
||
|
|
List<int> activityIds = const [],
|
||
|
|
List<int> tagIds = const [],
|
||
|
|
DateTime? timestamp,
|
||
|
|
}) async {
|
||
|
|
state = const AsyncLoading();
|
||
|
|
state = await AsyncValue.guard(() async {
|
||
|
|
final dao = ref.read(moodDaoProvider);
|
||
|
|
await dao.insertEntryWithActivities(
|
||
|
|
entry: MoodEntriesCompanion.insert(
|
||
|
|
moodLevel: moodLevel,
|
||
|
|
timestamp: timestamp ?? DateTime.now(),
|
||
|
|
note: Value(note),
|
||
|
|
),
|
||
|
|
activityIds: activityIds,
|
||
|
|
tagIds: tagIds,
|
||
|
|
);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> deleteEntry(int id) async {
|
||
|
|
state = const AsyncLoading();
|
||
|
|
state = await AsyncValue.guard(
|
||
|
|
() => ref.read(moodDaoProvider).deleteEntry(id),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> updateEntry({
|
||
|
|
required int id,
|
||
|
|
required int moodLevel,
|
||
|
|
String? note,
|
||
|
|
DateTime? timestamp,
|
||
|
|
}) async {
|
||
|
|
state = const AsyncLoading();
|
||
|
|
state = await AsyncValue.guard(
|
||
|
|
() => ref.read(moodDaoProvider).updateEntry(
|
||
|
|
MoodEntriesCompanion(
|
||
|
|
id: Value(id),
|
||
|
|
moodLevel: Value(moodLevel),
|
||
|
|
note: Value(note),
|
||
|
|
timestamp: Value(timestamp ?? DateTime.now()),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
final moodEntryNotifierProvider =
|
||
|
|
NotifierProvider.autoDispose<MoodEntryNotifier, AsyncValue<void>>(
|
||
|
|
MoodEntryNotifier.new);
|