import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/providers/activity_provider.dart'; import '../../core/providers/mood_provider.dart'; import '../../shared/widgets/activity_grid.dart'; import '../../shared/widgets/mood_selector.dart'; import 'widgets/activities_chip.dart'; import 'widgets/answer_chip.dart'; import 'widgets/step_scale.dart'; // ── Emoji / label data ──────────────────────────────────────────────────────── const _moodEmojis = ['😞', '😔', '😐', '🙂', '😄']; const _moodLabels = ['Awful', 'Bad', 'Okay', 'Good', 'Great']; const _energyEmojis = ['💤', '🥱', '⚡', '🔥', '🚀']; const _energyLabels = ['Very low', 'Low', 'OK', 'High', 'Very high']; const _positivityEmojis = ['🌧', '☁️', '🌤', '☀️', '🌈']; const _positivityLabels = ['Very neg', 'Negative', 'Neutral', 'Positive', 'Very pos']; const _selfWorthEmojis = ['💔', '😕', '😐', '💪', '⭐']; const _selfWorthLabels = ['Very low', 'Low', 'Moderate', 'High', 'Very high']; const _scaleColors = [ Color(0xFFE57373), Color(0xFFFFB74D), Color(0xFFFFD54F), Color(0xFF81C784), Color(0xFF4DB6AC), ]; // ── Step enum ───────────────────────────────────────────────────────────────── enum _Step { mood, sleep, energy, positivity, selfWorth, activities } // ── Screen ──────────────────────────────────────────────────────────────────── class LogMoodScreen extends ConsumerStatefulWidget { const LogMoodScreen({super.key}); @override ConsumerState createState() => _LogMoodScreenState(); } class _LogMoodScreenState extends ConsumerState { // answers int? _mood; int _sleepHours = 7; int _sleepMinutesVal = 30; // 0/5/10…55 int? _energy; int? _positivity; int? _selfWorth; // navigation state int _stepIndex = 0; bool _inReview = false; bool _editingFromReview = false; // sleep scroll controllers late final FixedExtentScrollController _hoursCtrl; late final FixedExtentScrollController _minsCtrl; // computed step list (set once isFirstToday is known) List<_Step>? _steps; @override void initState() { super.initState(); _hoursCtrl = FixedExtentScrollController(initialItem: _sleepHours); _minsCtrl = FixedExtentScrollController(initialItem: _sleepMinutesVal ~/ 5); } @override void dispose() { _hoursCtrl.dispose(); _minsCtrl.dispose(); super.dispose(); } // ── Helpers ───────────────────────────────────────────────────────────────── List<_Step> _buildStepList(bool isFirstToday) { return [ _Step.mood, if (isFirstToday) _Step.sleep, _Step.energy, _Step.positivity, _Step.selfWorth, _Step.activities, ]; } _Step get _currentStep => _steps![_stepIndex]; String _sleepLabel() { final mm = _sleepMinutesVal.toString().padLeft(2, '0'); return '$_sleepHours:$mm'; } int _sleepTotalMinutes() => _sleepHours * 60 + _sleepMinutesVal; Color _colorFor(int level) => _scaleColors[level - 1]; // ── Navigation ─────────────────────────────────────────────────────────────── void _advance() { if (_editingFromReview) { setState(() { _editingFromReview = false; _inReview = true; _stepIndex = _steps!.length; // back to review index }); return; } final next = _stepIndex + 1; if (next >= _steps!.length) { setState(() { _inReview = true; _stepIndex = _steps!.length; }); } else { setState(() => _stepIndex = next); } } void _editStepFromReview(int idx) { setState(() { _editingFromReview = true; _stepIndex = idx; _inReview = false; }); } // ── Save ───────────────────────────────────────────────────────────────────── Future _save() async { final selectedActivities = ref.read(selectedActivitiesProvider); await ref.read(moodEntryNotifierProvider.notifier).addEntry( moodLevel: _mood ?? 3, activityIds: selectedActivities.toList(), sleepMinutes: _steps!.contains(_Step.sleep) ? _sleepTotalMinutes() : null, energyLevel: _energy, positivityLevel: _positivity, selfWorthLevel: _selfWorth, ); if (!mounted) return; ref.read(selectedActivitiesProvider.notifier).clear(); ref.invalidate(isFirstEntryTodayProvider); setState(() { _mood = null; _sleepHours = 7; _sleepMinutesVal = 30; _energy = null; _positivity = null; _selfWorth = null; _stepIndex = 0; _inReview = false; _editingFromReview = false; _steps = null; }); // reset scroll controllers _hoursCtrl.jumpToItem(7); _minsCtrl.jumpToItem(6); // 30 / 5 = 6 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Mood logged!')), ); } // ── Answer chip row ────────────────────────────────────────────────────────── Widget _buildChipRow() { final steps = _steps; if (steps == null) return const SizedBox.shrink(); final chips = []; for (int i = 0; i < steps.length; i++) { final step = steps[i]; final answered = _stepIndex > i || _inReview; final isLiveSleep = step == _Step.sleep && _stepIndex == i && !_inReview; if (!answered && !isLiveSleep) continue; Widget chip; final tappable = _inReview ? () => _editStepFromReview(i) : null; switch (step) { case _Step.mood: if (_mood == null) continue; chip = AnswerChip( label: _moodEmojis[_mood! - 1], backgroundColor: _colorFor(_mood!), onTap: tappable, ); case _Step.sleep: chip = AnswerChip( label: _sleepLabel(), backgroundColor: const Color(0xFF42A5F5), onTap: tappable, ); case _Step.energy: if (_energy == null) continue; chip = AnswerChip( label: _energyEmojis[_energy! - 1], backgroundColor: _colorFor(_energy!), onTap: tappable, ); case _Step.positivity: if (_positivity == null) continue; chip = AnswerChip( label: _positivityEmojis[_positivity! - 1], backgroundColor: _colorFor(_positivity!), onTap: tappable, ); case _Step.selfWorth: if (_selfWorth == null) continue; chip = AnswerChip( label: _selfWorthEmojis[_selfWorth! - 1], backgroundColor: _colorFor(_selfWorth!), onTap: tappable, ); case _Step.activities: chip = ActivitiesChip( backgroundColor: const Color(0xFF78909C), onTap: tappable, ); } chips.add( Padding( padding: const EdgeInsets.only(right: 8), child: chip, ), ); } if (chips.isEmpty) return const SizedBox(height: 60); return SizedBox( height: 60, child: ListView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 24), children: chips, ), ); } // ── Step builders ───────────────────────────────────────────────────────────── Widget _buildMoodStep() { final theme = Theme.of(context); return Column( children: [ Text( 'How are you feeling?', style: theme.textTheme.headlineSmall ?.copyWith(fontWeight: FontWeight.w600), textAlign: TextAlign.center, ), const SizedBox(height: 48), MoodSelector( selected: _mood ?? 3, emojis: _moodEmojis, labels: _moodLabels, colors: _scaleColors, onChanged: (v) { setState(() => _mood = v); Future.delayed(const Duration(milliseconds: 250), _advance); }, ), const SizedBox(height: 16), if (_mood != null) AnimatedSwitcher( duration: const Duration(milliseconds: 200), child: Text( _moodLabels[_mood! - 1], key: ValueKey(_mood), style: theme.textTheme.titleLarge?.copyWith( color: _colorFor(_mood!), fontWeight: FontWeight.w500, ), ), ), ], ); } Widget _buildSleepStep() { final theme = Theme.of(context); const minuteOptions = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]; return Column( children: [ Text( 'How long did you sleep?', style: theme.textTheme.headlineSmall ?.copyWith(fontWeight: FontWeight.w600), textAlign: TextAlign.center, ), const SizedBox(height: 32), // live circle Container( width: 100, height: 100, decoration: const BoxDecoration( color: Color(0xFF42A5F5), shape: BoxShape.circle, ), child: Center( child: Text( _sleepLabel(), style: const TextStyle( fontSize: 22, fontWeight: FontWeight.w700, color: Colors.white, ), ), ), ), const SizedBox(height: 32), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // Hours wheel Column( children: [ Text('Hours', style: theme.textTheme.labelLarge), const SizedBox(height: 8), SizedBox( width: 80, height: 160, child: ListWheelScrollView.useDelegate( controller: _hoursCtrl, itemExtent: 48, perspective: 0.003, diameterRatio: 1.4, physics: const FixedExtentScrollPhysics(), onSelectedItemChanged: (i) => setState(() => _sleepHours = i), childDelegate: ListWheelChildBuilderDelegate( childCount: 13, // 0–12 builder: (ctx, i) => Center( child: Text( '$i', style: theme.textTheme.titleLarge, ), ), ), ), ), ], ), const SizedBox(width: 16), Text(':', style: theme.textTheme.headlineMedium), const SizedBox(width: 16), // Minutes wheel Column( children: [ Text('Minutes', style: theme.textTheme.labelLarge), const SizedBox(height: 8), SizedBox( width: 80, height: 160, child: ListWheelScrollView.useDelegate( controller: _minsCtrl, itemExtent: 48, perspective: 0.003, diameterRatio: 1.4, physics: const FixedExtentScrollPhysics(), onSelectedItemChanged: (i) => setState(() => _sleepMinutesVal = minuteOptions[i]), childDelegate: ListWheelChildBuilderDelegate( childCount: minuteOptions.length, builder: (ctx, i) => Center( child: Text( minuteOptions[i].toString().padLeft(2, '0'), style: theme.textTheme.titleLarge, ), ), ), ), ), ], ), ], ), const SizedBox(height: 32), FilledButton( onPressed: _advance, child: const Text('Next →'), ), ], ); } Widget _buildScaleStep({ required String title, required List emojis, required List labels, required int? current, required ValueChanged onSelected, }) { final theme = Theme.of(context); return Column( children: [ Text( title, style: theme.textTheme.headlineSmall ?.copyWith(fontWeight: FontWeight.w600), textAlign: TextAlign.center, ), const SizedBox(height: 48), StepScale( emojis: emojis, labels: labels, colors: _scaleColors, selected: current, onSelected: (v) { onSelected(v); Future.delayed(const Duration(milliseconds: 250), _advance); }, ), const SizedBox(height: 16), if (current != null) AnimatedSwitcher( duration: const Duration(milliseconds: 200), child: Text( labels[current - 1], key: ValueKey(current), style: theme.textTheme.titleLarge?.copyWith( color: _colorFor(current), fontWeight: FontWeight.w500, ), ), ), ], ); } Widget _buildActivitiesStep() { final theme = Theme.of(context); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Text( 'What have you been doing?', style: theme.textTheme.headlineSmall ?.copyWith(fontWeight: FontWeight.w600), textAlign: TextAlign.center, ), ), const SizedBox(height: 32), const ActivityGrid(), const SizedBox(height: 32), Center( child: FilledButton( onPressed: _advance, child: const Text('Done →'), ), ), ], ); } Widget _buildReviewStep() { final theme = Theme.of(context); final steps = _steps!; return Column( children: [ Text( 'Ready to save?', style: theme.textTheme.headlineSmall ?.copyWith(fontWeight: FontWeight.w600), textAlign: TextAlign.center, ), const SizedBox(height: 24), Wrap( spacing: 12, runSpacing: 12, alignment: WrapAlignment.center, children: [ for (int i = 0; i < steps.length; i++) _reviewChipFor(steps[i], i), ], ), const SizedBox(height: 48), // Save FAB GestureDetector( onTap: _save, child: Container( width: 72, height: 72, decoration: const BoxDecoration( color: Color(0xFF4CAF50), shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Color(0x554CAF50), blurRadius: 12, offset: Offset(0, 4), ) ], ), child: const Icon(Icons.check, color: Colors.white, size: 36), ), ), ], ); } Widget _reviewChipFor(_Step step, int idx) { switch (step) { case _Step.mood: return _reviewChipTile( label: _mood != null ? _moodLabels[_mood! - 1] : '—', emoji: _mood != null ? _moodEmojis[_mood! - 1] : '?', color: _mood != null ? _colorFor(_mood!) : Colors.grey, onTap: () => _editStepFromReview(idx), ); case _Step.sleep: return _reviewChipTile( label: 'Sleep', emoji: _sleepLabel(), color: const Color(0xFF42A5F5), onTap: () => _editStepFromReview(idx), ); case _Step.energy: return _reviewChipTile( label: _energy != null ? _energyLabels[_energy! - 1] : '—', emoji: _energy != null ? _energyEmojis[_energy! - 1] : '?', color: _energy != null ? _colorFor(_energy!) : Colors.grey, onTap: () => _editStepFromReview(idx), ); case _Step.positivity: return _reviewChipTile( label: _positivity != null ? _positivityLabels[_positivity! - 1] : '—', emoji: _positivity != null ? _positivityEmojis[_positivity! - 1] : '?', color: _positivity != null ? _colorFor(_positivity!) : Colors.grey, onTap: () => _editStepFromReview(idx), ); case _Step.selfWorth: return _reviewChipTile( label: _selfWorth != null ? _selfWorthLabels[_selfWorth! - 1] : '—', emoji: _selfWorth != null ? _selfWorthEmojis[_selfWorth! - 1] : '?', color: _selfWorth != null ? _colorFor(_selfWorth!) : Colors.grey, onTap: () => _editStepFromReview(idx), ); case _Step.activities: return GestureDetector( onTap: () => _editStepFromReview(idx), child: ActivitiesChip( backgroundColor: const Color(0xFF78909C), onTap: () => _editStepFromReview(idx), ), ); } } Widget _reviewChipTile({ required String label, required String emoji, required Color color, required VoidCallback onTap, }) { return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), decoration: BoxDecoration( color: color.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(30), border: Border.all(color: color.withValues(alpha: 0.5), width: 1.5), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text(emoji, style: const TextStyle(fontSize: 20)), const SizedBox(width: 8), Text( label, style: TextStyle( color: color, fontWeight: FontWeight.w600, fontSize: 14, ), ), const SizedBox(width: 4), Icon(Icons.edit, size: 14, color: color.withValues(alpha: 0.7)), ], ), ), ); } // ── Build ───────────────────────────────────────────────────────────────────── @override Widget build(BuildContext context) { final firstEntryAsync = ref.watch(isFirstEntryTodayProvider); return firstEntryAsync.when( loading: () => const Scaffold( body: Center(child: CircularProgressIndicator()), ), error: (e, _) => Scaffold( body: Center(child: Text('Error: $e')), ), data: (isFirstToday) { // Build (or reuse) the step list once resolved _steps ??= _buildStepList(isFirstToday); return Scaffold( body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 16), // ── Answer chip row ────────────────────────────────── _buildChipRow(), const SizedBox(height: 24), // ── Step content ───────────────────────────────────── Expanded( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24), child: _buildCurrentStep(), ), ), ], ), ), ); }, ); } Widget _buildCurrentStep() { if (_inReview) return _buildReviewStep(); final step = _currentStep; switch (step) { case _Step.mood: return _buildMoodStep(); case _Step.sleep: return _buildSleepStep(); case _Step.energy: return _buildScaleStep( title: 'How is your energy level?', emojis: _energyEmojis, labels: _energyLabels, current: _energy, onSelected: (v) => setState(() => _energy = v), ); case _Step.positivity: return _buildScaleStep( title: 'How positive do you feel?', emojis: _positivityEmojis, labels: _positivityLabels, current: _positivity, onSelected: (v) => setState(() => _positivity = v), ); case _Step.selfWorth: return _buildScaleStep( title: 'How is your self-worth?', emojis: _selfWorthEmojis, labels: _selfWorthLabels, current: _selfWorth, onSelected: (v) => setState(() => _selfWorth = v), ); case _Step.activities: return _buildActivitiesStep(); } } }