import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:uuid/uuid.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../models/cycle_entry.dart'; import '../models/user_profile.dart'; import '../providers/user_provider.dart'; import '../providers/navigation_provider.dart'; import '../screens/log/pad_tracker_screen.dart'; import '../services/notification_service.dart'; import '../theme/app_theme.dart'; class QuickLogDialog extends ConsumerStatefulWidget { final String logType; const QuickLogDialog({super.key, required this.logType}); @override ConsumerState createState() => _QuickLogDialogState(); } class _QuickLogDialogState extends ConsumerState { // State variables for the dialog FlowIntensity? _flowIntensity; MoodLevel? _mood; int? _energyLevel; PadType? _selectedPadType; int _padAbsorbency = 3; // Symptoms & Cravings final Map _symptoms = { 'Headache': false, 'Bloating': false, 'Breast Tenderness': false, 'Fatigue': false, 'Acne': false, 'Back Pain': false, 'Constipation': false, 'Diarrhea': false, 'Insomnia': false, 'Cramps': false, }; final TextEditingController _cravingController = TextEditingController(); final List _cravings = []; List _recentCravings = []; @override void initState() { super.initState(); if (widget.logType == 'cravings') { _loadRecentCravings(); } } @override void dispose() { _cravingController.dispose(); super.dispose(); } Future _loadRecentCravings() async { final prefs = await SharedPreferences.getInstance(); setState(() { _recentCravings = prefs.getStringList('recent_cravings') ?? []; }); } @override Widget build(BuildContext context) { return AlertDialog( title: Text('Quick Log: ${widget.logType.capitalize()}'), content: _buildLogContent(), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), ElevatedButton( onPressed: _saveLog, child: const Text('Save'), ), TextButton( onPressed: () { Navigator.of(context).pop(); ref.read(navigationProvider.notifier).setIndex(2); }, child: const Text('Full Log'), ) ], ); } Widget _buildLogContent() { switch (widget.logType) { case 'period': return _buildPeriodLog(); case 'mood': return _buildMoodLog(); case 'energy': return _buildEnergyLog(); case 'pads': return _buildPadsLog(); case 'symptoms': return _buildSymptomsLog(); case 'cravings': return _buildCravingsLog(); case 'prayer': return _buildPrayerLog(); default: return const Text('Invalid log type.'); } } Widget _buildSymptomsLog() { return SizedBox( width: double.maxFinite, child: ListView( shrinkWrap: true, children: [ const Text('Select symptoms you are experiencing:'), const SizedBox(height: 16), Wrap( spacing: 8, runSpacing: 8, children: _symptoms.keys.map((symptom) { final isSelected = _symptoms[symptom]!; return ChoiceChip( label: Text(symptom), selected: isSelected, onSelected: (selected) { setState(() { _symptoms[symptom] = selected; }); }, ); }).toList(), ), ], ), ); } Widget _buildCravingsLog() { return SizedBox( width: double.maxFinite, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ TextField( controller: _cravingController, decoration: const InputDecoration( labelText: 'Add a craving', hintText: 'e.g. Chocolate', border: OutlineInputBorder(), ), onSubmitted: (value) { if (value.isNotEmpty) { setState(() { _cravings.add(value.trim()); _cravingController.clear(); }); } }, ), const SizedBox(height: 8), Wrap( spacing: 8, children: _cravings .map((c) => Chip( label: Text(c), onDeleted: () { setState(() => _cravings.remove(c)); }, )) .toList(), ), const SizedBox(height: 16), if (_recentCravings.isNotEmpty) ...[ Text('Recent Cravings:', style: GoogleFonts.outfit( fontSize: 12, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Wrap( spacing: 8, children: _recentCravings .take(5) .map((c) => ActionChip( label: Text(c), onPressed: () { if (!_cravings.contains(c)) { setState(() => _cravings.add(c)); } }, )) .toList(), ), ] ], ), ); } Widget _buildPeriodLog() { return Column( mainAxisSize: MainAxisSize.min, children: [ const Text('Select your flow intensity:'), const SizedBox(height: 16), Wrap( spacing: 8, children: FlowIntensity.values.map((flow) { return ChoiceChip( label: Text(flow.label), selected: _flowIntensity == flow, onSelected: (selected) { if (selected) { setState(() { _flowIntensity = flow; }); } }, ); }).toList(), ), ], ); } Widget _buildMoodLog() { return Column( mainAxisSize: MainAxisSize.min, children: [ const Text('Select your mood:'), const SizedBox(height: 16), Wrap( spacing: 8, children: MoodLevel.values.map((mood) { return ChoiceChip( label: Text(mood.label), selected: _mood == mood, onSelected: (selected) { if (selected) { setState(() { _mood = mood; }); } }, ); }).toList(), ), ], ); } Widget _buildEnergyLog() { return Column( mainAxisSize: MainAxisSize.min, children: [ const Text('Select your energy level:'), const SizedBox(height: 16), Slider( value: (_energyLevel ?? 3).toDouble(), min: 1, max: 5, divisions: 4, label: (_energyLevel ?? 3).toString(), onChanged: (value) { setState(() { _energyLevel = value.round(); }); }, ), ], ); } Widget _buildPadsLog() { final theme = Theme.of(context); // ignore: unused_local_variable final user = ref.watch(userProfileProvider); return SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Flow Intensity:', style: GoogleFonts.outfit(fontWeight: FontWeight.w600)), const SizedBox(height: 8), Wrap( spacing: 8, children: FlowIntensity.values.map((flow) { return ChoiceChip( label: Text(flow.label), selected: _flowIntensity == flow, onSelected: (selected) { if (selected) setState(() => _flowIntensity = flow); }, ); }).toList(), ), const SizedBox(height: 16), Text('Protection Type:', style: GoogleFonts.outfit(fontWeight: FontWeight.w600)), const SizedBox(height: 8), DropdownButtonFormField( initialValue: _selectedPadType, decoration: InputDecoration( border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), contentPadding: const EdgeInsets.symmetric(horizontal: 12), ), items: PadType.values.map((type) { return DropdownMenuItem( value: type, child: Text(type.label), ); }).toList(), onChanged: (value) => setState(() => _selectedPadType = value), hint: const Text('Select type'), ), const SizedBox(height: 16), Text('Absorbency (1-5):', style: GoogleFonts.outfit(fontWeight: FontWeight.w600)), Slider( value: _padAbsorbency.toDouble(), min: 1, max: 5, divisions: 4, label: _padAbsorbency.toString(), onChanged: (val) => setState(() => _padAbsorbency = val.round()), ), const SizedBox(height: 16), if (_flowIntensity != null && _selectedPadType != null) Center( child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.sageGreen.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), ), child: Text( 'Estimated duration: ${_calculateRecommendedHours()} hours', style: GoogleFonts.outfit( color: AppColors.sageGreen, fontWeight: FontWeight.bold, ), ), ), ), const SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { Navigator.of(context).pop(); ref.read(navigationProvider.notifier).setIndex(2); Navigator.of(context).push(MaterialPageRoute( builder: (context) => const PadTrackerScreen(), )); }, style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.surfaceContainerHighest, foregroundColor: theme.colorScheme.onSurface, ), child: const Text('More Options (Inventory, etc.)'), ), ), ], ), ); } int _calculateRecommendedHours() { if (_selectedPadType == null || _flowIntensity == null) return 6; final type = _selectedPadType!; if (type == PadType.menstrualCup || type == PadType.menstrualDisc || type == PadType.periodUnderwear) { return 12; } int baseHours; switch (_flowIntensity!) { case FlowIntensity.heavy: baseHours = (type == PadType.superPad || type == PadType.overnight || type == PadType.tamponSuper) ? 4 : 3; break; case FlowIntensity.medium: baseHours = 6; break; case FlowIntensity.light: baseHours = 8; break; case FlowIntensity.spotting: baseHours = 10; break; case FlowIntensity.none: baseHours = 8; break; } return baseHours; } Widget _buildPrayerLog() { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Enter your prayer request or gratitude:'), const SizedBox(height: 16), TextField( controller: _cravingController, // Reusing controller for simplicity, or create _prayerController maxLines: 4, decoration: const InputDecoration( hintText: 'I am thankful for...', border: OutlineInputBorder(), ), ), ], ); } Future _saveLog() async { // Handle text input for cravings if user didn't hit enter if (widget.logType == 'cravings' && _cravingController.text.isNotEmpty) { _cravings.add(_cravingController.text.trim()); } final cycleNotifier = ref.read(cycleEntriesProvider.notifier); final today = DateTime.now(); final entries = ref.read(cycleEntriesProvider); final entry = entries.firstWhere( (e) => DateUtils.isSameDay(e.date, today), orElse: () => CycleEntry( id: const Uuid().v4(), date: today, createdAt: today, updatedAt: today), ); CycleEntry updatedEntry = entry; switch (widget.logType) { case 'period': updatedEntry = entry.copyWith( isPeriodDay: true, flowIntensity: _flowIntensity, ); break; case 'mood': updatedEntry = entry.copyWith(mood: _mood); break; case 'energy': updatedEntry = entry.copyWith(energyLevel: _energyLevel); break; case 'symptoms': updatedEntry = entry.copyWith( hasHeadache: _symptoms['Headache'], hasBloating: _symptoms['Bloating'], hasBreastTenderness: _symptoms['Breast Tenderness'], hasFatigue: _symptoms['Fatigue'], hasAcne: _symptoms['Acne'], hasLowerBackPain: _symptoms['Back Pain'], hasConstipation: _symptoms['Constipation'], hasDiarrhea: _symptoms['Diarrhea'], hasInsomnia: _symptoms['Insomnia'], crampIntensity: _symptoms['Cramps'] == true ? 2 : 0, // Default to mild cramps if just toggled ); // Trigger notification if any symptom is selected final user = ref.read(userProfileProvider); if (_symptoms.values.any((selected) => selected == true)) { final selectedSymptom = _symptoms.entries .firstWhere((element) => element.value == true) .key; NotificationService().showSymptomNotification( senderName: user?.name ?? 'Wife', symptom: selectedSymptom, ); } break; case 'cravings': final currentCravings = entry.cravings ?? []; final newCravings = {...currentCravings, ..._cravings}.toList(); updatedEntry = entry.copyWith(cravings: newCravings); // Update History final prefs = await SharedPreferences.getInstance(); final history = prefs.getStringList('recent_cravings') ?? []; final updatedHistory = {..._cravings, ...history}.take(20).toList(); await prefs.setStringList('recent_cravings', updatedHistory); await prefs.setStringList('recent_cravings', updatedHistory); break; case 'prayer': final currentPrayer = entry.prayerRequest ?? ''; final newPrayer = _cravingController.text.trim(); // Using reused controller if (newPrayer.isNotEmpty) { updatedEntry = entry.copyWith( prayerRequest: currentPrayer.isEmpty ? newPrayer : '$currentPrayer\n$newPrayer'); // Trigger notification final user = ref.read(userProfileProvider); NotificationService().showPrayerRequestNotification( senderName: user?.name ?? 'Wife', ); } else { return; // Don't save empty prayer } break; case 'pads': final userProfile = ref.read(userProfileProvider); if (userProfile != null) { final hours = _calculateRecommendedHours(); await ref.read(userProfileProvider.notifier).updateProfile( userProfile.copyWith( lastPadChangeTime: DateTime.now(), // Auto-inventory deduction could go here, but omitted for "Quick" simplicity // unless we want to match PadTrackerScreen exactly. ), ); await NotificationService().scheduleNotification( id: 100, title: 'Time to change!', body: 'It\'s been $hours hours since you logged your protection.', scheduledDate: DateTime.now().add(Duration(hours: hours)), ); } updatedEntry = entry.copyWith( isPeriodDay: _flowIntensity != FlowIntensity.none && _flowIntensity != FlowIntensity.spotting, flowIntensity: _flowIntensity, ); break; default: // Already handled or invalid return; } if (entries.any((e) => e.id == entry.id)) { cycleNotifier.updateEntry(updatedEntry); } else { cycleNotifier.addEntry(updatedEntry); } if (mounted) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Entry saved!')), ); } } } extension StringExtension on String { String capitalize() { return "${this[0].toUpperCase()}${substring(1)}"; } }