feat: add local-first private AI digest workflow

Migrate app code into canonical feature slices, add phone-only AI digest scheduling and review, wire local notification/background task support, and cover the flow with tests.
This commit is contained in:
Rijad Zuzo
2026-05-17 00:17:20 +02:00
parent dab50abf0e
commit f655adfbea
212 changed files with 24178 additions and 15895 deletions
@@ -0,0 +1,63 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:relationship_saver/core/llm/captured_fact_draft_parser.dart';
import 'package:relationship_saver/features/share_intake/domain/share_models.dart';
void main() {
test('parses a JSON suggestion into a captured draft', () {
final SharedPayload payload = SharedPayload(
sourceApp: 'signal',
payloadType: SharedPayloadType.text,
rawText: 'Mila birthday is on 2026-05-20',
createdAt: DateTime.utc(2026, 4, 17),
receivedAt: DateTime.utc(2026, 4, 17),
platform: 'android',
);
final CapturedFactDraft? result = parseCapturedFactDraftSuggestion(
'{"type":"importantDate","text":"Birthday to remember","label":"Birthday","dateValue":"2026-05-20","confidence":0.88,"isSensitive":false}',
fallbackPayload: payload,
);
expect(result, isNotNull);
expect(result!.type, CapturedFactType.importantDate);
expect(result.label, 'Birthday');
expect(result.dateValue, DateTime(2026, 5, 20));
expect(result.confidence, 0.88);
expect(result.needsReview, isTrue);
});
test('falls back to payload text when suggestion text is missing', () {
final SharedPayload payload = SharedPayload(
sourceApp: 'signal',
payloadType: SharedPayloadType.text,
rawText: 'Mila birthday is on 2026-05-20',
createdAt: DateTime.utc(2026, 4, 17),
receivedAt: DateTime.utc(2026, 4, 17),
platform: 'android',
);
final CapturedFactDraft? result = parseCapturedFactDraftSuggestion(
'{"type":"note","label":""}',
fallbackPayload: payload,
);
expect(result, isNotNull);
expect(result!.text, payload.rawText);
expect(result.label, isNull);
});
test('returns null for non-json responses', () {
final SharedPayload payload = SharedPayload(
sourceApp: 'signal',
payloadType: SharedPayloadType.text,
rawText: 'Mila birthday is on 2026-05-20',
createdAt: DateTime.utc(2026, 4, 17),
receivedAt: DateTime.utc(2026, 4, 17),
platform: 'android',
);
final CapturedFactDraft? result = parseCapturedFactDraftSuggestion(
'No structured output available.',
fallbackPayload: payload,
);
expect(result, isNull);
});
}