// ignore_for_file: sort_constructors_first import 'package:flutter/foundation.dart'; import 'package:relationship_saver/features/ai_digest/domain/ai_digest_models.dart'; import 'package:relationship_saver/features/dashboard/domain/dashboard_models.dart'; import 'package:relationship_saver/features/ideas/domain/idea_models.dart'; import 'package:relationship_saver/features/moments/domain/moment_models.dart'; import 'package:relationship_saver/features/people/domain/person_models.dart'; import 'package:relationship_saver/features/reminders/domain/reminder_models.dart'; import 'package:relationship_saver/features/share_intake/domain/share_models.dart'; /// Aggregate local snapshot used by the prototype app store. /// /// During this prototyping phase the app still uses one persisted snapshot for /// most product state. The types inside it are now feature-owned, so each slice /// can evolve without hiding its models in a horizontal "local" module. @immutable class LocalDataState { const LocalDataState({ required this.people, required this.moments, required this.ideas, required this.reminders, required this.tasks, this.dismissedSignalIds = const [], this.sourceLinks = const [], this.sharedMessages = const [], this.sharedInbox = const [], this.personFacts = const [], this.importantDates = const [], this.preferenceSignals = const [], this.aiSuggestionDrafts = const [], }); final List people; final List moments; final List ideas; final List reminders; final List tasks; final List dismissedSignalIds; final List sourceLinks; final List sharedMessages; final List sharedInbox; final List personFacts; final List importantDates; final List preferenceSignals; final List aiSuggestionDrafts; LocalDataState copyWith({ List? people, List? moments, List? ideas, List? reminders, List? tasks, List? dismissedSignalIds, List? sourceLinks, List? sharedMessages, List? sharedInbox, List? personFacts, List? importantDates, List? preferenceSignals, List? aiSuggestionDrafts, }) { return LocalDataState( people: people ?? this.people, moments: moments ?? this.moments, ideas: ideas ?? this.ideas, reminders: reminders ?? this.reminders, tasks: tasks ?? this.tasks, dismissedSignalIds: dismissedSignalIds ?? this.dismissedSignalIds, sourceLinks: sourceLinks ?? this.sourceLinks, sharedMessages: sharedMessages ?? this.sharedMessages, sharedInbox: sharedInbox ?? this.sharedInbox, personFacts: personFacts ?? this.personFacts, importantDates: importantDates ?? this.importantDates, preferenceSignals: preferenceSignals ?? this.preferenceSignals, aiSuggestionDrafts: aiSuggestionDrafts ?? this.aiSuggestionDrafts, ); } DashboardSummary summary({DateTime? now}) { final DateTime baseline = now ?? DateTime.now(); return DashboardSummary( activePeople: people.length, upcomingPlans: people .where((PersonProfile p) => p.nextMoment.isAfter(baseline)) .length, pendingIdeas: ideas .where((RelationshipIdea idea) => !idea.isArchived) .length, weeklyConsistency: moments.isEmpty ? 0 : (70 + moments.length * 4).clamp(0, 100), ); } Map toJson() { return { 'people': people .map((PersonProfile person) => person.toJson()) .toList(growable: false), 'moments': moments .map((RelationshipMoment moment) => moment.toJson()) .toList(growable: false), 'ideas': ideas .map((RelationshipIdea idea) => idea.toJson()) .toList(growable: false), 'reminders': reminders .map((ReminderRule reminder) => reminder.toJson()) .toList(growable: false), 'tasks': tasks .map((DashboardTask task) => task.toJson()) .toList(growable: false), 'dismissedSignalIds': dismissedSignalIds, 'sourceLinks': sourceLinks .map((SourceProfileLink link) => link.toJson()) .toList(growable: false), 'sharedMessages': sharedMessages .map((SharedMessageEntry entry) => entry.toJson()) .toList(growable: false), 'sharedInbox': sharedInbox .map((SharedInboxEntry entry) => entry.toJson()) .toList(growable: false), 'personFacts': personFacts .map((PersonFact fact) => fact.toJson()) .toList(growable: false), 'importantDates': importantDates .map((PersonImportantDate value) => value.toJson()) .toList(growable: false), 'preferenceSignals': preferenceSignals .map((PersonPreferenceSignal signal) => signal.toJson()) .toList(growable: false), 'aiSuggestionDrafts': aiSuggestionDrafts .map((AiSuggestionDraft draft) => draft.toJson()) .toList(growable: false), }; } factory LocalDataState.fromJson(Map json) { return LocalDataState( people: (json['people'] as List? ?? []) .map( (dynamic person) => PersonProfile.fromJson(person as Map), ) .toList(growable: false), moments: (json['moments'] as List? ?? []) .map( (dynamic moment) => RelationshipMoment.fromJson(moment as Map), ) .toList(growable: false), ideas: (json['ideas'] as List? ?? []) .map( (dynamic idea) => RelationshipIdea.fromJson(idea as Map), ) .toList(growable: false), reminders: (json['reminders'] as List? ?? []) .map( (dynamic reminder) => ReminderRule.fromJson(reminder as Map), ) .toList(growable: false), tasks: (json['tasks'] as List? ?? []) .map( (dynamic task) => DashboardTask.fromJson(task as Map), ) .toList(growable: false), dismissedSignalIds: (json['dismissedSignalIds'] as List? ?? []) .map((dynamic value) => '$value') .toList(growable: false), sourceLinks: (json['sourceLinks'] as List? ?? []) .map( (dynamic link) => SourceProfileLink.fromJson(link as Map), ) .toList(growable: false), sharedMessages: (json['sharedMessages'] as List? ?? []) .map( (dynamic entry) => SharedMessageEntry.fromJson(entry as Map), ) .toList(growable: false), sharedInbox: (json['sharedInbox'] as List? ?? []) .map( (dynamic entry) => SharedInboxEntry.fromJson(entry as Map), ) .toList(growable: false), personFacts: (json['personFacts'] as List? ?? []) .map( (dynamic fact) => PersonFact.fromJson(fact as Map), ) .toList(growable: false), importantDates: (json['importantDates'] as List? ?? []) .map( (dynamic value) => PersonImportantDate.fromJson(value as Map), ) .toList(growable: false), preferenceSignals: (json['preferenceSignals'] as List? ?? []) .map( (dynamic signal) => PersonPreferenceSignal.fromJson( signal as Map, ), ) .toList(growable: false), aiSuggestionDrafts: (json['aiSuggestionDrafts'] as List? ?? []) .map( (dynamic draft) => AiSuggestionDraft.fromJson(draft as Map), ) .toList(growable: false), ); } static LocalDataState seed() { return LocalDataState( people: [ PersonProfile( id: 'p-ava', name: 'Ava Hart', relationship: 'Partner', affinityScore: 92, nextMoment: DateTime(2026, 2, 16, 19, 30), tags: ['coffee', 'books', 'slow mornings'], notes: 'Prefers thoughtful plans over expensive plans.', aliases: ['Aves'], location: 'Austin, TX', lastUpdatedAt: DateTime(2026, 2, 14, 9, 0), lastInteractedAt: DateTime(2026, 2, 12, 18, 30), ), PersonProfile( id: 'p-jordan', name: 'Jordan Lee', relationship: 'Close Friend', affinityScore: 78, nextMoment: DateTime(2026, 2, 18, 18, 0), tags: ['running', 'street food'], notes: 'Has a race on Sunday; ask how training is going.', location: 'Chicago, IL', lastUpdatedAt: DateTime(2026, 2, 13, 8, 30), lastInteractedAt: DateTime(2026, 2, 11, 19, 0), ), PersonProfile( id: 'p-mila', name: 'Mila Stone', relationship: 'Sister', affinityScore: 84, nextMoment: DateTime(2026, 2, 20, 12, 0), tags: ['plants', 'retro music'], notes: 'Birthday prep should start this week.', aliases: ['Millie'], location: 'Seattle, WA', lastUpdatedAt: DateTime(2026, 2, 13, 14, 20), lastInteractedAt: DateTime(2026, 2, 12, 14, 20), ), ], moments: [ RelationshipMoment( id: 'm-1', personId: 'p-ava', title: 'Sunday Walk Tradition', summary: 'Short walk + no-phone hour worked really well.', at: DateTime(2026, 2, 9, 9, 30), type: 'ritual', ), RelationshipMoment( id: 'm-2', personId: 'p-jordan', title: 'Post-workout Check-in', summary: 'Shared training playlist and grabbed smoothies.', at: DateTime(2026, 2, 11, 19, 0), type: 'support', ), RelationshipMoment( id: 'm-3', personId: 'p-mila', title: 'Gift Idea Captured', summary: 'Found a vintage lamp from her saved style board.', at: DateTime(2026, 2, 12, 14, 20), type: 'gift', ), ], ideas: [ RelationshipIdea( id: 'i-1', personId: 'p-ava', type: IdeaType.gift, title: 'Handwritten recipe journal', details: 'Collect 10 memories and recipes from this year.', createdAt: DateTime(2026, 2, 12, 9), ), RelationshipIdea( id: 'i-2', personId: 'p-mila', type: IdeaType.event, title: 'Plant market + brunch date', details: 'Saturday morning slot; book nearby cafe in advance.', createdAt: DateTime(2026, 2, 13, 11), ), ], reminders: [ ReminderRule( id: 'r-1', personId: 'p-jordan', title: 'Weekly check-in message', cadence: ReminderCadence.weekly, nextAt: DateTime(2026, 2, 18, 18), ), ReminderRule( id: 'r-2', personId: 'p-ava', title: 'Sunday ritual planning', cadence: ReminderCadence.weekly, nextAt: DateTime(2026, 2, 16, 10), ), ], tasks: [ DashboardTask( id: 't-1', title: 'Plan Friday dinner with Ava', description: 'Keep it low-key: ramen + bookstore stop.', when: DateTime(2026, 2, 16, 17, 0), ), DashboardTask( id: 't-2', title: 'Send race-day encouragement to Jordan', description: 'Voice note before 8:00 AM.', when: DateTime(2026, 2, 17, 7, 30), ), DashboardTask( id: 't-3', title: 'Finalize Mila birthday shortlist', description: 'Pick 1 meaningful gift and 1 backup.', when: DateTime(2026, 2, 18, 20, 0), ), ], personFacts: [ PersonFact( id: 'pf-1', personId: 'p-ava', type: CapturedFactType.like, text: 'Quiet brunch spots and recipe-book stores', label: 'Weekend preference', sourceKind: CaptureSourceKind.manual, createdAt: DateTime(2026, 2, 10, 8, 0), updatedAt: DateTime(2026, 2, 10, 8, 0), ), PersonFact( id: 'pf-2', personId: 'p-mila', type: CapturedFactType.giftIdea, text: 'Vintage ceramic planter in muted green', label: 'Gift lead', sourceKind: CaptureSourceKind.manual, createdAt: DateTime(2026, 2, 12, 14, 25), updatedAt: DateTime(2026, 2, 12, 14, 25), ), ], importantDates: [ PersonImportantDate( id: 'pd-1', personId: 'p-mila', label: 'Birthday', date: DateTime(2026, 3, 3), classification: 'birthday', sourceKind: CaptureSourceKind.manual, createdAt: DateTime(2026, 2, 12, 14, 30), updatedAt: DateTime(2026, 2, 12, 14, 30), ), ], ); } }