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 '../../models/user_profile.dart'; import '../../providers/navigation_provider.dart'; import '../../providers/user_provider.dart'; import '../../theme/app_theme.dart'; import 'package:uuid/uuid.dart'; import '../../services/notification_service.dart'; import 'pad_tracker_screen.dart'; import '../../services/cycle_service.dart'; import '../../widgets/protected_wrapper.dart'; class LogScreen extends ConsumerStatefulWidget { final DateTime? initialDate; const LogScreen({super.key, this.initialDate}); @override ConsumerState createState() => _LogScreenState(); } class _LogScreenState extends ConsumerState { late DateTime _selectedDate; String? _existingEntryId; bool? _isPeriodDay; bool? _isSpotting; FlowIntensity? _flowIntensity; MoodLevel? _mood; int? _energyLevel; int _crampIntensity = 0; bool _hasHeadache = false; bool _hasBloating = false; bool _hasBreastTenderness = false; bool _hasFatigue = false; bool _hasAcne = false; bool _hasLowerBackPain = false; bool _hasConstipation = false; bool _hasDiarrhea = false; bool _hasInsomnia = false; int? _stressLevel; final TextEditingController _notesController = TextEditingController(); final TextEditingController _cravingsController = TextEditingController(); final TextEditingController _pantylinerCountController = TextEditingController(); // Intimacy tracking bool? _hadIntimacy; bool? _intimacyProtected; // null = no selection, true = protected, false = unprotected // Pantyliner / Supply tracking bool? _usedPantyliner; // Used for "Did you use supplies?" int _pantylinerCount = 0; int? _selectedSupplyIndex; // Index of selected supply from inventory // 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(); }); } void _loadExistingData() { final entries = ref.read(cycleEntriesProvider); try { final entry = entries.firstWhere( (e) => DateUtils.isSameDay(e.date, _selectedDate), ); setState(() { _existingEntryId = entry.id; _isPeriodDay = entry.isPeriodDay; _isSpotting = entry.flowIntensity == FlowIntensity.spotting; _flowIntensity = entry.flowIntensity; _mood = entry.mood; _energyLevel = entry.energyLevel; _crampIntensity = entry.crampIntensity ?? 0; _hasHeadache = entry.hasHeadache; _hasBloating = entry.hasBloating; _hasBreastTenderness = entry.hasBreastTenderness; _hasFatigue = entry.hasFatigue; _hasAcne = entry.hasAcne; _hasLowerBackPain = entry.hasLowerBackPain; _hasConstipation = entry.hasConstipation; _hasDiarrhea = entry.hasDiarrhea; _hasInsomnia = entry.hasInsomnia; _stressLevel = entry.stressLevel; _notesController.text = entry.notes ?? ''; _cravingsController.text = entry.cravings?.join(', ') ?? ''; _husbandNotes = entry.husbandNotes; _hadIntimacy = entry.hadIntimacy; _intimacyProtected = entry.intimacyProtected; _usedPantyliner = entry.usedPantyliner; _pantylinerCount = entry.pantylinerCount; _pantylinerCountController.text = entry.pantylinerCount.toString(); }); } catch (_) { // No existing entry for this day } } @override void dispose() { _notesController.dispose(); _cravingsController.dispose(); super.dispose(); } Future _saveEntry() async { List? cravings; if (_cravingsController.text.isNotEmpty) { cravings = _cravingsController.text .split(',') .map((e) => e.trim()) .where((e) => e.isNotEmpty) .toList(); } final entry = CycleEntry( id: _existingEntryId ?? const Uuid().v4(), date: _selectedDate, isPeriodDay: _isPeriodDay ?? false, flowIntensity: _isPeriodDay == true ? _flowIntensity : (_isSpotting == true ? FlowIntensity.spotting : null), mood: _mood, energyLevel: _energyLevel, crampIntensity: _crampIntensity > 0 ? _crampIntensity : null, hasHeadache: _hasHeadache, hasBloating: _hasBloating, hasBreastTenderness: _hasBreastTenderness, hasFatigue: _hasFatigue, hasAcne: _hasAcne, hasLowerBackPain: _hasLowerBackPain, hasConstipation: _hasConstipation, hasDiarrhea: _hasDiarrhea, hasInsomnia: _hasInsomnia, stressLevel: _stressLevel, notes: _notesController.text.isNotEmpty ? _notesController.text : null, cravings: cravings, husbandNotes: _husbandNotes, hadIntimacy: _hadIntimacy ?? false, intimacyProtected: _hadIntimacy == true ? _intimacyProtected : null, usedPantyliner: _usedPantyliner ?? false, pantylinerCount: _usedPantyliner == true ? _pantylinerCount : 0, createdAt: DateTime.now(), updatedAt: DateTime.now(), ); if (_existingEntryId != null) { await ref.read(cycleEntriesProvider.notifier).updateEntry(entry); } else { await ref.read(cycleEntriesProvider.notifier).addEntry(entry); } // Trigger Notification if Period Start if (_isPeriodDay == true && ref.read(userProfileProvider)?.notifyPeriodStart == true) { final entries = ref.read(cycleEntriesProvider); final yesterday = _selectedDate.subtract(const Duration(days: 1)); final wasPeriodYesterday = entries .any((e) => DateUtils.isSameDay(e.date, yesterday) && e.isPeriodDay); if (!wasPeriodYesterday) { NotificationService().showLocalNotification( id: 1001, title: 'Period Started', body: 'Period start recorded for ${_formatDate(_selectedDate)}.', ); } } if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Entry saved!', style: GoogleFonts.outfit()), backgroundColor: AppColors.success, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ); if (widget.initialDate != null) { Navigator.pop(context); } else { _resetForm(); } } } void _resetForm() { setState(() { _existingEntryId = null; _isPeriodDay = null; _isSpotting = null; _flowIntensity = null; _mood = null; _energyLevel = 3; _crampIntensity = 0; _hasHeadache = false; _hasBloating = false; _hasBreastTenderness = false; _hasFatigue = false; _hasAcne = false; _hasLowerBackPain = false; _hasConstipation = false; _hasDiarrhea = false; _hasInsomnia = false; _stressLevel = 1; _notesController.clear(); _cravingsController.clear(); _husbandNotes = null; _hadIntimacy = null; _intimacyProtected = null; _usedPantyliner = null; _pantylinerCount = 0; }); } bool _shouldShowPeriodCompletionPrompt() { final user = ref.read(userProfileProvider); final entries = ref.read(cycleEntriesProvider); if (user == null) return false; // Only show for the current selected date if (!DateUtils.isSameDay(_selectedDate, DateTime.now())) return false; final cycleInfo = CycleService.calculateCycleInfo(user, entries); return cycleInfo.phase == CyclePhase.menstrual && cycleInfo.dayOfCycle >= 3; } @override Widget build(BuildContext context) { final theme = Theme.of(context); final userProfile = ref.watch(userProfileProvider); final isPadTrackingEnabled = userProfile?.isPadTrackingEnabled ?? false; return ProtectedContentWrapper( title: 'Daily Log', isProtected: userProfile?.isLogProtected ?? false, userProfile: userProfile, child: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'How are you feeling?', style: GoogleFonts.outfit( fontSize: 28, fontWeight: FontWeight.w600, color: theme.colorScheme.onSurface, ), ), Text( _formatDate(_selectedDate), style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurfaceVariant, ), ), ], ), if (widget.initialDate == null) IconButton( onPressed: () => ref.read(navigationProvider.notifier).setIndex(0), icon: const Icon(Icons.close), style: IconButton.styleFrom( backgroundColor: theme .colorScheme.surfaceContainerHighest .withValues(alpha: 0.5), ), ), ], ), const SizedBox(height: 24), // Period Toggle _buildSectionCard( context, title: 'Period', child: Row( children: [ Expanded( child: Text( 'Did you start your period today?', style: GoogleFonts.outfit( fontSize: 16, color: theme.colorScheme.onSurface, ), ), ), _buildYesNoControl( context, value: _isPeriodDay, onChanged: (value) => setState(() { _isPeriodDay = value; if (value) _isSpotting = false; }), activeColor: AppColors.menstrualPhase, ), ], ), ), // Are you spotting? (only if NOT period day) if (_isPeriodDay != true) ...[ const SizedBox(height: 16), _buildSectionCard( context, title: 'Spotting', child: Row( children: [ Expanded( child: Text( 'Are you spotting?', style: GoogleFonts.outfit( fontSize: 16, color: theme.colorScheme.onSurface, ), ), ), _buildYesNoControl( context, value: _isSpotting, onChanged: (value) => setState(() => _isSpotting = value), activeColor: AppColors.menstrualPhase, ), ], ), ), ], // Still on Period? (If predicted but toggle is NO) if (_isPeriodDay == false && _shouldShowPeriodCompletionPrompt()) ...[ const SizedBox(height: 16), _buildSectionCard( context, title: 'Period Status', child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Predicted period end is near. Is your period still going, or did it finish?', style: GoogleFonts.outfit(fontSize: 14), ), const SizedBox(height: 12), Row( children: [ Expanded( child: OutlinedButton( onPressed: () => setState(() => _isPeriodDay = true), style: OutlinedButton.styleFrom( foregroundColor: AppColors.menstrualPhase, side: const BorderSide( color: AppColors.menstrualPhase), ), child: const Text('Still Going'), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton( onPressed: () { setState(() { _isPeriodDay = false; _isSpotting = false; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Period marked as finished.')), ); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.menstrualPhase, foregroundColor: Colors.white, ), child: const Text('Finished'), ), ), ], ), ], ), ), ], // Flow Intensity (only if period day) if (_isPeriodDay == true) ...[ const SizedBox(height: 16), _buildSectionCard( context, title: 'Flow Intensity', child: Column( children: [ Row( children: FlowIntensity.values.map((flow) { final isSelected = _flowIntensity == flow; return Expanded( child: GestureDetector( onTap: () => setState(() => _flowIntensity = flow), child: AnimatedContainer( duration: const Duration(milliseconds: 200), margin: const EdgeInsets.symmetric(horizontal: 4), padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: isSelected ? AppColors.menstrualPhase .withValues(alpha: 0.2) : theme .colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( flow.toString().split('.').last, style: theme.textTheme.labelLarge!.copyWith( color: isSelected ? AppColors.menstrualPhase : theme.colorScheme.onSurface, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), ), ), ), ), ); }).toList(), ), ], ), ), ], // Supply / Material Tracking if (isPadTrackingEnabled) ...[ const SizedBox(height: 16), _buildSectionCard( context, title: 'Supplies', child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: double.infinity, child: OutlinedButton.icon( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => PadTrackerScreen( isSpotting: _isSpotting ?? false, initialFlow: _flowIntensity, ), ), ); }, icon: const Icon(Icons.timer_outlined), label: const Text('Pad Tracker & Reminders'), style: OutlinedButton.styleFrom( foregroundColor: AppColors.menstrualPhase, side: const BorderSide( color: AppColors.menstrualPhase), ), ), ), const SizedBox(height: 16), Row( children: [ Expanded( child: Text( _getSupplyQuestionLabel(userProfile), style: GoogleFonts.outfit( fontSize: 16, color: theme.colorScheme.onSurface, ), ), ), _buildYesNoControl( context, value: _usedPantyliner, onChanged: (value) => setState(() { _usedPantyliner = value; if (!value) { _pantylinerCount = 0; _selectedSupplyIndex = null; } }), activeColor: AppColors.menstrualPhase, ), ], ), if (_usedPantyliner == true) ...[ const SizedBox(height: 12), if (userProfile?.padSupplies?.isNotEmpty == true) ...[ Text( 'Select item from inventory:', style: GoogleFonts.outfit( fontSize: 14, fontWeight: FontWeight.w500, color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: List.generate( userProfile!.padSupplies!.length, (index) { final item = userProfile.padSupplies![index]; final isSelected = _selectedSupplyIndex == index; return ChoiceChip( label: Text('${item.brand} (${item.type.label})'), selected: isSelected, onSelected: (selected) { setState(() { _selectedSupplyIndex = selected ? index : null; }); }, selectedColor: AppColors.menstrualPhase .withValues(alpha: 0.2), labelStyle: GoogleFonts.outfit( color: isSelected ? AppColors.menstrualPhase : theme.colorScheme.onSurface, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, ), ); }), ), const SizedBox(height: 12), ], TextFormField( controller: _pantylinerCountController, keyboardType: TextInputType.number, decoration: InputDecoration( labelText: 'Quantity Used', hintText: '1', border: OutlineInputBorder( borderRadius: BorderRadius.circular(12)), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ), onChanged: (value) { setState(() { _pantylinerCount = int.tryParse(value) ?? 0; }); }, ), ], ], ), ), ], const SizedBox(height: 16), // Mood _buildSectionCard( context, title: 'Mood', child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: MoodLevel.values.map((mood) { final isSelected = _mood == mood; return GestureDetector( onTap: () => setState(() => _mood = mood), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: isSelected ? AppColors.softGold.withValues(alpha: 0.2) : Colors.transparent, borderRadius: BorderRadius.circular(12), border: isSelected ? Border.all(color: AppColors.softGold) : Border.all(color: Colors.transparent), ), child: Column( children: [ Text( mood.emoji, style: TextStyle( fontSize: isSelected ? 32 : 28, ), ), const SizedBox(height: 4), Text( mood.label, style: GoogleFonts.outfit( fontSize: 10, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? AppColors.softGold : theme.colorScheme.onSurfaceVariant, ), ), ], ), ), ); }).toList(), ), ), const SizedBox(height: 16), // Levels _buildSectionCard( context, title: 'Daily Levels', child: Column( children: [ Row( children: [ SizedBox( width: 80, child: Text( 'Energy', style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), Expanded( child: Slider( value: (_energyLevel ?? 3).toDouble(), min: 1, max: 5, divisions: 4, activeColor: AppColors.sageGreen, onChanged: (value) { setState(() => _energyLevel = value.round()); }, ), ), SizedBox( width: 50, child: Text( _getEnergyLabel(_energyLevel), textAlign: TextAlign.end, style: GoogleFonts.outfit( fontSize: 11, color: theme.colorScheme.onSurfaceVariant, ), ), ), ], ), const SizedBox(height: 12), Row( children: [ SizedBox( width: 80, child: Text( 'Stress', style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), Expanded( child: Slider( value: (_stressLevel ?? 1).toDouble(), min: 1, max: 5, divisions: 4, activeColor: AppColors.ovulationPhase, onChanged: (value) { setState(() => _stressLevel = value.round()); }, ), ), SizedBox( width: 50, child: Text( '${_stressLevel ?? 1}/5', textAlign: TextAlign.end, style: GoogleFonts.outfit( fontSize: 12, color: theme.colorScheme.onSurfaceVariant, ), ), ), ], ), ], ), ), const SizedBox(height: 16), // Symptoms _buildSectionCard( context, title: 'Symptoms', child: Column( children: [ Row( children: [ SizedBox( width: 80, child: Text( 'Cramps', style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), Expanded( child: Slider( value: _crampIntensity.toDouble(), min: 0, max: 5, divisions: 5, activeColor: AppColors.rose, onChanged: (value) { setState(() => _crampIntensity = value.round()); }, ), ), SizedBox( width: 50, child: Text( _crampIntensity == 0 ? 'None' : '$_crampIntensity/5', textAlign: TextAlign.end, style: GoogleFonts.outfit( fontSize: 11, color: theme.colorScheme.onSurfaceVariant, ), ), ), ], ), const SizedBox(height: 12), Wrap( spacing: 8, runSpacing: 8, children: [ _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)), ], ), ], ), ), const SizedBox(height: 16), // Cravings _buildSectionCard( context, title: 'Cravings', child: TextField( controller: _cravingsController, decoration: InputDecoration( hintText: 'e.g., Chocolate, salty chips (comma separated)', filled: true, fillColor: theme.colorScheme.surfaceContainerHighest .withValues(alpha: 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 _buildSectionCard( context, title: 'Intimacy', child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SwitchListTile( title: Text('Had Intimacy Today', style: GoogleFonts.outfit(fontSize: 14)), value: _hadIntimacy ?? false, onChanged: (val) => setState(() { _hadIntimacy = val; if (!val) { _intimacyProtected = null; } }), activeThumbColor: AppColors.sageGreen, contentPadding: EdgeInsets.zero, ), if (_hadIntimacy == true) ...[ 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: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _intimacyProtected == true ? AppColors.sageGreen .withValues(alpha: 0.2) : Colors.grey.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), border: Border.all( color: _intimacyProtected == true ? AppColors.sageGreen : Colors.grey.withValues(alpha: 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: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _intimacyProtected == false ? AppColors.rose.withValues(alpha: 0.15) : Colors.grey.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), border: Border.all( color: _intimacyProtected == false ? AppColors.rose : Colors.grey.withValues(alpha: 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: theme.colorScheme.surfaceContainerHighest .withValues(alpha: 0.1), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), ), style: GoogleFonts.outfit( fontSize: 14, color: theme.colorScheme.onSurface, ), ), ), const SizedBox(height: 24), // Save Button SizedBox( width: double.infinity, height: 54, child: ElevatedButton( onPressed: _saveEntry, child: const Text('Save Entry'), ), ), const SizedBox(height: 40), ], ), ), ), ); } Widget _buildSectionCard(BuildContext context, {required String title, required Widget child}) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; return Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: theme.cardTheme.color, borderRadius: BorderRadius.circular(16), border: Border.all( color: theme.colorScheme.outline.withValues(alpha: 0.05)), boxShadow: isDark ? null : [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: GoogleFonts.outfit( fontSize: 16, fontWeight: FontWeight.w600, color: theme.colorScheme.onSurface, ), ), const SizedBox(height: 12), if (title == 'Supplies') Center(child: child) else child, ], ), ); } Widget _buildYesNoControl(BuildContext context, {required bool? value, required ValueChanged onChanged, required Color activeColor}) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; return Row( mainAxisSize: MainAxisSize.min, children: [ GestureDetector( onTap: () => onChanged(false), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: value == false ? theme.colorScheme.error .withValues(alpha: isDark ? 0.3 : 0.2) : theme.colorScheme.surfaceContainerHighest .withValues(alpha: 0.3), borderRadius: const BorderRadius.horizontal(left: Radius.circular(8)), border: value == false ? Border.all(color: theme.colorScheme.error) : Border.all(color: Colors.transparent), ), child: Text( 'No', style: GoogleFonts.outfit( color: value == false ? theme.colorScheme.error : theme.colorScheme.onSurfaceVariant, fontWeight: value == false ? FontWeight.w600 : FontWeight.w400, ), ), ), ), GestureDetector( onTap: () => onChanged(true), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: value == true ? activeColor.withValues(alpha: isDark ? 0.3 : 0.2) : theme.colorScheme.surfaceContainerHighest .withValues(alpha: 0.3), borderRadius: const BorderRadius.horizontal(right: Radius.circular(8)), border: value == true ? Border.all(color: activeColor) : Border.all(color: Colors.transparent), ), child: Text( 'Yes', style: GoogleFonts.outfit( color: value == true ? activeColor : theme.colorScheme.onSurfaceVariant, fontWeight: value == true ? FontWeight.w600 : FontWeight.w400, ), ), ), ), ], ); } Widget _buildSymptomChip(BuildContext context, String label, bool isSelected, ValueChanged onChanged) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; return Material( color: Colors.transparent, child: InkWell( onTap: () => onChanged(!isSelected), borderRadius: BorderRadius.circular(20), child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), decoration: BoxDecoration( color: isSelected ? theme.colorScheme.tertiary .withValues(alpha: isDark ? 0.3 : 0.2) : theme.colorScheme.surfaceContainerHighest .withValues(alpha: 0.3), borderRadius: BorderRadius.circular(20), 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, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, ), ), ), ), ); } String _formatDate(DateTime date) { 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' ]; return '${days[date.weekday - 1]}, ${_getMonth(date.month)} ${date.day}'; } String _getMonth(int month) { const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; return months[month - 1]; } String _getEnergyLabel(int? level) { if (level == null) return 'Not logged'; switch (level) { case 1: return 'Very Low'; case 2: return 'Low'; case 3: return 'Normal'; case 4: return 'Good'; case 5: return 'Excellent'; default: return 'Normal'; } } String _getSupplyQuestionLabel(UserProfile? user) { if (user == null || user.padSupplies == null || user.padSupplies!.isEmpty) { return 'Did you use any supplies today?'; } final hasLiners = user.padSupplies!.any((s) => s.type == PadType.pantyLiner); final hasPads = user.padSupplies!.any((s) => s.type != PadType.pantyLiner); if (hasPads && hasLiners) { return 'Did you use any supplies (pads, liners) today?'; } if (hasLiners) return 'Did you use pantyliners today?'; return 'Did you use any supplies (pads) today?'; } }