Files
dailyou/lib/core/providers/activity_provider.dart
stefwill 59597c7a4f feat: wire up app shell, log mood screen, and fix Android build
- Bootstrap ProviderScope in main.dart and move App to app.dart with light/dark theming
- Add initial LogMoodScreen with mood entry flow and shared activity/mood widgets
- Add kIsWeb guard in app_database.dart for drift web support
- Enable Android core library desugaring required by flutter_local_notifications 21.x
- Guard all async notifier state assignments with ref.mounted checks to prevent
  use-after-dispose errors when providers are auto-disposed mid-operation
2026-04-26 12:00:14 +10:00

80 lines
2.6 KiB
Dart

import 'package:drift/drift.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../database/app_database.dart';
import 'database_provider.dart';
// ── All activities stream ─────────────────────────────────────────────────────
final activitiesProvider = StreamProvider.autoDispose<List<Activity>>((ref) {
return ref.watch(activityDaoProvider).watchAllActivities();
});
// ── Activity frequency for charts ────────────────────────────────────────────
final activityFrequencyProvider = FutureProvider.autoDispose
.family<Map<int, int>, ({DateTime start, DateTime end})>(
(ref, range) =>
ref.watch(activityDaoProvider).getActivityFrequency(range.start, range.end),
);
// ── Selected activities (used by log mood screen) ─────────────────────────────
class SelectedActivities extends Notifier<Set<int>> {
@override
Set<int> build() => {};
void toggle(int activityId) {
if (state.contains(activityId)) {
state = <int>{...state}..remove(activityId);
} else {
state = {...state, activityId};
}
}
void clear() => state = {};
}
final selectedActivitiesProvider =
NotifierProvider.autoDispose<SelectedActivities, Set<int>>(
SelectedActivities.new);
// ── Activity notifier (create / delete custom activities) ─────────────────────
class ActivityNotifier extends Notifier<AsyncValue<void>> {
@override
AsyncValue<void> build() => const AsyncData(null);
Future<void> addActivity({
required String name,
required int iconCodepoint,
required String colourHex,
}) async {
state = const AsyncLoading();
final next = await AsyncValue.guard(
() => ref.read(activityDaoProvider).insertActivity(
ActivitiesCompanion.insert(
name: name,
iconCodepoint: iconCodepoint,
colourHex: colourHex,
isCustom: const Value(true),
),
),
);
if (!ref.mounted) return;
state = next;
}
Future<void> deleteActivity(int id) async {
state = const AsyncLoading();
final next = await AsyncValue.guard(
() => ref.read(activityDaoProvider).deleteActivity(id),
);
if (!ref.mounted) return;
state = next;
}
}
final activityNotifierProvider =
NotifierProvider.autoDispose<ActivityNotifier, AsyncValue<void>>(
ActivityNotifier.new);