feat: Implement husband features and fix iOS Safari web startup

Implement initial features for husband's companion app, including mock data
service and husband notes screen. Refactor scripture and cycle services
for improved stability and testability. Address iOS Safari web app
startup issue by removing deprecated initialization.

- Implemented MockDataService and HusbandNotesScreen.
- Converted _DashboardTab and DevotionalScreen to StatefulWidgets for robust
  scripture provider initialization.
- Refactored CycleService to use immutable CycleInfo class, reducing UI rebuilds.
- Removed deprecated window.flutterConfiguration from index.html, resolving
  Flutter web app startup failure on iOS Safari.
- Updated and fixed related tests.
This commit is contained in:
2025-12-26 22:40:52 -06:00
parent 464692ce56
commit b4b2bfe749
47 changed files with 240110 additions and 2578 deletions

View File

@@ -7,10 +7,10 @@ part 'user_profile.g.dart';
enum RelationshipStatus {
@HiveField(0)
single,
@HiveField(1)
engaged,
@HiveField(2)
married,
}
@@ -20,16 +20,14 @@ enum RelationshipStatus {
enum FertilityGoal {
@HiveField(0)
tryingToConceive, // TTC
@HiveField(1)
tryingToAvoid, // TTA - NFP
@HiveField(2)
justTracking,
}
<<<<<<< HEAD
=======
@HiveType(typeId: 9)
enum BibleTranslation {
@HiveField(0)
@@ -44,63 +42,67 @@ enum BibleTranslation {
nasb,
@HiveField(5)
kjv,
@HiveField(6)
msg,
}
>>>>>>> 6742220 (Your commit message here)
/// User profile model
@HiveType(typeId: 2)
class UserProfile extends HiveObject {
@HiveField(0)
String id;
@HiveField(1)
String name;
@HiveField(2)
RelationshipStatus relationshipStatus;
@HiveField(3)
FertilityGoal? fertilityGoal;
@HiveField(4)
int averageCycleLength;
@HiveField(5)
int averagePeriodLength;
@HiveField(6)
DateTime? lastPeriodStartDate;
@HiveField(7)
bool notificationsEnabled;
@HiveField(8)
String? devotionalTime; // HH:mm format
@HiveField(9)
bool hasCompletedOnboarding;
@HiveField(10)
DateTime createdAt;
@HiveField(11)
DateTime updatedAt;
@HiveField(12)
String? partnerName; // For married users
@HiveField(14, defaultValue: UserRole.wife)
UserRole role;
@HiveField(15, defaultValue: false)
bool isIrregularCycle;
<<<<<<< HEAD
=======
@HiveField(16, defaultValue: BibleTranslation.esv)
BibleTranslation bibleTranslation;
>>>>>>> 6742220 (Your commit message here)
@HiveField(17)
List<String>? favoriteFoods;
@HiveField(18, defaultValue: false)
bool isDataShared;
UserProfile({
required this.id,
required this.name,
@@ -115,36 +117,35 @@ class UserProfile extends HiveObject {
required this.createdAt,
required this.updatedAt,
this.partnerName,
<<<<<<< HEAD
this.role = UserRole.wife,
this.isIrregularCycle = false,
=======
this.role = UserRole.wife,
this.isIrregularCycle = false,
this.bibleTranslation = BibleTranslation.esv,
>>>>>>> 6742220 (Your commit message here)
this.favoriteFoods,
this.isDataShared = false,
});
/// Check if user is married
bool get isMarried => relationshipStatus == RelationshipStatus.married;
/// Check if user is trying to conceive
bool get isTTC => fertilityGoal == FertilityGoal.tryingToConceive;
/// Check if user is practicing NFP
bool get isNFP => fertilityGoal == FertilityGoal.tryingToAvoid;
/// Check if user is husband
bool get isHusband => role == UserRole.husband;
/// Should show fertility content
bool get showFertilityContent =>
!isHusband && isMarried && fertilityGoal != FertilityGoal.justTracking && fertilityGoal != null;
bool get showFertilityContent =>
!isHusband &&
isMarried &&
fertilityGoal != FertilityGoal.justTracking &&
fertilityGoal != null;
/// Should show intimacy recommendations
bool get showIntimacyContent => isMarried;
/// Copy with updated fields
UserProfile copyWith({
String? id,
@@ -160,15 +161,11 @@ class UserProfile extends HiveObject {
DateTime? createdAt,
DateTime? updatedAt,
String? partnerName,
<<<<<<< HEAD
UserRole? role,
bool? isIrregularCycle,
=======
UserRole? role,
bool? isIrregularCycle,
BibleTranslation? bibleTranslation,
>>>>>>> 6742220 (Your commit message here)
List<String>? favoriteFoods,
bool? isDataShared,
}) {
return UserProfile(
id: id ?? this.id,
@@ -180,39 +177,41 @@ class UserProfile extends HiveObject {
lastPeriodStartDate: lastPeriodStartDate ?? this.lastPeriodStartDate,
notificationsEnabled: notificationsEnabled ?? this.notificationsEnabled,
devotionalTime: devotionalTime ?? this.devotionalTime,
hasCompletedOnboarding: hasCompletedOnboarding ?? this.hasCompletedOnboarding,
hasCompletedOnboarding:
hasCompletedOnboarding ?? this.hasCompletedOnboarding,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? DateTime.now(),
partnerName: partnerName ?? this.partnerName,
<<<<<<< HEAD
role: role ?? this.role,
isIrregularCycle: isIrregularCycle ?? this.isIrregularCycle,
=======
role: role ?? this.role,
isIrregularCycle: isIrregularCycle ?? this.isIrregularCycle,
bibleTranslation: bibleTranslation ?? this.bibleTranslation,
>>>>>>> 6742220 (Your commit message here)
favoriteFoods: favoriteFoods ?? this.favoriteFoods,
isDataShared: isDataShared ?? this.isDataShared,
);
}
}
<<<<<<< HEAD
=======
extension BibleTranslationExtension on BibleTranslation {
String get label {
switch (this) {
case BibleTranslation.esv: return 'ESV';
case BibleTranslation.niv: return 'NIV';
case BibleTranslation.nkjv: return 'NKJV';
case BibleTranslation.nlt: return 'NLT';
case BibleTranslation.nasb: return 'NASB';
case BibleTranslation.kjv: return 'KJV';
case BibleTranslation.esv:
return 'ESV';
case BibleTranslation.niv:
return 'NIV';
case BibleTranslation.nkjv:
return 'NKJV';
case BibleTranslation.nlt:
return 'NLT';
case BibleTranslation.nasb:
return 'NASB';
case BibleTranslation.kjv:
return 'KJV';
case BibleTranslation.msg:
return 'MSG';
}
}
}
>>>>>>> 6742220 (Your commit message here)
@HiveType(typeId: 8)
enum UserRole {
@HiveField(0)