158 lines
6.0 KiB
Dart
158 lines
6.0 KiB
Dart
import 'dart:convert';
|
|
|
|
/// Represents the daily record for a specific calendar date in the Word of the Day practice.
|
|
/// Supports both Single Word Mode (1 resonant archetype) and Triptych Mode (Morning, Day, Evening).
|
|
class WordOfDayRecord {
|
|
final String dateKey; // 'yyyy-MM-dd'
|
|
final int wordId; // base id for Single Word Mode
|
|
final bool isRevealed; // whether Single Word is revealed
|
|
final bool isStepCompleted; // whether Single Word step is checked off
|
|
final String diaryNote; // user reflection on daily synchronicity
|
|
final DateTime? revealedAt;
|
|
final DateTime? completedAt;
|
|
|
|
// Triptych fields (3 words: Morning, Day, Evening)
|
|
final bool isTriptychMode;
|
|
final int morningWordId;
|
|
final int dayWordId;
|
|
final int eveningWordId;
|
|
final bool isMorningRevealed;
|
|
final bool isDayRevealed;
|
|
final bool isEveningRevealed;
|
|
final bool isDayStepCompleted;
|
|
final DateTime? morningRevealedAt;
|
|
final DateTime? dayRevealedAt;
|
|
final DateTime? eveningRevealedAt;
|
|
|
|
const WordOfDayRecord({
|
|
required this.dateKey,
|
|
required this.wordId,
|
|
this.isRevealed = false,
|
|
this.isStepCompleted = false,
|
|
this.diaryNote = '',
|
|
this.revealedAt,
|
|
this.completedAt,
|
|
this.isTriptychMode = false,
|
|
this.morningWordId = 0,
|
|
this.dayWordId = 0,
|
|
this.eveningWordId = 0,
|
|
this.isMorningRevealed = false,
|
|
this.isDayRevealed = false,
|
|
this.isEveningRevealed = false,
|
|
this.isDayStepCompleted = false,
|
|
this.morningRevealedAt,
|
|
this.dayRevealedAt,
|
|
this.eveningRevealedAt,
|
|
});
|
|
|
|
bool get isAnyRevealed =>
|
|
isRevealed || isMorningRevealed || isDayRevealed || isEveningRevealed;
|
|
|
|
bool get areAllTriptychRevealed =>
|
|
isMorningRevealed && isDayRevealed && isEveningRevealed;
|
|
|
|
bool get isAnyStepCompleted => isStepCompleted || isDayStepCompleted;
|
|
|
|
WordOfDayRecord copyWith({
|
|
String? dateKey,
|
|
int? wordId,
|
|
bool? isRevealed,
|
|
bool? isStepCompleted,
|
|
String? diaryNote,
|
|
DateTime? revealedAt,
|
|
DateTime? completedAt,
|
|
bool? isTriptychMode,
|
|
int? morningWordId,
|
|
int? dayWordId,
|
|
int? eveningWordId,
|
|
bool? isMorningRevealed,
|
|
bool? isDayRevealed,
|
|
bool? isEveningRevealed,
|
|
bool? isDayStepCompleted,
|
|
DateTime? morningRevealedAt,
|
|
DateTime? dayRevealedAt,
|
|
DateTime? eveningRevealedAt,
|
|
}) {
|
|
return WordOfDayRecord(
|
|
dateKey: dateKey ?? this.dateKey,
|
|
wordId: wordId ?? this.wordId,
|
|
isRevealed: isRevealed ?? this.isRevealed,
|
|
isStepCompleted: isStepCompleted ?? this.isStepCompleted,
|
|
diaryNote: diaryNote ?? this.diaryNote,
|
|
revealedAt: revealedAt ?? this.revealedAt,
|
|
completedAt: completedAt ?? this.completedAt,
|
|
isTriptychMode: isTriptychMode ?? this.isTriptychMode,
|
|
morningWordId: morningWordId ?? this.morningWordId,
|
|
dayWordId: dayWordId ?? this.dayWordId,
|
|
eveningWordId: eveningWordId ?? this.eveningWordId,
|
|
isMorningRevealed: isMorningRevealed ?? this.isMorningRevealed,
|
|
isDayRevealed: isDayRevealed ?? this.isDayRevealed,
|
|
isEveningRevealed: isEveningRevealed ?? this.isEveningRevealed,
|
|
isDayStepCompleted: isDayStepCompleted ?? this.isDayStepCompleted,
|
|
morningRevealedAt: morningRevealedAt ?? this.morningRevealedAt,
|
|
dayRevealedAt: dayRevealedAt ?? this.dayRevealedAt,
|
|
eveningRevealedAt: eveningRevealedAt ?? this.eveningRevealedAt,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toMap() => {
|
|
'dateKey': dateKey,
|
|
'wordId': wordId,
|
|
'isRevealed': isRevealed,
|
|
'isStepCompleted': isStepCompleted,
|
|
'diaryNote': diaryNote,
|
|
if (revealedAt != null) 'revealedAt': revealedAt!.toIso8601String(),
|
|
if (completedAt != null) 'completedAt': completedAt!.toIso8601String(),
|
|
'isTriptychMode': isTriptychMode,
|
|
'morningWordId': morningWordId,
|
|
'dayWordId': dayWordId,
|
|
'eveningWordId': eveningWordId,
|
|
'isMorningRevealed': isMorningRevealed,
|
|
'isDayRevealed': isDayRevealed,
|
|
'isEveningRevealed': isEveningRevealed,
|
|
'isDayStepCompleted': isDayStepCompleted,
|
|
if (morningRevealedAt != null)
|
|
'morningRevealedAt': morningRevealedAt!.toIso8601String(),
|
|
if (dayRevealedAt != null)
|
|
'dayRevealedAt': dayRevealedAt!.toIso8601String(),
|
|
if (eveningRevealedAt != null)
|
|
'eveningRevealedAt': eveningRevealedAt!.toIso8601String(),
|
|
};
|
|
|
|
factory WordOfDayRecord.fromMap(Map<String, dynamic> map) => WordOfDayRecord(
|
|
dateKey: map['dateKey'] as String? ?? '',
|
|
wordId: (map['wordId'] as num?)?.toInt() ?? 0,
|
|
isRevealed: map['isRevealed'] as bool? ?? false,
|
|
isStepCompleted: map['isStepCompleted'] as bool? ?? false,
|
|
diaryNote: map['diaryNote'] as String? ?? '',
|
|
revealedAt: map['revealedAt'] != null
|
|
? DateTime.tryParse(map['revealedAt'] as String)
|
|
: null,
|
|
completedAt: map['completedAt'] != null
|
|
? DateTime.tryParse(map['completedAt'] as String)
|
|
: null,
|
|
isTriptychMode: map['isTriptychMode'] as bool? ?? false,
|
|
morningWordId: (map['morningWordId'] as num?)?.toInt() ?? 0,
|
|
dayWordId: (map['dayWordId'] as num?)?.toInt() ?? 0,
|
|
eveningWordId: (map['eveningWordId'] as num?)?.toInt() ?? 0,
|
|
isMorningRevealed: map['isMorningRevealed'] as bool? ?? false,
|
|
isDayRevealed: map['isDayRevealed'] as bool? ?? false,
|
|
isEveningRevealed: map['isEveningRevealed'] as bool? ?? false,
|
|
isDayStepCompleted: map['isDayStepCompleted'] as bool? ?? false,
|
|
morningRevealedAt: map['morningRevealedAt'] != null
|
|
? DateTime.tryParse(map['morningRevealedAt'] as String)
|
|
: null,
|
|
dayRevealedAt: map['dayRevealedAt'] != null
|
|
? DateTime.tryParse(map['dayRevealedAt'] as String)
|
|
: null,
|
|
eveningRevealedAt: map['eveningRevealedAt'] != null
|
|
? DateTime.tryParse(map['eveningRevealedAt'] as String)
|
|
: null,
|
|
);
|
|
|
|
String toJson() => json.encode(toMap());
|
|
|
|
factory WordOfDayRecord.fromJson(String source) =>
|
|
WordOfDayRecord.fromMap(json.decode(source) as Map<String, dynamic>);
|
|
}
|