Files
rely/lib/app/state/local_data_state.dart
2026-05-18 20:33:54 +02:00

234 lines
8.9 KiB
Dart

// 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 <String>[],
this.sourceLinks = const <SourceProfileLink>[],
this.sharedMessages = const <SharedMessageEntry>[],
this.sharedInbox = const <SharedInboxEntry>[],
this.personFacts = const <PersonFact>[],
this.importantDates = const <PersonImportantDate>[],
this.preferenceSignals = const <PersonPreferenceSignal>[],
this.aiSuggestionDrafts = const <AiSuggestionDraft>[],
});
final List<PersonProfile> people;
final List<RelationshipMoment> moments;
final List<RelationshipIdea> ideas;
final List<ReminderRule> reminders;
final List<DashboardTask> tasks;
final List<String> dismissedSignalIds;
final List<SourceProfileLink> sourceLinks;
final List<SharedMessageEntry> sharedMessages;
final List<SharedInboxEntry> sharedInbox;
final List<PersonFact> personFacts;
final List<PersonImportantDate> importantDates;
final List<PersonPreferenceSignal> preferenceSignals;
final List<AiSuggestionDraft> aiSuggestionDrafts;
LocalDataState copyWith({
List<PersonProfile>? people,
List<RelationshipMoment>? moments,
List<RelationshipIdea>? ideas,
List<ReminderRule>? reminders,
List<DashboardTask>? tasks,
List<String>? dismissedSignalIds,
List<SourceProfileLink>? sourceLinks,
List<SharedMessageEntry>? sharedMessages,
List<SharedInboxEntry>? sharedInbox,
List<PersonFact>? personFacts,
List<PersonImportantDate>? importantDates,
List<PersonPreferenceSignal>? preferenceSignals,
List<AiSuggestionDraft>? 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<String, dynamic> toJson() {
return <String, dynamic>{
'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<String, dynamic> json) {
return LocalDataState(
people: (json['people'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic person) =>
PersonProfile.fromJson(person as Map<String, dynamic>),
)
.toList(growable: false),
moments: (json['moments'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic moment) =>
RelationshipMoment.fromJson(moment as Map<String, dynamic>),
)
.toList(growable: false),
ideas: (json['ideas'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic idea) =>
RelationshipIdea.fromJson(idea as Map<String, dynamic>),
)
.toList(growable: false),
reminders: (json['reminders'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic reminder) =>
ReminderRule.fromJson(reminder as Map<String, dynamic>),
)
.toList(growable: false),
tasks: (json['tasks'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic task) =>
DashboardTask.fromJson(task as Map<String, dynamic>),
)
.toList(growable: false),
dismissedSignalIds:
(json['dismissedSignalIds'] as List<dynamic>? ?? <dynamic>[])
.map((dynamic value) => '$value')
.toList(growable: false),
sourceLinks: (json['sourceLinks'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic link) =>
SourceProfileLink.fromJson(link as Map<String, dynamic>),
)
.toList(growable: false),
sharedMessages: (json['sharedMessages'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic entry) =>
SharedMessageEntry.fromJson(entry as Map<String, dynamic>),
)
.toList(growable: false),
sharedInbox: (json['sharedInbox'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic entry) =>
SharedInboxEntry.fromJson(entry as Map<String, dynamic>),
)
.toList(growable: false),
personFacts: (json['personFacts'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic fact) => PersonFact.fromJson(fact as Map<String, dynamic>),
)
.toList(growable: false),
importantDates: (json['importantDates'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic value) =>
PersonImportantDate.fromJson(value as Map<String, dynamic>),
)
.toList(growable: false),
preferenceSignals:
(json['preferenceSignals'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic signal) => PersonPreferenceSignal.fromJson(
signal as Map<String, dynamic>,
),
)
.toList(growable: false),
aiSuggestionDrafts:
(json['aiSuggestionDrafts'] as List<dynamic>? ?? <dynamic>[])
.map(
(dynamic draft) =>
AiSuggestionDraft.fromJson(draft as Map<String, dynamic>),
)
.toList(growable: false),
);
}
static LocalDataState empty() {
return const LocalDataState(
people: <PersonProfile>[],
moments: <RelationshipMoment>[],
ideas: <RelationshipIdea>[],
reminders: <ReminderRule>[],
tasks: <DashboardTask>[],
);
}
static LocalDataState seed() => empty();
}