956 lines
29 KiB
Dart
956 lines
29 KiB
Dart
import '../../../../core/l10n/l10n.dart';
|
|
|
|
class PersonMeta {
|
|
final String? source;
|
|
final double? confidence;
|
|
final DateTime? lastUpdatedAt;
|
|
|
|
PersonMeta({this.source, this.confidence, this.lastUpdatedAt});
|
|
|
|
factory PersonMeta.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return PersonMeta();
|
|
return PersonMeta(
|
|
source: json['source'] as String?,
|
|
confidence: (json['confidence'] as num?)?.toDouble(),
|
|
lastUpdatedAt: json['last_updated_at'] != null
|
|
? DateTime.parse(json['last_updated_at'] as String)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'source': source,
|
|
'confidence': confidence,
|
|
'last_updated_at': lastUpdatedAt?.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
class Person {
|
|
final String name;
|
|
final String? relationship;
|
|
final String? role;
|
|
final String? preferredContactChannel;
|
|
final String? notes;
|
|
final PersonMeta? meta;
|
|
|
|
Person({
|
|
required this.name,
|
|
this.relationship,
|
|
this.role,
|
|
this.preferredContactChannel,
|
|
this.notes,
|
|
this.meta,
|
|
});
|
|
|
|
factory Person.fromJson(Map<String, dynamic> json) {
|
|
return Person(
|
|
name: json['name'] as String? ?? '',
|
|
relationship: json['relationship'] as String?,
|
|
role: json['role'] as String?,
|
|
preferredContactChannel: json['preferred_contact_channel'] as String?,
|
|
notes: json['notes'] as String?,
|
|
meta: json['meta'] != null
|
|
? PersonMeta.fromJson(json['meta'] as Map<String, dynamic>?)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'name': name,
|
|
'relationship': relationship,
|
|
'role': role,
|
|
'preferred_contact_channel': preferredContactChannel,
|
|
'notes': notes,
|
|
'meta': meta?.toJson(),
|
|
};
|
|
|
|
Person copyWith({
|
|
String? name,
|
|
String? relationship,
|
|
String? role,
|
|
String? preferredContactChannel,
|
|
String? notes,
|
|
PersonMeta? meta,
|
|
}) {
|
|
return Person(
|
|
name: name ?? this.name,
|
|
relationship: relationship ?? this.relationship,
|
|
role: role ?? this.role,
|
|
preferredContactChannel:
|
|
preferredContactChannel ?? this.preferredContactChannel,
|
|
notes: notes ?? this.notes,
|
|
meta: meta ?? this.meta,
|
|
);
|
|
}
|
|
}
|
|
|
|
class PlaceMeta {
|
|
final String? source;
|
|
final double? confidence;
|
|
final DateTime? lastUpdatedAt;
|
|
|
|
PlaceMeta({this.source, this.confidence, this.lastUpdatedAt});
|
|
|
|
factory PlaceMeta.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return PlaceMeta();
|
|
return PlaceMeta(
|
|
source: json['source'] as String?,
|
|
confidence: (json['confidence'] as num?)?.toDouble(),
|
|
lastUpdatedAt: json['last_updated_at'] != null
|
|
? DateTime.parse(json['last_updated_at'] as String)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'source': source,
|
|
'confidence': confidence,
|
|
'last_updated_at': lastUpdatedAt?.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
class Place {
|
|
final String name;
|
|
final String? category;
|
|
final String? address;
|
|
final String? timezone;
|
|
final int? commuteMinutes;
|
|
final String? preference;
|
|
final String? notes;
|
|
final PlaceMeta? meta;
|
|
|
|
Place({
|
|
required this.name,
|
|
this.category,
|
|
this.address,
|
|
this.timezone,
|
|
this.commuteMinutes,
|
|
this.preference,
|
|
this.notes,
|
|
this.meta,
|
|
});
|
|
|
|
factory Place.fromJson(Map<String, dynamic> json) {
|
|
return Place(
|
|
name: json['name'] as String? ?? '',
|
|
category: json['category'] as String?,
|
|
address: json['address'] as String?,
|
|
timezone: json['timezone'] as String?,
|
|
commuteMinutes: json['commute_minutes'] as int?,
|
|
preference: json['preference'] as String?,
|
|
notes: json['notes'] as String?,
|
|
meta: json['meta'] != null
|
|
? PlaceMeta.fromJson(json['meta'] as Map<String, dynamic>?)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'name': name,
|
|
'category': category,
|
|
'address': address,
|
|
'timezone': timezone,
|
|
'commute_minutes': commuteMinutes,
|
|
'preference': preference,
|
|
'notes': notes,
|
|
'meta': meta?.toJson(),
|
|
};
|
|
|
|
Place copyWith({
|
|
String? name,
|
|
String? category,
|
|
String? address,
|
|
String? timezone,
|
|
int? commuteMinutes,
|
|
String? preference,
|
|
String? notes,
|
|
PlaceMeta? meta,
|
|
}) {
|
|
return Place(
|
|
name: name ?? this.name,
|
|
category: category ?? this.category,
|
|
address: address ?? this.address,
|
|
timezone: timezone ?? this.timezone,
|
|
commuteMinutes: commuteMinutes ?? this.commuteMinutes,
|
|
preference: preference ?? this.preference,
|
|
notes: notes ?? this.notes,
|
|
meta: meta ?? this.meta,
|
|
);
|
|
}
|
|
}
|
|
|
|
class UserPreferences {
|
|
final String? communicationStyle;
|
|
final List<String> languagePreference;
|
|
final String? locationPreference;
|
|
final String? workLifestyle;
|
|
final List<String> notificationPreference;
|
|
|
|
UserPreferences({
|
|
this.communicationStyle,
|
|
this.languagePreference = const [],
|
|
this.locationPreference,
|
|
this.workLifestyle,
|
|
this.notificationPreference = const [],
|
|
});
|
|
|
|
factory UserPreferences.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return UserPreferences();
|
|
return UserPreferences(
|
|
communicationStyle: json['communication_style'] as String?,
|
|
languagePreference:
|
|
(json['language_preference'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
locationPreference: json['location_preference'] as String?,
|
|
workLifestyle: json['work_lifestyle'] as String?,
|
|
notificationPreference:
|
|
(json['notification_preference'] as List<dynamic>?)?.cast<String>() ??
|
|
[],
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'communication_style': communicationStyle,
|
|
'language_preference': languagePreference,
|
|
'location_preference': locationPreference,
|
|
'work_lifestyle': workLifestyle,
|
|
'notification_preference': notificationPreference,
|
|
};
|
|
|
|
UserPreferences copyWith({
|
|
String? communicationStyle,
|
|
List<String>? languagePreference,
|
|
String? locationPreference,
|
|
String? workLifestyle,
|
|
List<String>? notificationPreference,
|
|
}) {
|
|
return UserPreferences(
|
|
communicationStyle: communicationStyle ?? this.communicationStyle,
|
|
languagePreference: languagePreference ?? this.languagePreference,
|
|
locationPreference: locationPreference ?? this.locationPreference,
|
|
workLifestyle: workLifestyle ?? this.workLifestyle,
|
|
notificationPreference:
|
|
notificationPreference ?? this.notificationPreference,
|
|
);
|
|
}
|
|
}
|
|
|
|
class TimeWindow {
|
|
final List<String> weekdays;
|
|
final String? start;
|
|
final String? end;
|
|
|
|
TimeWindow({this.weekdays = const [], this.start, this.end});
|
|
|
|
factory TimeWindow.fromJson(Map<String, dynamic> json) {
|
|
return TimeWindow(
|
|
weekdays: (json['weekdays'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
start: json['start'] as String?,
|
|
end: json['end'] as String?,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'weekdays': weekdays,
|
|
'start': start,
|
|
'end': end,
|
|
};
|
|
}
|
|
|
|
class SchedulingPreferences {
|
|
final List<TimeWindow> productiveWindows;
|
|
final List<TimeWindow> preferredMeetingWindows;
|
|
final List<TimeWindow> noMeetingWindows;
|
|
final List<TimeWindow> deepWorkWindows;
|
|
final List<int> preferredMeetingDurationMinutes;
|
|
final int? meetingBufferMinutes;
|
|
final int? maxMeetingsPerDay;
|
|
final String? notes;
|
|
|
|
SchedulingPreferences({
|
|
this.productiveWindows = const [],
|
|
this.preferredMeetingWindows = const [],
|
|
this.noMeetingWindows = const [],
|
|
this.deepWorkWindows = const [],
|
|
this.preferredMeetingDurationMinutes = const [30, 60],
|
|
this.meetingBufferMinutes,
|
|
this.maxMeetingsPerDay,
|
|
this.notes,
|
|
});
|
|
|
|
factory SchedulingPreferences.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return SchedulingPreferences();
|
|
return SchedulingPreferences(
|
|
productiveWindows:
|
|
(json['productive_windows'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
preferredMeetingWindows:
|
|
(json['preferred_meeting_windows'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
noMeetingWindows:
|
|
(json['no_meeting_windows'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
deepWorkWindows:
|
|
(json['deep_work_windows'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
preferredMeetingDurationMinutes:
|
|
(json['preferred_meeting_duration_minutes'] as List<dynamic>?)
|
|
?.cast<int>() ??
|
|
[30, 60],
|
|
meetingBufferMinutes: json['meeting_buffer_minutes'] as int?,
|
|
maxMeetingsPerDay: json['max_meetings_per_day'] as int?,
|
|
notes: json['notes'] as String?,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'productive_windows': productiveWindows.map((e) => e.toJson()).toList(),
|
|
'preferred_meeting_windows': preferredMeetingWindows
|
|
.map((e) => e.toJson())
|
|
.toList(),
|
|
'no_meeting_windows': noMeetingWindows.map((e) => e.toJson()).toList(),
|
|
'deep_work_windows': deepWorkWindows.map((e) => e.toJson()).toList(),
|
|
'preferred_meeting_duration_minutes': preferredMeetingDurationMinutes,
|
|
'meeting_buffer_minutes': meetingBufferMinutes,
|
|
'max_meetings_per_day': maxMeetingsPerDay,
|
|
'notes': notes,
|
|
};
|
|
|
|
SchedulingPreferences copyWith({
|
|
List<TimeWindow>? productiveWindows,
|
|
List<TimeWindow>? preferredMeetingWindows,
|
|
List<TimeWindow>? noMeetingWindows,
|
|
List<TimeWindow>? deepWorkWindows,
|
|
List<int>? preferredMeetingDurationMinutes,
|
|
int? meetingBufferMinutes,
|
|
int? maxMeetingsPerDay,
|
|
String? notes,
|
|
}) {
|
|
return SchedulingPreferences(
|
|
productiveWindows: productiveWindows ?? this.productiveWindows,
|
|
preferredMeetingWindows:
|
|
preferredMeetingWindows ?? this.preferredMeetingWindows,
|
|
noMeetingWindows: noMeetingWindows ?? this.noMeetingWindows,
|
|
deepWorkWindows: deepWorkWindows ?? this.deepWorkWindows,
|
|
preferredMeetingDurationMinutes:
|
|
preferredMeetingDurationMinutes ??
|
|
this.preferredMeetingDurationMinutes,
|
|
meetingBufferMinutes: meetingBufferMinutes ?? this.meetingBufferMinutes,
|
|
maxMeetingsPerDay: maxMeetingsPerDay ?? this.maxMeetingsPerDay,
|
|
notes: notes ?? this.notes,
|
|
);
|
|
}
|
|
}
|
|
|
|
class RecurringRoutineMeta {
|
|
final String? source;
|
|
final double? confidence;
|
|
final DateTime? lastUpdatedAt;
|
|
|
|
RecurringRoutineMeta({this.source, this.confidence, this.lastUpdatedAt});
|
|
|
|
factory RecurringRoutineMeta.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return RecurringRoutineMeta();
|
|
return RecurringRoutineMeta(
|
|
source: json['source'] as String?,
|
|
confidence: (json['confidence'] as num?)?.toDouble(),
|
|
lastUpdatedAt: json['last_updated_at'] != null
|
|
? DateTime.parse(json['last_updated_at'] as String)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'source': source,
|
|
'confidence': confidence,
|
|
'last_updated_at': lastUpdatedAt?.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
class RecurringRoutine {
|
|
final String name;
|
|
final String? description;
|
|
final String? cadence;
|
|
final List<TimeWindow> timeWindows;
|
|
final String? importance;
|
|
final RecurringRoutineMeta? meta;
|
|
|
|
RecurringRoutine({
|
|
required this.name,
|
|
this.description,
|
|
this.cadence,
|
|
this.timeWindows = const [],
|
|
this.importance,
|
|
this.meta,
|
|
});
|
|
|
|
factory RecurringRoutine.fromJson(Map<String, dynamic> json) {
|
|
return RecurringRoutine(
|
|
name: json['name'] as String? ?? '',
|
|
description: json['description'] as String?,
|
|
cadence: json['cadence'] as String?,
|
|
timeWindows:
|
|
(json['time_windows'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
importance: json['importance'] as String?,
|
|
meta: json['meta'] != null
|
|
? RecurringRoutineMeta.fromJson(json['meta'] as Map<String, dynamic>?)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'name': name,
|
|
'description': description,
|
|
'cadence': cadence,
|
|
'time_windows': timeWindows.map((e) => e.toJson()).toList(),
|
|
'importance': importance,
|
|
'meta': meta?.toJson(),
|
|
};
|
|
|
|
RecurringRoutine copyWith({
|
|
String? name,
|
|
String? description,
|
|
String? cadence,
|
|
List<TimeWindow>? timeWindows,
|
|
String? importance,
|
|
RecurringRoutineMeta? meta,
|
|
}) {
|
|
return RecurringRoutine(
|
|
name: name ?? this.name,
|
|
description: description ?? this.description,
|
|
cadence: cadence ?? this.cadence,
|
|
timeWindows: timeWindows ?? this.timeWindows,
|
|
importance: importance ?? this.importance,
|
|
meta: meta ?? this.meta,
|
|
);
|
|
}
|
|
}
|
|
|
|
class UserMemoryContent {
|
|
final String? occupation;
|
|
final String? timezone;
|
|
final String? primaryLanguage;
|
|
final List<Person> people;
|
|
final List<Place> places;
|
|
final UserPreferences preferences;
|
|
final SchedulingPreferences schedulingPreferences;
|
|
final List<String> interests;
|
|
final List<String> avoidTopics;
|
|
final List<String> customRules;
|
|
final List<RecurringRoutine> recurringRoutines;
|
|
|
|
UserMemoryContent({
|
|
this.occupation,
|
|
this.timezone,
|
|
this.primaryLanguage,
|
|
this.people = const [],
|
|
this.places = const [],
|
|
UserPreferences? preferences,
|
|
SchedulingPreferences? schedulingPreferences,
|
|
this.interests = const [],
|
|
this.avoidTopics = const [],
|
|
this.customRules = const [],
|
|
this.recurringRoutines = const [],
|
|
}) : preferences = preferences ?? UserPreferences(),
|
|
schedulingPreferences = schedulingPreferences ?? SchedulingPreferences();
|
|
|
|
factory UserMemoryContent.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return UserMemoryContent();
|
|
return UserMemoryContent(
|
|
occupation: json['occupation'] as String?,
|
|
timezone: json['timezone'] as String?,
|
|
primaryLanguage: json['primary_language'] as String?,
|
|
people:
|
|
(json['people'] as List<dynamic>?)
|
|
?.map((e) => Person.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
places:
|
|
(json['places'] as List<dynamic>?)
|
|
?.map((e) => Place.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
preferences: UserPreferences.fromJson(
|
|
json['preferences'] as Map<String, dynamic>?,
|
|
),
|
|
schedulingPreferences: SchedulingPreferences.fromJson(
|
|
json['scheduling_preferences'] as Map<String, dynamic>?,
|
|
),
|
|
interests: (json['interests'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
avoidTopics:
|
|
(json['avoid_topics'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
customRules:
|
|
(json['custom_rules'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
recurringRoutines:
|
|
(json['recurring_routines'] as List<dynamic>?)
|
|
?.map((e) => RecurringRoutine.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'occupation': occupation,
|
|
'timezone': timezone,
|
|
'primary_language': primaryLanguage,
|
|
'people': people.map((e) => e.toJson()).toList(),
|
|
'places': places.map((e) => e.toJson()).toList(),
|
|
'preferences': preferences.toJson(),
|
|
'scheduling_preferences': schedulingPreferences.toJson(),
|
|
'interests': interests,
|
|
'avoid_topics': avoidTopics,
|
|
'custom_rules': customRules,
|
|
'recurring_routines': recurringRoutines.map((e) => e.toJson()).toList(),
|
|
};
|
|
|
|
UserMemoryContent copyWith({
|
|
String? occupation,
|
|
String? timezone,
|
|
String? primaryLanguage,
|
|
List<Person>? people,
|
|
List<Place>? places,
|
|
UserPreferences? preferences,
|
|
SchedulingPreferences? schedulingPreferences,
|
|
List<String>? interests,
|
|
List<String>? avoidTopics,
|
|
List<String>? customRules,
|
|
List<RecurringRoutine>? recurringRoutines,
|
|
}) {
|
|
return UserMemoryContent(
|
|
occupation: occupation ?? this.occupation,
|
|
timezone: timezone ?? this.timezone,
|
|
primaryLanguage: primaryLanguage ?? this.primaryLanguage,
|
|
people: people ?? this.people,
|
|
places: places ?? this.places,
|
|
preferences: preferences ?? this.preferences,
|
|
schedulingPreferences:
|
|
schedulingPreferences ?? this.schedulingPreferences,
|
|
interests: interests ?? this.interests,
|
|
avoidTopics: avoidTopics ?? this.avoidTopics,
|
|
customRules: customRules ?? this.customRules,
|
|
recurringRoutines: recurringRoutines ?? this.recurringRoutines,
|
|
);
|
|
}
|
|
|
|
String get summary {
|
|
final parts = <String>[];
|
|
if (occupation != null && occupation!.isNotEmpty) {
|
|
parts.add(occupation!);
|
|
}
|
|
if (people.isNotEmpty) {
|
|
parts.add(L10n.current.memorySummaryContactsCount(people.length));
|
|
}
|
|
if (places.isNotEmpty) {
|
|
parts.add(L10n.current.memorySummaryPlacesCount(places.length));
|
|
}
|
|
if (interests.isNotEmpty) {
|
|
parts.add(L10n.current.memorySummaryInterestsCount(interests.length));
|
|
}
|
|
return parts.isEmpty ? L10n.current.memoryNoInfo : parts.join(' · ');
|
|
}
|
|
}
|
|
|
|
class KeyMilestone {
|
|
final String name;
|
|
final DateTime? dueDate;
|
|
final String? status;
|
|
final String? notes;
|
|
|
|
KeyMilestone({required this.name, this.dueDate, this.status, this.notes});
|
|
|
|
factory KeyMilestone.fromJson(Map<String, dynamic> json) {
|
|
return KeyMilestone(
|
|
name: json['name'] as String? ?? '',
|
|
dueDate: json['due_date'] != null
|
|
? DateTime.parse(json['due_date'] as String)
|
|
: null,
|
|
status: json['status'] as String?,
|
|
notes: json['notes'] as String?,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'name': name,
|
|
'due_date': dueDate?.toIso8601String().split('T').first,
|
|
'status': status,
|
|
'notes': notes,
|
|
};
|
|
}
|
|
|
|
class CurrentProject {
|
|
final String name;
|
|
final String? description;
|
|
final String? status;
|
|
final String? priority;
|
|
final DateTime? deadline;
|
|
final List<String> collaborators;
|
|
final List<KeyMilestone> keyMilestones;
|
|
final String? notes;
|
|
|
|
CurrentProject({
|
|
required this.name,
|
|
this.description,
|
|
this.status,
|
|
this.priority,
|
|
this.deadline,
|
|
this.collaborators = const [],
|
|
this.keyMilestones = const [],
|
|
this.notes,
|
|
});
|
|
|
|
factory CurrentProject.fromJson(Map<String, dynamic> json) {
|
|
return CurrentProject(
|
|
name: json['name'] as String? ?? '',
|
|
description: json['description'] as String?,
|
|
status: json['status'] as String?,
|
|
priority: json['priority'] as String?,
|
|
deadline: json['deadline'] != null
|
|
? DateTime.parse(json['deadline'] as String)
|
|
: null,
|
|
collaborators:
|
|
(json['collaborators'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
keyMilestones:
|
|
(json['key_milestones'] as List<dynamic>?)
|
|
?.map((e) => KeyMilestone.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
notes: json['notes'] as String?,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'name': name,
|
|
'description': description,
|
|
'status': status,
|
|
'priority': priority,
|
|
'deadline': deadline?.toIso8601String().split('T').first,
|
|
'collaborators': collaborators,
|
|
'key_milestones': keyMilestones.map((e) => e.toJson()).toList(),
|
|
'notes': notes,
|
|
};
|
|
|
|
CurrentProject copyWith({
|
|
String? name,
|
|
String? description,
|
|
String? status,
|
|
String? priority,
|
|
DateTime? deadline,
|
|
List<String>? collaborators,
|
|
List<KeyMilestone>? keyMilestones,
|
|
String? notes,
|
|
}) {
|
|
return CurrentProject(
|
|
name: name ?? this.name,
|
|
description: description ?? this.description,
|
|
status: status ?? this.status,
|
|
priority: priority ?? this.priority,
|
|
deadline: deadline ?? this.deadline,
|
|
collaborators: collaborators ?? this.collaborators,
|
|
keyMilestones: keyMilestones ?? this.keyMilestones,
|
|
notes: notes ?? this.notes,
|
|
);
|
|
}
|
|
}
|
|
|
|
class WorkHabits {
|
|
final List<TimeWindow> availableHours;
|
|
final List<TimeWindow> deepWorkBlocks;
|
|
final List<TimeWindow> preferredMeetingWindows;
|
|
final List<TimeWindow> noMeetingWindows;
|
|
final List<int> preferredMeetingDurationMinutes;
|
|
final String? notificationChannel;
|
|
final String? notes;
|
|
|
|
WorkHabits({
|
|
this.availableHours = const [],
|
|
this.deepWorkBlocks = const [],
|
|
this.preferredMeetingWindows = const [],
|
|
this.noMeetingWindows = const [],
|
|
this.preferredMeetingDurationMinutes = const [30, 60],
|
|
this.notificationChannel,
|
|
this.notes,
|
|
});
|
|
|
|
factory WorkHabits.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return WorkHabits();
|
|
return WorkHabits(
|
|
availableHours:
|
|
(json['available_hours'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
deepWorkBlocks:
|
|
(json['deep_work_blocks'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
preferredMeetingWindows:
|
|
(json['preferred_meeting_windows'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
noMeetingWindows:
|
|
(json['no_meeting_windows'] as List<dynamic>?)
|
|
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
preferredMeetingDurationMinutes:
|
|
(json['preferred_meeting_duration_minutes'] as List<dynamic>?)
|
|
?.cast<int>() ??
|
|
[30, 60],
|
|
notificationChannel: json['notification_channel'] as String?,
|
|
notes: json['notes'] as String?,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'available_hours': availableHours.map((e) => e.toJson()).toList(),
|
|
'deep_work_blocks': deepWorkBlocks.map((e) => e.toJson()).toList(),
|
|
'preferred_meeting_windows': preferredMeetingWindows
|
|
.map((e) => e.toJson())
|
|
.toList(),
|
|
'no_meeting_windows': noMeetingWindows.map((e) => e.toJson()).toList(),
|
|
'preferred_meeting_duration_minutes': preferredMeetingDurationMinutes,
|
|
'notification_channel': notificationChannel,
|
|
'notes': notes,
|
|
};
|
|
|
|
WorkHabits copyWith({
|
|
List<TimeWindow>? availableHours,
|
|
List<TimeWindow>? deepWorkBlocks,
|
|
List<TimeWindow>? preferredMeetingWindows,
|
|
List<TimeWindow>? noMeetingWindows,
|
|
List<int>? preferredMeetingDurationMinutes,
|
|
String? notificationChannel,
|
|
String? notes,
|
|
}) {
|
|
return WorkHabits(
|
|
availableHours: availableHours ?? this.availableHours,
|
|
deepWorkBlocks: deepWorkBlocks ?? this.deepWorkBlocks,
|
|
preferredMeetingWindows:
|
|
preferredMeetingWindows ?? this.preferredMeetingWindows,
|
|
noMeetingWindows: noMeetingWindows ?? this.noMeetingWindows,
|
|
preferredMeetingDurationMinutes:
|
|
preferredMeetingDurationMinutes ??
|
|
this.preferredMeetingDurationMinutes,
|
|
notificationChannel: notificationChannel ?? this.notificationChannel,
|
|
notes: notes ?? this.notes,
|
|
);
|
|
}
|
|
}
|
|
|
|
class TeamMemberMeta {
|
|
final String? source;
|
|
final double? confidence;
|
|
final DateTime? lastUpdatedAt;
|
|
|
|
TeamMemberMeta({this.source, this.confidence, this.lastUpdatedAt});
|
|
|
|
factory TeamMemberMeta.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return TeamMemberMeta();
|
|
return TeamMemberMeta(
|
|
source: json['source'] as String?,
|
|
confidence: (json['confidence'] as num?)?.toDouble(),
|
|
lastUpdatedAt: json['last_updated_at'] != null
|
|
? DateTime.parse(json['last_updated_at'] as String)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'source': source,
|
|
'confidence': confidence,
|
|
'last_updated_at': lastUpdatedAt?.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
class TeamMember {
|
|
final String name;
|
|
final String? role;
|
|
final String? relationship;
|
|
final String? preferredContactChannel;
|
|
final String? notes;
|
|
final TeamMemberMeta? meta;
|
|
|
|
TeamMember({
|
|
required this.name,
|
|
this.role,
|
|
this.relationship,
|
|
this.preferredContactChannel,
|
|
this.notes,
|
|
this.meta,
|
|
});
|
|
|
|
factory TeamMember.fromJson(Map<String, dynamic> json) {
|
|
return TeamMember(
|
|
name: json['name'] as String? ?? '',
|
|
role: json['role'] as String?,
|
|
relationship: json['relationship'] as String?,
|
|
preferredContactChannel: json['preferred_contact_channel'] as String?,
|
|
notes: json['notes'] as String?,
|
|
meta: json['meta'] != null
|
|
? TeamMemberMeta.fromJson(json['meta'] as Map<String, dynamic>?)
|
|
: null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'name': name,
|
|
'role': role,
|
|
'relationship': relationship,
|
|
'preferred_contact_channel': preferredContactChannel,
|
|
'notes': notes,
|
|
'meta': meta?.toJson(),
|
|
};
|
|
|
|
TeamMember copyWith({
|
|
String? name,
|
|
String? role,
|
|
String? relationship,
|
|
String? preferredContactChannel,
|
|
String? notes,
|
|
TeamMemberMeta? meta,
|
|
}) {
|
|
return TeamMember(
|
|
name: name ?? this.name,
|
|
role: role ?? this.role,
|
|
relationship: relationship ?? this.relationship,
|
|
preferredContactChannel:
|
|
preferredContactChannel ?? this.preferredContactChannel,
|
|
notes: notes ?? this.notes,
|
|
meta: meta ?? this.meta,
|
|
);
|
|
}
|
|
}
|
|
|
|
class WorkProfileContent {
|
|
final String? occupation;
|
|
final List<String> expertise;
|
|
final List<String> preferredTools;
|
|
final List<CurrentProject> currentProjects;
|
|
final WorkHabits workHabits;
|
|
final List<TeamMember> teamMembers;
|
|
final String? teamContext;
|
|
final List<String> workRules;
|
|
|
|
WorkProfileContent({
|
|
this.occupation,
|
|
this.expertise = const [],
|
|
this.preferredTools = const [],
|
|
this.currentProjects = const [],
|
|
WorkHabits? workHabits,
|
|
this.teamMembers = const [],
|
|
this.teamContext,
|
|
this.workRules = const [],
|
|
}) : workHabits = workHabits ?? WorkHabits();
|
|
|
|
factory WorkProfileContent.fromJson(Map<String, dynamic>? json) {
|
|
if (json == null) return WorkProfileContent();
|
|
return WorkProfileContent(
|
|
occupation: json['occupation'] as String?,
|
|
expertise: (json['expertise'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
preferredTools:
|
|
(json['preferred_tools'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
currentProjects:
|
|
(json['current_projects'] as List<dynamic>?)
|
|
?.map((e) => CurrentProject.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
workHabits: WorkHabits.fromJson(
|
|
json['work_habits'] as Map<String, dynamic>?,
|
|
),
|
|
teamMembers:
|
|
(json['team_members'] as List<dynamic>?)
|
|
?.map((e) => TeamMember.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
teamContext: json['team_context'] as String?,
|
|
workRules: (json['work_rules'] as List<dynamic>?)?.cast<String>() ?? [],
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'occupation': occupation,
|
|
'expertise': expertise,
|
|
'preferred_tools': preferredTools,
|
|
'current_projects': currentProjects.map((e) => e.toJson()).toList(),
|
|
'work_habits': workHabits.toJson(),
|
|
'team_members': teamMembers.map((e) => e.toJson()).toList(),
|
|
'team_context': teamContext,
|
|
'work_rules': workRules,
|
|
};
|
|
|
|
WorkProfileContent copyWith({
|
|
String? occupation,
|
|
List<String>? expertise,
|
|
List<String>? preferredTools,
|
|
List<CurrentProject>? currentProjects,
|
|
WorkHabits? workHabits,
|
|
List<TeamMember>? teamMembers,
|
|
String? teamContext,
|
|
List<String>? workRules,
|
|
}) {
|
|
return WorkProfileContent(
|
|
occupation: occupation ?? this.occupation,
|
|
expertise: expertise ?? this.expertise,
|
|
preferredTools: preferredTools ?? this.preferredTools,
|
|
currentProjects: currentProjects ?? this.currentProjects,
|
|
workHabits: workHabits ?? this.workHabits,
|
|
teamMembers: teamMembers ?? this.teamMembers,
|
|
teamContext: teamContext ?? this.teamContext,
|
|
workRules: workRules ?? this.workRules,
|
|
);
|
|
}
|
|
|
|
String get summary {
|
|
final parts = <String>[];
|
|
if (occupation != null && occupation!.isNotEmpty) {
|
|
parts.add(occupation!);
|
|
}
|
|
if (expertise.isNotEmpty) {
|
|
parts.add(L10n.current.memorySummaryExpertiseCount(expertise.length));
|
|
}
|
|
if (currentProjects.isNotEmpty) {
|
|
parts.add(
|
|
L10n.current.memorySummaryProjectsCount(currentProjects.length),
|
|
);
|
|
}
|
|
if (teamMembers.isNotEmpty) {
|
|
parts.add(L10n.current.memorySummaryTeamMembersCount(teamMembers.length));
|
|
}
|
|
return parts.isEmpty ? L10n.current.memoryNoInfo : parts.join(' · ');
|
|
}
|
|
}
|
|
|
|
class MemoryListResponse {
|
|
final UserMemoryContent? userMemory;
|
|
final WorkProfileContent? workMemory;
|
|
|
|
MemoryListResponse({this.userMemory, this.workMemory});
|
|
|
|
factory MemoryListResponse.fromJson(Map<String, dynamic> json) {
|
|
return MemoryListResponse(
|
|
userMemory: json['user_memory'] != null
|
|
? UserMemoryContent.fromJson(
|
|
json['user_memory'] as Map<String, dynamic>?,
|
|
)
|
|
: null,
|
|
workMemory: json['work_memory'] != null
|
|
? WorkProfileContent.fromJson(
|
|
json['work_memory'] as Map<String, dynamic>?,
|
|
)
|
|
: null,
|
|
);
|
|
}
|
|
}
|