- 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
76 lines
2.4 KiB
Dart
76 lines
2.4 KiB
Dart
import 'dart:convert';
|
|
import 'package:crypto/crypto.dart';
|
|
import 'package:drift/drift.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../database/app_database.dart';
|
|
import 'database_provider.dart';
|
|
|
|
// ── Insight type enum ─────────────────────────────────────────────────────────
|
|
|
|
enum InsightType { weekly, monthly, query }
|
|
|
|
// ── Cached insight lookup ─────────────────────────────────────────────────────
|
|
|
|
final cachedInsightProvider =
|
|
FutureProvider.autoDispose.family<LlmInsight?, String>((ref, promptHash) {
|
|
return ref.watch(insightDaoProvider).getCached(promptHash);
|
|
});
|
|
|
|
// ── Insight notifier — triggers generation and caches results ─────────────────
|
|
|
|
class InsightNotifier extends Notifier<AsyncValue<String?>> {
|
|
@override
|
|
AsyncValue<String?> build() => const AsyncData(null);
|
|
|
|
String _hashPrompt(String prompt) =>
|
|
sha256.convert(utf8.encode(prompt)).toString();
|
|
|
|
Future<void> generateInsight({
|
|
required String prompt,
|
|
required InsightType type,
|
|
DateTime? rangeStart,
|
|
DateTime? rangeEnd,
|
|
}) async {
|
|
state = const AsyncLoading();
|
|
|
|
final hash = _hashPrompt(prompt);
|
|
final dao = ref.read(insightDaoProvider);
|
|
|
|
final cached = await dao.getCached(hash);
|
|
if (!ref.mounted) return;
|
|
if (cached != null) {
|
|
state = AsyncData(cached.responseText);
|
|
return;
|
|
}
|
|
|
|
// Generation happens in LlmNotifier (see llm_provider.dart)
|
|
state = const AsyncData(null);
|
|
}
|
|
|
|
Future<void> saveInsight({
|
|
required String promptHash,
|
|
required String responseText,
|
|
required InsightType type,
|
|
DateTime? rangeStart,
|
|
DateTime? rangeEnd,
|
|
}) async {
|
|
await ref.read(insightDaoProvider).upsertInsight(
|
|
LlmInsightsCompanion.insert(
|
|
type: type.name,
|
|
promptHash: promptHash,
|
|
responseText: responseText,
|
|
rangeStart: Value(rangeStart),
|
|
rangeEnd: Value(rangeEnd),
|
|
),
|
|
);
|
|
if (!ref.mounted) return;
|
|
state = AsyncData(responseText);
|
|
}
|
|
|
|
void clear() => state = const AsyncData(null);
|
|
}
|
|
|
|
final insightNotifierProvider =
|
|
NotifierProvider.autoDispose<InsightNotifier, AsyncValue<String?>>(
|
|
InsightNotifier.new);
|