/// Post-sort home — landscape summary and gateways (Stitch Practice Hub). library; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/value_card.dart'; import '../providers/values_sort_provider.dart'; import '../widgets/practice_chrome.dart'; class PracticeHubScreen extends StatelessWidget { const PracticeHubScreen({super.key}); @override Widget build(BuildContext context) { final sort = context.watch(); final text = Theme.of(context).textTheme; final colors = Theme.of(context).colorScheme; final answered = sort.totalAnsweredReflections; final slots = sort.totalReflectionSlots; final progress = slots == 0 ? 0.0 : answered / slots; final core = sort.rankedCards.take(5).toList(growable: false); return PracticeScaffold( padding: const EdgeInsets.fromLTRB(20, 4, 20, 8), footer: FilledButton.tonal( onPressed: () => _confirmReset(context, sort), style: FilledButton.styleFrom( minimumSize: const Size.fromHeight(52), backgroundColor: colors.surfaceContainerHigh, foregroundColor: colors.onSurface, shape: const StadiumBorder(), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.restart_alt, size: 18, color: colors.outline), const SizedBox(width: 8), Text( 'Finish Practice (Reset All)', style: text.labelLarge?.copyWith(color: colors.onSurface), ), ], ), ), child: ListView( children: [ Text( 'Your Values Landscape', style: text.displaySmall?.copyWith(color: colors.onSurface), ), const SizedBox(height: 18), _CoreValuesCard( values: core, onValueTap: (card) => sort.goToReflection(valueId: card.id), ), const SizedBox(height: 20), _GatewayCard( icon: Icons.layers_outlined, iconColor: colors.primary, title: 'All Sorted Values', onTap: sort.goToOverview, ), const SizedBox(height: 12), _GatewayCard( icon: Icons.format_list_numbered, iconColor: colors.secondary, title: 'Order Top Values', onTap: sort.goToRanking, ), const SizedBox(height: 12), _GatewayCard( icon: Icons.edit_note, iconColor: colors.tertiary, title: 'Reflect & Inquire', meta: slots == 0 ? 'Rank top values first' : '$answered of $slots Answered (${(progress * 100).round()}%)', metaBackground: colors.tertiaryContainer.withValues(alpha: 0.45), metaForeground: colors.onTertiaryContainer, progress: slots == 0 ? null : progress, onTap: sort.coreValues.isEmpty ? null : sort.goToReflection, ), const SizedBox(height: 8), ], ), ); } Future _confirmReset( BuildContext context, ValuesSortController sort, ) async { final ok = await showModalBottomSheet( context: context, isScrollControlled: true, builder: (ctx) { final text = Theme.of(ctx).textTheme; final c = Theme.of(ctx).colorScheme; return SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(24, 8, 24, 24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ CircleAvatar( backgroundColor: c.errorContainer.withValues(alpha: 0.5), child: Icon(Icons.hourglass_empty, color: c.error), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Reset Entire Practice?', style: text.titleLarge), Text( 'Clean slate contemplation', style: text.labelSmall, ), ], ), ), ], ), const SizedBox(height: 14), Text( 'This deliberate action will clear all 5 categorized piles, ' 'your prioritized hierarchy, and stored reflection notes. ' 'You will begin this mindful exploration from the initial deck.', style: text.bodyMedium, ), const SizedBox(height: 14), Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: c.surfaceContainer, borderRadius: BorderRadius.circular(16), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.lightbulb_outline, size: 18, color: c.secondary), const SizedBox(width: 8), Expanded( child: Text( 'Tip: You can pause here and revisit your values whenever you need clarity in daily choices without resetting.', style: text.bodySmall, ), ), ], ), ), const SizedBox(height: 18), PrimaryPillButton( label: 'Yes, Reset All ${sort.totalCount} Cards', onPressed: () => Navigator.pop(ctx, true), ), const SizedBox(height: 8), GhostPillButton( label: 'Keep My Current Landscape', onPressed: () => Navigator.pop(ctx, false), ), ], ), ), ); }, ); if (ok == true) sort.restart(); } } class _CoreValuesCard extends StatelessWidget { const _CoreValuesCard({ required this.values, required this.onValueTap, }); final List values; final void Function(ValueCard card) onValueTap; @override Widget build(BuildContext context) { final text = Theme.of(context).textTheme; final colors = Theme.of(context).colorScheme; final accent = colors.secondary; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: colors.surfaceContainerLow, borderRadius: BorderRadius.circular(22), border: Border.all(color: colors.outlineVariant.withValues(alpha: 0.7)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 28, height: 28, decoration: BoxDecoration( color: accent.withValues(alpha: 0.18), shape: BoxShape.circle, ), child: Icon(Icons.star, size: 15, color: accent), ), const SizedBox(width: 10), Expanded( child: Text( 'Your Core Values', style: text.titleLarge?.copyWith( color: colors.onSurface, fontWeight: FontWeight.w400, ), ), ), ], ), const SizedBox(height: 14), if (values.isEmpty) Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: Text( 'Rank your Most Important values to distill your core set here.', style: text.bodyMedium?.copyWith( color: colors.onSurfaceVariant, ), ), ) else LayoutBuilder( builder: (context, constraints) { final gap = 8.0; final chipWidth = (constraints.maxWidth - gap) / 2; return Wrap( spacing: gap, runSpacing: gap, children: [ for (var i = 0; i < values.length; i++) SizedBox( width: chipWidth, child: _CoreValueChip( rank: i + 1, title: values[i].title, accent: accent, onTap: () => onValueTap(values[i]), ), ), ], ); }, ), ], ), ); } } class _CoreValueChip extends StatelessWidget { const _CoreValueChip({ required this.rank, required this.title, required this.accent, required this.onTap, }); final int rank; final String title; final Color accent; final VoidCallback onTap; @override Widget build(BuildContext context) { final text = Theme.of(context).textTheme; final colors = Theme.of(context).colorScheme; return Material( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(14), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(14), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), child: Row( children: [ Container( width: 22, height: 22, alignment: Alignment.center, decoration: BoxDecoration( color: accent.withValues(alpha: 0.18), shape: BoxShape.circle, ), child: Text( '$rank', style: text.labelSmall?.copyWith( color: accent, fontWeight: FontWeight.w700, ), ), ), const SizedBox(width: 8), Expanded( child: Text( title, maxLines: 1, overflow: TextOverflow.ellipsis, style: text.labelMedium?.copyWith( color: colors.onSurface, fontWeight: FontWeight.w600, ), ), ), ], ), ), ), ); } } class _GatewayCard extends StatelessWidget { const _GatewayCard({ required this.icon, required this.iconColor, required this.title, required this.onTap, this.meta, this.metaBackground, this.metaForeground, this.progress, }); final IconData icon; final Color iconColor; final String title; final String? meta; final Color? metaBackground; final Color? metaForeground; final VoidCallback? onTap; final double? progress; @override Widget build(BuildContext context) { final text = Theme.of(context).textTheme; final colors = Theme.of(context).colorScheme; final enabled = onTap != null; final hasMeta = meta != null && meta!.isNotEmpty; return Opacity( opacity: enabled ? 1 : 0.55, child: Material( color: colors.surfaceContainerLow, elevation: 0, shadowColor: colors.shadow.withValues(alpha: 0.08), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(20), child: Padding( padding: const EdgeInsets.all(18), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: 40, height: 40, decoration: BoxDecoration( color: colors.surfaceContainerHigh, shape: BoxShape.circle, ), child: Icon(icon, color: iconColor, size: 22), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( title, style: text.titleLarge?.copyWith( color: colors.onSurface, fontWeight: FontWeight.w400, ), ), if (hasMeta) ...[ const SizedBox(height: 6), Container( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 3, ), decoration: BoxDecoration( color: metaBackground ?? colors.surfaceContainer, borderRadius: BorderRadius.circular(999), ), child: Text( meta!, style: text.labelSmall?.copyWith( color: metaForeground ?? colors.onSurfaceVariant, ), ), ), ], ], ), ), Icon( Icons.arrow_forward, color: colors.primary, size: 22, ), ], ), if (progress != null) ...[ const SizedBox(height: 14), ClipRRect( borderRadius: BorderRadius.circular(999), child: LinearProgressIndicator( value: progress, minHeight: 6, backgroundColor: colors.surfaceContainerHighest, color: colors.tertiary, ), ), ], ], ), ), ), ), ); } }