/// Deep reflection on top values, with optional full-screen journal sheet. library; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/values_sort_provider.dart'; import '../widgets/practice_chrome.dart'; class ReflectionScreen extends StatelessWidget { const ReflectionScreen({super.key}); @override Widget build(BuildContext context) { final sort = context.watch(); final cores = sort.coreValues; final activeId = sort.activeReflectionValueId ?? (cores.isEmpty ? null : cores.first.id); final active = activeId == null ? null : sort.cardById(activeId); final text = Theme.of(context).textTheme; final colors = Theme.of(context).colorScheme; return PracticeScaffold( header: Padding( padding: const EdgeInsets.fromLTRB(8, 4, 12, 0), child: Row( children: [ IconButton( onPressed: sort.goToHub, icon: const Icon(Icons.arrow_back), ), Expanded( child: Text( 'Step 5 · Deep Reflection', style: text.labelMedium, ), ), ], ), ), child: cores.isEmpty || active == null ? Center( child: Text( 'Rank at least one core value to reflect.', style: text.bodyLarge, ), ) : ListView( children: [ Text('Your Core Values', style: text.displaySmall), const SizedBox(height: 4), Text( '${cores.length} core anchors · ' '${sort.totalAnsweredReflections} of ${sort.totalReflectionSlots} answered', style: text.bodyMedium, ), const SizedBox(height: 14), SizedBox( height: 88, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: cores.length, separatorBuilder: (_, _) => const SizedBox(width: 8), itemBuilder: (context, index) { final card = cores[index]; final selected = card.id == active.id; final answered = sort.answeredPromptCount(card.id); final rankColor = selected ? colors.onPrimary : colors.secondary; final titleColor = selected ? colors.onPrimary : colors.onSurface; final metaColor = selected ? colors.onPrimary.withValues(alpha: 0.85) : colors.onSurfaceVariant; return InkWell( onTap: () => sort.selectReflectionValue(card.id), borderRadius: BorderRadius.circular(16), child: Container( width: 120, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: selected ? colors.primary : colors.surfaceContainerLow, borderRadius: BorderRadius.circular(16), border: Border.all( color: selected ? colors.primary : colors.outlineVariant, width: selected ? 2 : 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '#${index + 1}', style: text.labelSmall?.copyWith( color: rankColor, fontWeight: FontWeight.w700, ), ), Text( card.title, maxLines: 1, overflow: TextOverflow.ellipsis, style: text.titleMedium?.copyWith( color: titleColor, fontWeight: selected ? FontWeight.w700 : FontWeight.w500, ), ), Text( '$answered/${kReflectionPrompts.length}', style: text.labelSmall?.copyWith( color: metaColor, ), ), ], ), ), ); }, ), ), const SizedBox(height: 18), Text(active.title, style: text.headlineMedium), const SizedBox(height: 4), Text( '"${active.description}"', style: text.bodyMedium?.copyWith(fontStyle: FontStyle.italic), ), const SizedBox(height: 16), ...List.generate(kReflectionPrompts.length, (index) { final answer = sort.reflectionFor(active.id, index); final answered = answer.isNotEmpty; return Padding( padding: const EdgeInsets.only(bottom: 10), child: Material( color: colors.surfaceContainerLow, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(18), side: BorderSide(color: colors.outlineVariant), ), child: ListTile( leading: Icon( answered ? Icons.check_circle : Icons.circle_outlined, color: answered ? colors.tertiary : colors.onSurfaceVariant, ), title: Text( kReflectionPrompts[index], style: text.titleMedium, ), subtitle: answered ? Text( answer, maxLines: 2, overflow: TextOverflow.ellipsis, ) : null, trailing: Icon( answered ? Icons.edit_outlined : Icons.open_in_full, ), onTap: () => _openJournal( context, sort, active.id, index, ), ), ), ); }), ], ), ); } Future _openJournal( BuildContext context, ValuesSortController sort, String valueId, int promptIndex, ) async { sort.selectPrompt(promptIndex); final card = sort.cardById(valueId); if (card == null) return; await showModalBottomSheet( context: context, isScrollControlled: true, useSafeArea: true, builder: (ctx) => _ReflectionJournalSheet( cardTitle: card.title, prompt: kReflectionPrompts[promptIndex], initialText: sort.reflectionFor(valueId, promptIndex), onSave: (text) { sort.setReflection(valueId, promptIndex, text); }, ), ); } } class _ReflectionJournalSheet extends StatefulWidget { const _ReflectionJournalSheet({ required this.cardTitle, required this.prompt, required this.initialText, required this.onSave, }); final String cardTitle; final String prompt; final String initialText; final ValueChanged onSave; @override State<_ReflectionJournalSheet> createState() => _ReflectionJournalSheetState(); } class _ReflectionJournalSheetState extends State<_ReflectionJournalSheet> { late final TextEditingController _controller; @override void initState() { super.initState(); _controller = TextEditingController(text: widget.initialText); } @override void dispose() { _controller.dispose(); super.dispose(); } void _saveAndClose() { widget.onSave(_controller.text); Navigator.of(context).pop(); } @override Widget build(BuildContext context) { final text = Theme.of(context).textTheme; final colors = Theme.of(context).colorScheme; final bottom = MediaQuery.viewInsetsOf(context).bottom; return Padding( padding: EdgeInsets.fromLTRB(20, 8, 20, bottom + 20), child: Column( children: [ Row( children: [ Expanded( child: Text( 'Reflection · ${widget.cardTitle}', style: text.titleLarge, ), ), IconButton( onPressed: () => Navigator.pop(context), icon: const Icon(Icons.close), ), ], ), Align( alignment: Alignment.centerLeft, child: Text( widget.prompt, style: text.bodyLarge?.copyWith(color: colors.onSurfaceVariant), ), ), const SizedBox(height: 12), Expanded( child: TextField( controller: _controller, expands: true, maxLines: null, textAlignVertical: TextAlignVertical.top, decoration: const InputDecoration( hintText: 'Write freely. This stays on your device.', ), ), ), const SizedBox(height: 12), PrimaryPillButton( label: 'Save reflection', onPressed: _saveAndClose, ), ], ), ); } }