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:
@@ -0,0 +1,82 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:relationship_saver/features/local/local_models.dart';
|
||||
import 'package:relationship_saver/features/people/presentation/people_view.dart';
|
||||
import 'package:relationship_saver/features/people/presentation/providers/people_ui_state.dart';
|
||||
import 'package:relationship_saver/features/share_intake/share_capture_models.dart';
|
||||
import 'package:relationship_saver/features/share_intake/share_capture_review_sheet.dart';
|
||||
import 'package:relationship_saver/features/share_intake/share_inbox_view.dart';
|
||||
import 'package:relationship_saver/features/share_intake/share_payload_parser.dart';
|
||||
|
||||
SharedPayload? buildSharedPayloadFromRawText({
|
||||
required String rawText,
|
||||
required String platform,
|
||||
String? sourceAppHint,
|
||||
}) {
|
||||
final String trimmed = rawText.trim();
|
||||
if (trimmed.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final String sourceApp = SharePayloadParser.detectSourceApp(
|
||||
rawText: trimmed,
|
||||
sourceAppHint: sourceAppHint,
|
||||
);
|
||||
final SharedPayload payload = SharePayloadParser.parse(
|
||||
rawText: trimmed,
|
||||
sourceApp: sourceApp,
|
||||
platform: platform,
|
||||
createdAt: DateTime.now(),
|
||||
receivedAt: DateTime.now(),
|
||||
);
|
||||
if (payload.rawText.trim().isEmpty && (payload.url?.trim().isEmpty ?? true)) {
|
||||
return null;
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
Future<SharedMessageIngestResult?> startShareCaptureReview(
|
||||
BuildContext context, {
|
||||
required WidgetRef ref,
|
||||
required SharedPayload payload,
|
||||
}) {
|
||||
return showShareCaptureReviewSheet(
|
||||
context,
|
||||
ref: ref,
|
||||
payload: payload,
|
||||
initialPersonId: ref.read(selectedPersonIdProvider),
|
||||
);
|
||||
}
|
||||
|
||||
void openShareCaptureDestination(
|
||||
BuildContext context, {
|
||||
required WidgetRef ref,
|
||||
required SharedMessageIngestResult result,
|
||||
}) {
|
||||
if (result.isQueuedForResolution) {
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => const ShareInboxView(),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.profileId != null) {
|
||||
ref.read(selectedPersonIdProvider.notifier).select(result.profileId!);
|
||||
}
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => const PeopleView(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String shareCaptureResultMessage(SharedMessageIngestResult result) {
|
||||
if (result.isQueuedForResolution) {
|
||||
return 'Saved shared capture to inbox.';
|
||||
}
|
||||
if (result.createdProfile) {
|
||||
return 'Saved shared capture and created ${result.profileName}.';
|
||||
}
|
||||
return 'Saved shared capture to ${result.profileName}.';
|
||||
}
|
||||
Reference in New Issue
Block a user