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

@@ -2,55 +2,52 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../models/cycle_entry.dart';
import '../../providers/navigation_provider.dart';
import '../../providers/user_provider.dart';
import '../../theme/app_theme.dart';
import 'package:uuid/uuid.dart';
class LogScreen extends ConsumerStatefulWidget {
<<<<<<< HEAD
const LogScreen({super.key});
=======
final DateTime? initialDate;
const LogScreen({super.key, this.initialDate});
>>>>>>> 6742220 (Your commit message here)
@override
ConsumerState<LogScreen> createState() => _LogScreenState();
}
class _LogScreenState extends ConsumerState<LogScreen> {
<<<<<<< HEAD
=======
late DateTime _selectedDate;
String? _existingEntryId;
>>>>>>> 6742220 (Your commit message here)
bool _isPeriodDay = false;
FlowIntensity? _flowIntensity;
MoodLevel? _mood;
int _energyLevel = 3;
int? _energyLevel;
int _crampIntensity = 0;
bool _hasHeadache = false;
bool _hasBloating = false;
bool _hasBreastTenderness = false;
bool _hasFatigue = false;
bool _hasAcne = false;
<<<<<<< HEAD
final TextEditingController _notesController = TextEditingController();
@override
=======
bool _hasLowerBackPain = false;
bool _hasConstipation = false;
bool _hasDiarrhea = false;
bool _hasInsomnia = false;
int _stressLevel = 1;
int? _stressLevel;
final TextEditingController _notesController = TextEditingController();
final TextEditingController _cravingsController = TextEditingController();
// Intimacy tracking
bool _hadIntimacy = false;
bool? _intimacyProtected; // null = no selection, true = protected, false = unprotected
// Hidden field to preserve husband's notes
String? _husbandNotes;
@override
void initState() {
super.initState();
_selectedDate = widget.initialDate ?? DateTime.now();
// Defer data loading to avoid build-time ref.read
WidgetsBinding.instance.addPostFrameCallback((_) {
_loadExistingData();
@@ -79,8 +76,12 @@ class _LogScreenState extends ConsumerState<LogScreen> {
_hasConstipation = entry.hasConstipation;
_hasDiarrhea = entry.hasDiarrhea;
_hasInsomnia = entry.hasInsomnia;
_stressLevel = entry.stressLevel ?? 1;
_stressLevel = entry.stressLevel;
_notesController.text = entry.notes ?? '';
_cravingsController.text = entry.cravings?.join(', ') ?? '';
_husbandNotes = entry.husbandNotes;
_hadIntimacy = entry.hadIntimacy;
_intimacyProtected = entry.intimacyProtected;
});
} catch (_) {
// No existing entry for this day
@@ -88,21 +89,25 @@ class _LogScreenState extends ConsumerState<LogScreen> {
}
@override
>>>>>>> 6742220 (Your commit message here)
void dispose() {
_notesController.dispose();
_cravingsController.dispose();
super.dispose();
}
Future<void> _saveEntry() async {
List<String>? cravings;
if (_cravingsController.text.isNotEmpty) {
cravings = _cravingsController.text
.split(',')
.map((e) => e.trim())
.where((e) => e.isNotEmpty)
.toList();
}
final entry = CycleEntry(
<<<<<<< HEAD
id: const Uuid().v4(),
date: DateTime.now(),
=======
id: _existingEntryId ?? const Uuid().v4(),
date: _selectedDate,
>>>>>>> 6742220 (Your commit message here)
isPeriodDay: _isPeriodDay,
flowIntensity: _isPeriodDay ? _flowIntensity : null,
mood: _mood,
@@ -113,60 +118,47 @@ class _LogScreenState extends ConsumerState<LogScreen> {
hasBreastTenderness: _hasBreastTenderness,
hasFatigue: _hasFatigue,
hasAcne: _hasAcne,
<<<<<<< HEAD
=======
hasLowerBackPain: _hasLowerBackPain,
hasConstipation: _hasConstipation,
hasDiarrhea: _hasDiarrhea,
hasInsomnia: _hasInsomnia,
stressLevel: _stressLevel > 1 ? _stressLevel : null,
>>>>>>> 6742220 (Your commit message here)
stressLevel: _stressLevel,
notes: _notesController.text.isNotEmpty ? _notesController.text : null,
cravings: cravings,
husbandNotes: _husbandNotes,
hadIntimacy: _hadIntimacy,
intimacyProtected: _hadIntimacy ? _intimacyProtected : null,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
<<<<<<< HEAD
await ref.read(cycleEntriesProvider.notifier).addEntry(entry);
=======
if (_existingEntryId != null) {
await ref.read(cycleEntriesProvider.notifier).updateEntry(entry);
} else {
await ref.read(cycleEntriesProvider.notifier).addEntry(entry);
}
>>>>>>> 6742220 (Your commit message here)
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Entry saved!', style: GoogleFonts.outfit()),
<<<<<<< HEAD
backgroundColor: AppColors.sageGreen,
=======
backgroundColor: AppColors.success,
>>>>>>> 6742220 (Your commit message here)
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
);
<<<<<<< HEAD
_resetForm();
=======
if (widget.initialDate != null) {
Navigator.pop(context);
} else {
_resetForm();
}
>>>>>>> 6742220 (Your commit message here)
}
}
void _resetForm() {
setState(() {
<<<<<<< HEAD
=======
_existingEntryId = null;
>>>>>>> 6742220 (Your commit message here)
_isPeriodDay = false;
_flowIntensity = null;
_mood = null;
@@ -177,26 +169,24 @@ class _LogScreenState extends ConsumerState<LogScreen> {
_hasBreastTenderness = false;
_hasFatigue = false;
_hasAcne = false;
<<<<<<< HEAD
=======
_hasLowerBackPain = false;
_hasConstipation = false;
_hasDiarrhea = false;
_hasInsomnia = false;
_stressLevel = 1;
>>>>>>> 6742220 (Your commit message here)
_notesController.clear();
_cravingsController.clear();
_husbandNotes = null;
_hadIntimacy = false;
_intimacyProtected = null;
});
}
@override
Widget build(BuildContext context) {
<<<<<<< HEAD
=======
final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
>>>>>>> 6742220 (Your commit message here)
return SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
@@ -204,22 +194,6 @@ class _LogScreenState extends ConsumerState<LogScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
<<<<<<< HEAD
Text(
'How are you feeling?',
style: GoogleFonts.outfit(
fontSize: 28,
fontWeight: FontWeight.w600,
color: AppColors.charcoal,
),
),
Text(
_formatDate(DateTime.now()),
style: GoogleFonts.outfit(
fontSize: 14,
color: AppColors.warmGray,
),
=======
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -245,23 +219,21 @@ class _LogScreenState extends ConsumerState<LogScreen> {
),
if (widget.initialDate == null)
IconButton(
onPressed: () => ref.read(navigationProvider.notifier).setIndex(0),
onPressed: () =>
ref.read(navigationProvider.notifier).setIndex(0),
icon: const Icon(Icons.close),
style: IconButton.styleFrom(
backgroundColor: theme.colorScheme.surfaceVariant.withOpacity(0.5),
backgroundColor:
theme.colorScheme.surfaceVariant.withOpacity(0.5),
),
),
],
>>>>>>> 6742220 (Your commit message here)
),
const SizedBox(height: 24),
// Period Toggle
_buildSectionCard(
<<<<<<< HEAD
=======
context,
>>>>>>> 6742220 (Your commit message here)
title: 'Period',
child: Row(
children: [
@@ -270,11 +242,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
'Is today a period day?',
style: GoogleFonts.outfit(
fontSize: 16,
<<<<<<< HEAD
color: AppColors.charcoal,
=======
color: theme.colorScheme.onSurface,
>>>>>>> 6742220 (Your commit message here)
),
),
),
@@ -291,10 +259,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
if (_isPeriodDay) ...[
const SizedBox(height: 16),
_buildSectionCard(
<<<<<<< HEAD
=======
context,
>>>>>>> 6742220 (Your commit message here)
title: 'Flow Intensity',
child: Row(
children: FlowIntensity.values.map((flow) {
@@ -302,31 +267,20 @@ class _LogScreenState extends ConsumerState<LogScreen> {
return Expanded(
child: GestureDetector(
onTap: () => setState(() => _flowIntensity = flow),
<<<<<<< HEAD
child: Container(
=======
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
>>>>>>> 6742220 (Your commit message here)
margin: const EdgeInsets.symmetric(horizontal: 4),
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
color: isSelected
<<<<<<< HEAD
? AppColors.menstrualPhase.withOpacity(0.2)
: AppColors.lightGray.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
border: isSelected
? Border.all(color: AppColors.menstrualPhase)
: null,
=======
? AppColors.menstrualPhase.withOpacity(isDark ? 0.3 : 0.2)
: theme.colorScheme.surfaceVariant.withOpacity(0.3),
? AppColors.menstrualPhase
.withOpacity(isDark ? 0.3 : 0.2)
: theme.colorScheme.surfaceVariant
.withOpacity(0.3),
borderRadius: BorderRadius.circular(10),
border: isSelected
? Border.all(color: AppColors.menstrualPhase)
: Border.all(color: Colors.transparent),
>>>>>>> 6742220 (Your commit message here)
),
child: Column(
children: [
@@ -334,11 +288,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
Icons.water_drop,
color: isSelected
? AppColors.menstrualPhase
<<<<<<< HEAD
: AppColors.warmGray,
=======
: theme.colorScheme.onSurfaceVariant,
>>>>>>> 6742220 (Your commit message here)
size: 20,
),
const SizedBox(height: 4),
@@ -346,16 +296,12 @@ class _LogScreenState extends ConsumerState<LogScreen> {
flow.label,
style: GoogleFonts.outfit(
fontSize: 11,
<<<<<<< HEAD
color: isSelected
? AppColors.menstrualPhase
: AppColors.warmGray,
=======
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
fontWeight: isSelected
? FontWeight.w600
: FontWeight.w400,
color: isSelected
? AppColors.menstrualPhase
: theme.colorScheme.onSurfaceVariant,
>>>>>>> 6742220 (Your commit message here)
),
),
],
@@ -372,10 +318,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
// Mood
_buildSectionCard(
<<<<<<< HEAD
=======
context,
>>>>>>> 6742220 (Your commit message here)
title: 'Mood',
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
@@ -383,29 +326,18 @@ class _LogScreenState extends ConsumerState<LogScreen> {
final isSelected = _mood == mood;
return GestureDetector(
onTap: () => setState(() => _mood = mood),
<<<<<<< HEAD
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isSelected
? AppColors.softGold.withOpacity(0.2)
=======
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isSelected
? AppColors.softGold.withOpacity(isDark ? 0.3 : 0.2)
>>>>>>> 6742220 (Your commit message here)
? AppColors.softGold
.withOpacity(isDark ? 0.3 : 0.2)
: Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: isSelected
? Border.all(color: AppColors.softGold)
<<<<<<< HEAD
: null,
=======
: Border.all(color: Colors.transparent),
>>>>>>> 6742220 (Your commit message here)
),
child: Column(
children: [
@@ -420,16 +352,12 @@ class _LogScreenState extends ConsumerState<LogScreen> {
mood.label,
style: GoogleFonts.outfit(
fontSize: 10,
<<<<<<< HEAD
color: isSelected
? AppColors.softGold
: AppColors.warmGray,
=======
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
fontWeight: isSelected
? FontWeight.w600
: FontWeight.w400,
color: isSelected
? AppColors.softGold
: theme.colorScheme.onSurfaceVariant,
>>>>>>> 6742220 (Your commit message here)
),
),
],
@@ -442,16 +370,6 @@ class _LogScreenState extends ConsumerState<LogScreen> {
const SizedBox(height: 16),
<<<<<<< HEAD
// Energy Level
_buildSectionCard(
title: 'Energy Level',
child: Column(
children: [
Row(
children: [
const Icon(Icons.battery_1_bar, color: AppColors.warmGray),
=======
// Energy & Stress Levels
_buildSectionCard(
context,
@@ -471,33 +389,18 @@ class _LogScreenState extends ConsumerState<LogScreen> {
),
),
),
>>>>>>> 6742220 (Your commit message here)
Expanded(
child: Slider(
value: _energyLevel.toDouble(),
value: (_energyLevel ?? 3).toDouble(),
min: 1,
max: 5,
divisions: 4,
<<<<<<< HEAD
=======
activeColor: AppColors.sageGreen,
>>>>>>> 6742220 (Your commit message here)
onChanged: (value) {
setState(() => _energyLevel = value.round());
},
),
),
<<<<<<< HEAD
const Icon(Icons.battery_full, color: AppColors.sageGreen),
],
),
Text(
_getEnergyLabel(_energyLevel),
style: GoogleFonts.outfit(
fontSize: 13,
color: AppColors.warmGray,
),
=======
SizedBox(
width: 50,
child: Text(
@@ -527,7 +430,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
),
Expanded(
child: Slider(
value: _stressLevel.toDouble(),
value: (_stressLevel ?? 1).toDouble(),
min: 1,
max: 5,
divisions: 4,
@@ -540,7 +443,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
SizedBox(
width: 50,
child: Text(
'$_stressLevel/5',
'${_stressLevel ?? 1}/5',
textAlign: TextAlign.end,
style: GoogleFonts.outfit(
fontSize: 12,
@@ -549,7 +452,6 @@ class _LogScreenState extends ConsumerState<LogScreen> {
),
),
],
>>>>>>> 6742220 (Your commit message here)
),
],
),
@@ -559,10 +461,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
// Symptoms
_buildSectionCard(
<<<<<<< HEAD
=======
context,
>>>>>>> 6742220 (Your commit message here)
title: 'Symptoms',
child: Column(
children: [
@@ -575,11 +474,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
'Cramps',
style: GoogleFonts.outfit(
fontSize: 14,
<<<<<<< HEAD
color: AppColors.charcoal,
=======
color: theme.colorScheme.onSurface,
>>>>>>> 6742220 (Your commit message here)
),
),
),
@@ -596,22 +491,15 @@ class _LogScreenState extends ConsumerState<LogScreen> {
),
),
SizedBox(
<<<<<<< HEAD
width: 40,
child: Text(
_crampIntensity == 0 ? 'None' : '$_crampIntensity/5',
style: GoogleFonts.outfit(
fontSize: 12,
color: AppColors.warmGray,
=======
width: 50,
child: Text(
_crampIntensity == 0 ? 'None' : '$_crampIntensity/5',
_crampIntensity == 0
? 'None'
: '$_crampIntensity/5',
textAlign: TextAlign.end,
style: GoogleFonts.outfit(
fontSize: 11,
color: theme.colorScheme.onSurfaceVariant,
>>>>>>> 6742220 (Your commit message here)
),
),
),
@@ -623,23 +511,29 @@ class _LogScreenState extends ConsumerState<LogScreen> {
spacing: 8,
runSpacing: 8,
children: [
<<<<<<< HEAD
_buildSymptomChip('Headache', _hasHeadache, (v) => setState(() => _hasHeadache = v)),
_buildSymptomChip('Bloating', _hasBloating, (v) => setState(() => _hasBloating = v)),
_buildSymptomChip('Breast Tenderness', _hasBreastTenderness, (v) => setState(() => _hasBreastTenderness = v)),
_buildSymptomChip('Fatigue', _hasFatigue, (v) => setState(() => _hasFatigue = v)),
_buildSymptomChip('Acne', _hasAcne, (v) => setState(() => _hasAcne = v)),
=======
_buildSymptomChip(context, 'Headache', _hasHeadache, (v) => setState(() => _hasHeadache = v)),
_buildSymptomChip(context, 'Bloating', _hasBloating, (v) => setState(() => _hasBloating = v)),
_buildSymptomChip(context, 'Breast Tenderness', _hasBreastTenderness, (v) => setState(() => _hasBreastTenderness = v)),
_buildSymptomChip(context, 'Fatigue', _hasFatigue, (v) => setState(() => _hasFatigue = v)),
_buildSymptomChip(context, 'Acne', _hasAcne, (v) => setState(() => _hasAcne = v)),
_buildSymptomChip(context, 'Back Pain', _hasLowerBackPain, (v) => setState(() => _hasLowerBackPain = v)),
_buildSymptomChip(context, 'Constipation', _hasConstipation, (v) => setState(() => _hasConstipation = v)),
_buildSymptomChip(context, 'Diarrhea', _hasDiarrhea, (v) => setState(() => _hasDiarrhea = v)),
_buildSymptomChip(context, 'Insomnia', _hasInsomnia, (v) => setState(() => _hasInsomnia = v)),
>>>>>>> 6742220 (Your commit message here)
_buildSymptomChip(context, 'Headache', _hasHeadache,
(v) => setState(() => _hasHeadache = v)),
_buildSymptomChip(context, 'Bloating', _hasBloating,
(v) => setState(() => _hasBloating = v)),
_buildSymptomChip(context, 'Breast Tenderness',
_hasBreastTenderness,
(v) => setState(() => _hasBreastTenderness = v)),
_buildSymptomChip(context, 'Fatigue', _hasFatigue,
(v) => setState(() => _hasFatigue = v)),
_buildSymptomChip(context, 'Acne', _hasAcne,
(v) => setState(() => _hasAcne = v)),
_buildSymptomChip(context, 'Back Pain',
_hasLowerBackPain,
(v) => setState(() => _hasLowerBackPain = v)),
_buildSymptomChip(
context,
'Constipation',
_hasConstipation,
(v) => setState(() => _hasConstipation = v)),
_buildSymptomChip(context, 'Diarrhea', _hasDiarrhea,
(v) => setState(() => _hasDiarrhea = v)),
_buildSymptomChip(context, 'Insomnia', _hasInsomnia,
(v) => setState(() => _hasInsomnia = v)),
],
),
],
@@ -648,31 +542,138 @@ class _LogScreenState extends ConsumerState<LogScreen> {
const SizedBox(height: 16),
// Notes
// Cravings
_buildSectionCard(
<<<<<<< HEAD
=======
context,
>>>>>>> 6742220 (Your commit message here)
title: 'Notes',
title: 'Cravings',
child: TextField(
controller: _notesController,
maxLines: 3,
controller: _cravingsController,
decoration: InputDecoration(
hintText: 'Add any notes about how you\'re feeling...',
<<<<<<< HEAD
hintStyle: GoogleFonts.outfit(
color: AppColors.lightGray,
fontSize: 14,
),
border: InputBorder.none,
),
style: GoogleFonts.outfit(
fontSize: 14,
color: AppColors.charcoal,
=======
hintText: 'e.g., Chocolate, salty chips (comma separated)',
filled: true,
fillColor: isDark ? theme.colorScheme.surface : theme.colorScheme.surfaceVariant.withOpacity(0.1),
fillColor: isDark
? theme.colorScheme.surface
: theme.colorScheme.surfaceVariant.withOpacity(0.1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
),
style: GoogleFonts.outfit(
fontSize: 14,
color: theme.colorScheme.onSurface,
),
),
),
const SizedBox(height: 16),
// Intimacy Tracking (for married users)
_buildSectionCard(
context,
title: 'Intimacy',
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SwitchListTile(
title: Text('Had Intimacy Today', style: GoogleFonts.outfit(fontSize: 14)),
value: _hadIntimacy,
onChanged: (val) => setState(() {
_hadIntimacy = val;
if (!val) _intimacyProtected = null;
}),
activeColor: AppColors.sageGreen,
contentPadding: EdgeInsets.zero,
),
if (_hadIntimacy) ...[
const SizedBox(height: 8),
Text('Protection:', style: GoogleFonts.outfit(fontSize: 13, color: AppColors.warmGray)),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: GestureDetector(
onTap: () => setState(() => _intimacyProtected = true),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
color: _intimacyProtected == true
? AppColors.sageGreen.withOpacity(0.2)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: _intimacyProtected == true
? AppColors.sageGreen
: Colors.grey.withOpacity(0.3),
),
),
child: Center(
child: Text(
'Protected',
style: GoogleFonts.outfit(
fontWeight: FontWeight.w500,
color: _intimacyProtected == true
? AppColors.sageGreen
: AppColors.warmGray,
),
),
),
),
),
),
const SizedBox(width: 12),
Expanded(
child: GestureDetector(
onTap: () => setState(() => _intimacyProtected = false),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
color: _intimacyProtected == false
? AppColors.rose.withOpacity(0.15)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: _intimacyProtected == false
? AppColors.rose
: Colors.grey.withOpacity(0.3),
),
),
child: Center(
child: Text(
'Unprotected',
style: GoogleFonts.outfit(
fontWeight: FontWeight.w500,
color: _intimacyProtected == false
? AppColors.rose
: AppColors.warmGray,
),
),
),
),
),
),
],
),
],
],
),
),
const SizedBox(height: 16),
// Notes
_buildSectionCard(
context,
title: 'Notes',
child: TextField(
controller: _notesController,
maxLines: 3,
decoration: InputDecoration(
hintText: 'Add any notes about how you\'re feeling...',
filled: true,
fillColor: isDark
? theme.colorScheme.surface
: theme.colorScheme.surfaceVariant.withOpacity(0.1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
@@ -681,7 +682,6 @@ class _LogScreenState extends ConsumerState<LogScreen> {
style: GoogleFonts.outfit(
fontSize: 14,
color: theme.colorScheme.onSurface,
>>>>>>> 6742220 (Your commit message here)
),
),
),
@@ -691,10 +691,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
// Save Button
SizedBox(
width: double.infinity,
<<<<<<< HEAD
=======
height: 54,
>>>>>>> 6742220 (Your commit message here)
child: ElevatedButton(
onPressed: _saveEntry,
child: const Text('Save Entry'),
@@ -707,36 +704,27 @@ class _LogScreenState extends ConsumerState<LogScreen> {
);
}
<<<<<<< HEAD
Widget _buildSectionCard({required String title, required Widget child}) {
=======
Widget _buildSectionCard(BuildContext context, {required String title, required Widget child}) {
Widget _buildSectionCard(BuildContext context,
{required String title, required Widget child}) {
final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
>>>>>>> 6742220 (Your commit message here)
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
<<<<<<< HEAD
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: AppColors.charcoal.withOpacity(0.05),
=======
color: theme.cardTheme.color,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: theme.colorScheme.outline.withOpacity(0.05)),
boxShadow: isDark ? null : [
BoxShadow(
color: Colors.black.withOpacity(0.05),
>>>>>>> 6742220 (Your commit message here)
blurRadius: 10,
offset: const Offset(0, 4),
),
],
boxShadow: isDark
? null
: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -746,11 +734,7 @@ class _LogScreenState extends ConsumerState<LogScreen> {
style: GoogleFonts.outfit(
fontSize: 16,
fontWeight: FontWeight.w600,
<<<<<<< HEAD
color: AppColors.charcoal,
=======
color: theme.colorScheme.onSurface,
>>>>>>> 6742220 (Your commit message here)
),
),
const SizedBox(height: 12),
@@ -760,25 +744,8 @@ class _LogScreenState extends ConsumerState<LogScreen> {
);
}
<<<<<<< HEAD
Widget _buildSymptomChip(String label, bool isSelected, ValueChanged<bool> onChanged) {
return GestureDetector(
onTap: () => onChanged(!isSelected),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
color: isSelected ? AppColors.lavender.withOpacity(0.3) : AppColors.lightGray.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
border: isSelected ? Border.all(color: AppColors.lavender) : null,
),
child: Text(
label,
style: GoogleFonts.outfit(
fontSize: 13,
color: isSelected ? AppColors.ovulationPhase : AppColors.warmGray,
fontWeight: isSelected ? FontWeight.w500 : FontWeight.w400,
=======
Widget _buildSymptomChip(BuildContext context, String label, bool isSelected, ValueChanged<bool> onChanged) {
Widget _buildSymptomChip(BuildContext context, String label, bool isSelected,
ValueChanged<bool> onChanged) {
final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
@@ -791,22 +758,23 @@ class _LogScreenState extends ConsumerState<LogScreen> {
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
color: isSelected
? theme.colorScheme.tertiary.withOpacity(isDark ? 0.3 : 0.2)
color: isSelected
? theme.colorScheme.tertiary.withOpacity(isDark ? 0.3 : 0.2)
: theme.colorScheme.surfaceVariant.withOpacity(0.3),
borderRadius: BorderRadius.circular(20),
border: isSelected
? Border.all(color: theme.colorScheme.tertiary)
border: isSelected
? Border.all(color: theme.colorScheme.tertiary)
: Border.all(color: Colors.transparent),
),
child: Text(
label,
style: GoogleFonts.outfit(
fontSize: 13,
color: isSelected ? theme.colorScheme.onSurface : theme.colorScheme.onSurfaceVariant,
color: isSelected
? theme.colorScheme.onSurface
: theme.colorScheme.onSurfaceVariant,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
),
>>>>>>> 6742220 (Your commit message here)
),
),
),
@@ -814,31 +782,42 @@ class _LogScreenState extends ConsumerState<LogScreen> {
}
String _formatDate(DateTime date) {
<<<<<<< HEAD
=======
final now = DateTime.now();
if (DateUtils.isSameDay(date, now)) {
return 'Today, ${_getMonth(date.month)} ${date.day}';
}
const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
const days = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday'
];
return '${days[date.weekday - 1]}, ${_getMonth(date.month)} ${date.day}';
}
String _getMonth(int month) {
>>>>>>> 6742220 (Your commit message here)
const months = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
<<<<<<< HEAD
const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
return '${days[date.weekday - 1]}, ${months[date.month - 1]} ${date.day}';
=======
return months[month - 1];
>>>>>>> 6742220 (Your commit message here)
}
String _getEnergyLabel(int level) {
String _getEnergyLabel(int? level) {
if (level == null) return 'Not logged';
switch (level) {
case 1:
return 'Very Low';