import 'package:flutter/material.dart'; import '../models/models.dart'; import '../storage/local_storage.dart'; import '../theme.dart'; import 'about_screen.dart'; import 'baseline_screen.dart'; import 'compare_runs_screen.dart'; class SavedRunDetailScreen extends StatefulWidget { final SavedRun savedRun; const SavedRunDetailScreen({super.key, required this.savedRun}); @override State createState() => _SavedRunDetailScreenState(); } class _SavedRunDetailScreenState extends State { late SavedRun _savedRun; int _savedRunsCount = 0; @override void initState() { super.initState(); _savedRun = widget.savedRun; _loadSavedRunsCount(); } Future _loadSavedRunsCount() async { final count = await LocalStorage.getSavedRunsCount(); setState(() => _savedRunsCount = count); } @override Widget build(BuildContext context) { final result = _savedRun.result; final dominant = result.dominantFactor; final secondary = result.secondaryFactor; return Scaffold( appBar: AppBar( title: const Text('Saved Run'), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => Navigator.pop(context), ), actions: [ IconButton( icon: const Icon(Icons.info_outline), onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (_) => const AboutScreen()), ), ), ], ), body: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Label (editable) _buildLabelRow(), const SizedBox(height: 8), Text( _savedRun.displayDate, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: AppColors.textSecondary, ), ), const SizedBox(height: 24), if (dominant != null) ...[ // Dominant challenge card _buildDominantCard(dominant), const SizedBox(height: 24), // Secondary factor if (secondary != null) ...[ Text( 'Secondary Factor', style: Theme.of(context).textTheme.headlineSmall, ), const SizedBox(height: 12), _buildSecondaryCard(secondary), const SizedBox(height: 24), ], // All factors if (result.rankedFactors.length > 2) ...[ Text( 'All Factors', style: Theme.of(context).textTheme.headlineSmall, ), const SizedBox(height: 12), ...result.rankedFactors.skip(2).map((factor) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: _buildFactorRow(factor), ); }), const SizedBox(height: 16), ], ] else ...[ _buildOptimalCard(), const SizedBox(height: 24), ], // Profile summary _buildProfileSummary(), const SizedBox(height: 24), // Model version Center( child: Text( 'Model v${result.modelVersion}', style: Theme.of(context).textTheme.bodySmall, ), ), const SizedBox(height: 32), // Action buttons SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _viewInputs, child: const Text('View Inputs'), ), ), const SizedBox(height: 12), SizedBox( width: double.infinity, child: OutlinedButton( onPressed: _useAsStartingPoint, child: const Text('Use as Starting Point'), ), ), if (_savedRunsCount >= 2) ...[ const SizedBox(height: 12), SizedBox( width: double.infinity, child: OutlinedButton( onPressed: _compare, child: const Text('Compare'), ), ), ], const SizedBox(height: 16), ], ), ), ), ); } Widget _buildLabelRow() { return Row( children: [ Expanded( child: Text( _savedRun.label, style: Theme.of(context).textTheme.headlineMedium, ), ), IconButton( icon: const Icon(Icons.edit_outlined, size: 20), onPressed: _editLabel, ), ], ); } Widget _buildDominantCard(RankedFactor factor) { return Container( width: double.infinity, padding: const EdgeInsets.all(24), decoration: BoxDecoration( gradient: const LinearGradient( colors: [AppColors.primary, AppColors.primaryDark], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(20), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'DOMINANT CHALLENGE', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w700, color: Colors.white70, letterSpacing: 1.2, ), ), const SizedBox(height: 12), Text( factor.displayName, style: const TextStyle( fontSize: 28, fontWeight: FontWeight.w700, color: Colors.white, letterSpacing: -0.5, ), ), const SizedBox(height: 20), Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'ESTIMATED GAIN', style: TextStyle( fontSize: 11, fontWeight: FontWeight.w600, color: Colors.white60, letterSpacing: 0.8, ), ), const SizedBox(height: 4), Text( '${factor.delta.rangeDisplay} months', style: const TextStyle( fontSize: 24, fontWeight: FontWeight.w700, color: Colors.white, ), ), ], ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.white.withAlpha(51), borderRadius: BorderRadius.circular(8), ), child: Text( _getConfidenceLabel(factor.delta.confidence), style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: Colors.white, ), ), ), ], ), ], ), ); } Widget _buildSecondaryCard(RankedFactor factor) { return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.divider), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( factor.displayName, style: Theme.of(context).textTheme.headlineSmall, ), const SizedBox(height: 4), Text( '${factor.delta.rangeDisplay} months', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: AppColors.primary, fontWeight: FontWeight.w600, ), ), ], ), ), _buildConfidenceBadge(factor.delta.confidence), ], ), ); } Widget _buildFactorRow(RankedFactor factor) { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: AppColors.surfaceVariant, borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( factor.displayName, style: Theme.of(context).textTheme.bodyLarge, ), Text( '${factor.delta.rangeDisplay} mo', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: AppColors.primary, fontWeight: FontWeight.w600, ), ), ], ), ); } Widget _buildOptimalCard() { return Container( width: double.infinity, padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: AppColors.success.withAlpha(26), borderRadius: BorderRadius.circular(20), border: Border.all(color: AppColors.success.withAlpha(77)), ), child: Column( children: [ const Icon( Icons.check_circle_outline, size: 48, color: AppColors.success, ), const SizedBox(height: 16), Text( 'No significant factors identified', style: Theme.of(context).textTheme.headlineSmall?.copyWith( color: AppColors.success, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( 'Behaviors were near optimal at this time.', style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), ], ), ); } Widget _buildProfileSummary() { final profile = _savedRun.profile; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.surfaceVariant, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ const Icon(Icons.person_outline, color: AppColors.textSecondary), const SizedBox(width: 12), Expanded( child: Text( '${profile.age} years old, ${profile.sex.name}, ${profile.country}', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: AppColors.textSecondary, ), ), ), ], ), ); } Widget _buildConfidenceBadge(Confidence confidence) { Color color; switch (confidence) { case Confidence.high: color = AppColors.success; break; case Confidence.moderate: color = AppColors.warning; break; case Confidence.emerging: color = AppColors.textTertiary; break; } return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: color.withAlpha(26), borderRadius: BorderRadius.circular(6), ), child: Text( _getConfidenceLabel(confidence), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: color, ), ), ); } String _getConfidenceLabel(Confidence confidence) { switch (confidence) { case Confidence.high: return 'High'; case Confidence.moderate: return 'Moderate'; case Confidence.emerging: return 'Emerging'; } } void _editLabel() { final controller = TextEditingController(text: _savedRun.label); showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Edit Label'), content: TextField( controller: controller, autofocus: true, decoration: const InputDecoration( hintText: 'Enter a label', ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Cancel'), ), TextButton( onPressed: () async { final newLabel = controller.text.trim(); final navigator = Navigator.of(context); if (newLabel.isNotEmpty) { await LocalStorage.updateSavedRunLabel(_savedRun.id, newLabel); setState(() { _savedRun = _savedRun.copyWith(label: newLabel); }); } navigator.pop(); }, child: const Text('Save'), ), ], ), ); } void _viewInputs() { // Navigate to read-only baseline screen with saved data Navigator.push( context, MaterialPageRoute( builder: (_) => BaselineScreen( readOnly: true, initialProfile: _savedRun.profile, ), ), ); } void _useAsStartingPoint() { // Navigate to editable baseline screen with saved data pre-filled Navigator.pushAndRemoveUntil( context, MaterialPageRoute( builder: (_) => BaselineScreen( initialProfile: _savedRun.profile, ), ), (route) => false, ); } void _compare() { Navigator.push( context, MaterialPageRoute( builder: (_) => CompareRunsScreen(initialRun: _savedRun), ), ); } }