feat: Add auto-sync, fix partner linking UI, update sharing settings

- Add 10-second periodic auto-sync to CycleEntriesNotifier
- Fix husband_devotional_screen: use partnerId for isConnected check, navigate to SharingSettingsScreen instead of legacy mock dialog
- Remove obsolete _showConnectDialog method and mock data import
- Update husband_settings_screen: show 'Partner Settings' with linked partner name when connected
- Add SharingSettingsScreen: Pad Supplies toggle (disabled when pad tracking off), Intimacy always enabled
- Add CORS OPTIONS handler to backend server
- Add _ensureServerRegistration for reliable partner linking
- Add copy button to Invite Partner dialog
- Dynamic base URL for web (uses window.location.hostname)
This commit is contained in:
2026-01-09 17:20:49 -06:00
parent d28898cb81
commit 1c2c56e9e2
21 changed files with 1690 additions and 493 deletions

View File

@@ -0,0 +1,53 @@
import 'package:hive/hive.dart';
import 'package:uuid/uuid.dart';
part 'prayer_request.g.dart';
@HiveType(typeId: 15)
class PrayerRequest extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String request;
@HiveField(2)
final bool isAnswered;
@HiveField(3)
final DateTime createdAt;
@HiveField(4)
final DateTime updatedAt;
PrayerRequest({
required this.id,
required this.request,
this.isAnswered = false,
required this.createdAt,
required this.updatedAt,
});
PrayerRequest copyWith({
String? request,
bool? isAnswered,
DateTime? updatedAt,
}) {
return PrayerRequest(
id: id,
request: request ?? this.request,
isAnswered: isAnswered ?? this.isAnswered,
createdAt: createdAt,
updatedAt: updatedAt ?? DateTime.now(),
);
}
factory PrayerRequest.create({required String request}) {
return PrayerRequest(
id: const Uuid().v4(),
request: request,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
}
}

View File

@@ -0,0 +1,53 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'prayer_request.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class PrayerRequestAdapter extends TypeAdapter<PrayerRequest> {
@override
final int typeId = 15;
@override
PrayerRequest read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return PrayerRequest(
id: fields[0] as String,
request: fields[1] as String,
isAnswered: fields[2] as bool,
createdAt: fields[3] as DateTime,
updatedAt: fields[4] as DateTime,
);
}
@override
void write(BinaryWriter writer, PrayerRequest obj) {
writer
..writeByte(5)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.request)
..writeByte(2)
..write(obj.isAnswered)
..writeByte(3)
..write(obj.createdAt)
..writeByte(4)
..write(obj.updatedAt);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is PrayerRequestAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -313,6 +313,9 @@ class UserProfile extends HiveObject {
@HiveField(56, defaultValue: false)
bool useExampleData;
@HiveField(57)
String? partnerId; // ID of the partner to sync with
UserProfile({
required this.id,
required this.name,
@@ -370,6 +373,7 @@ class UserProfile extends HiveObject {
this.husbandThemeMode = AppThemeMode.system,
this.husbandAccentColor = '0xFF1A3A5C',
this.useExampleData = false,
this.partnerId,
});
/// Check if user is married
@@ -452,6 +456,7 @@ class UserProfile extends HiveObject {
AppThemeMode? husbandThemeMode,
String? husbandAccentColor,
bool? useExampleData,
String? partnerId,
}) {
return UserProfile(
id: id ?? this.id,
@@ -513,6 +518,7 @@ class UserProfile extends HiveObject {
husbandThemeMode: husbandThemeMode ?? this.husbandThemeMode,
husbandAccentColor: husbandAccentColor ?? this.husbandAccentColor,
useExampleData: useExampleData ?? this.useExampleData,
partnerId: partnerId ?? this.partnerId,
);
}
}

View File

@@ -123,13 +123,14 @@ class UserProfileAdapter extends TypeAdapter<UserProfile> {
husbandAccentColor:
fields[55] == null ? '0xFF1A3A5C' : fields[55] as String,
useExampleData: fields[56] == null ? false : fields[56] as bool,
partnerId: fields[57] as String?,
);
}
@override
void write(BinaryWriter writer, UserProfile obj) {
writer
..writeByte(56)
..writeByte(57)
..writeByte(0)
..write(obj.id)
..writeByte(1)
@@ -241,7 +242,9 @@ class UserProfileAdapter extends TypeAdapter<UserProfile> {
..writeByte(55)
..write(obj.husbandAccentColor)
..writeByte(56)
..write(obj.useExampleData);
..write(obj.useExampleData)
..writeByte(57)
..write(obj.partnerId);
}
@override