Skip to content

Commit

Permalink
Merge pull request #1949 from matthiasn/feat/checklist_item_suggestion
Browse files Browse the repository at this point in the history
feat: checklist item suggestion
  • Loading branch information
matthiasn authored Mar 4, 2025
2 parents e314df4 + ae62f76 commit 5612115
Show file tree
Hide file tree
Showing 20 changed files with 904 additions and 147 deletions.
96 changes: 96 additions & 0 deletions lib/features/ai/state/latest_summary_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import 'dart:async';

import 'package:lotti/classes/checklist_item_data.dart';
import 'package:lotti/classes/journal_entities.dart';
import 'package:lotti/features/journal/repository/journal_repository.dart';
import 'package:lotti/get_it.dart';
import 'package:lotti/services/db_notification.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'latest_summary_controller.g.dart';

@riverpod
class LatestSummaryController extends _$LatestSummaryController {
LatestSummaryController() {
listen();
}

StreamSubscription<Set<String>>? _updateSubscription;
final UpdateNotifications _updateNotifications = getIt<UpdateNotifications>();
final watchedIds = <String>{};

void listen() {
_updateSubscription =
_updateNotifications.updateStream.listen((affectedIds) {
if (affectedIds.intersection(watchedIds).isNotEmpty) {
_fetch().then((latest) {
if (latest != state.value) {
state = AsyncData(latest);
}
});
}
});
}

@override
Future<AiResponseEntry?> build({
required String id,
}) async {
ref.onDispose(() => _updateSubscription?.cancel());
watchedIds.add(id);
final latestAiEntry = await _fetch();
return latestAiEntry;
}

Future<AiResponseEntry?> _fetch() async {
final linked = await ref
.read(journalRepositoryProvider)
.getLinkedEntities(linkedTo: id);

return linked.whereType<AiResponseEntry>().toList().firstOrNull;
}
}

@Riverpod(keepAlive: true)
class ChecklistItemSuggestionsController
extends _$ChecklistItemSuggestionsController {
Set<String> alreadyCreated = {};

@override
Future<List<ChecklistItemData>> build({
required String id,
}) async {
final latestAiEntry =
await ref.watch(latestSummaryControllerProvider(id: id).future);

final exp = RegExp(
r'TODO:\s(.+)',
multiLine: true,
);

final checklistItems = exp
.allMatches(latestAiEntry?.data.response ?? '')
.map((e) {
final title = e.group(1);
if (title != null) {
return ChecklistItemData(
title: title.replaceAll(RegExp('[-.,"]'), '').trim(),
isChecked: false,
linkedChecklists: [],
);
}
})
.nonNulls
.where((e) => !alreadyCreated.contains(e.title))
.toList();

return checklistItems;
}

void notifyCreatedChecklistItem({
required String title,
}) {
alreadyCreated.add(title);
ref.invalidateSelf();
}
}
Loading

0 comments on commit 5612115

Please sign in to comment.