From 8bb1cc1e61d7229b6c32cae0462adf6d7baf7e66 Mon Sep 17 00:00:00 2001 From: John Mizerek Date: Sat, 21 Feb 2026 19:50:32 -0800 Subject: [PATCH] Add unified View Inputs screen for saved runs Shows all profile and behavioral inputs in a single scrolling list instead of paginated screens. Displays formatted values for all fields. Co-Authored-By: Claude Opus 4.5 --- lib/screens/saved_run_detail_screen.dart | 8 +- lib/screens/screens.dart | 1 + lib/screens/view_inputs_screen.dart | 333 +++++++++++++++++++++++ 3 files changed, 338 insertions(+), 4 deletions(-) create mode 100644 lib/screens/view_inputs_screen.dart diff --git a/lib/screens/saved_run_detail_screen.dart b/lib/screens/saved_run_detail_screen.dart index 7026613..84721c9 100644 --- a/lib/screens/saved_run_detail_screen.dart +++ b/lib/screens/saved_run_detail_screen.dart @@ -5,6 +5,7 @@ import '../theme.dart'; import 'about_screen.dart'; import 'baseline_screen.dart'; import 'compare_runs_screen.dart'; +import 'view_inputs_screen.dart'; class SavedRunDetailScreen extends StatefulWidget { final SavedRun savedRun; @@ -459,13 +460,12 @@ class _SavedRunDetailScreenState extends State { } void _viewInputs() { - // Navigate to read-only baseline screen with saved data Navigator.push( context, MaterialPageRoute( - builder: (_) => BaselineScreen( - readOnly: true, - initialProfile: _savedRun.profile, + builder: (_) => ViewInputsScreen( + profile: _savedRun.profile, + behaviors: _savedRun.behaviors, ), ), ); diff --git a/lib/screens/screens.dart b/lib/screens/screens.dart index def862a..c83ae25 100644 --- a/lib/screens/screens.dart +++ b/lib/screens/screens.dart @@ -7,4 +7,5 @@ export 'onboarding_screen.dart'; export 'results_screen.dart'; export 'saved_run_detail_screen.dart'; export 'saved_runs_screen.dart'; +export 'view_inputs_screen.dart'; export 'welcome_screen.dart'; diff --git a/lib/screens/view_inputs_screen.dart b/lib/screens/view_inputs_screen.dart new file mode 100644 index 0000000..ff917d5 --- /dev/null +++ b/lib/screens/view_inputs_screen.dart @@ -0,0 +1,333 @@ +import 'package:flutter/material.dart'; +import '../models/models.dart'; +import '../theme.dart'; + +class ViewInputsScreen extends StatelessWidget { + final UserProfile profile; + final BehavioralInputs behaviors; + + const ViewInputsScreen({ + super.key, + required this.profile, + required this.behaviors, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Saved Inputs'), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.pop(context), + ), + ), + body: SafeArea( + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Profile Section + _buildSectionHeader(context, 'Profile'), + const SizedBox(height: 12), + _buildInputRow(context, 'Age', '${profile.age} years'), + _buildInputRow(context, 'Sex', _formatSex(profile.sex)), + _buildInputRow(context, 'Country', profile.country), + _buildInputRow(context, 'Height', _formatHeight(profile.heightCm)), + _buildInputRow(context, 'Weight', _formatWeight(profile.weightKg)), + _buildInputRow(context, 'BMI', profile.bmi.toStringAsFixed(1)), + if (profile.diagnoses.isNotEmpty) + _buildInputRow( + context, + 'Conditions', + profile.diagnoses.map(_formatDiagnosis).join(', '), + ), + const SizedBox(height: 24), + + // Habits Section + _buildSectionHeader(context, 'Habits'), + const SizedBox(height: 12), + _buildInputRow( + context, + 'Smoking', + _formatSmoking(behaviors.smoking, behaviors.cigarettesPerDay), + ), + _buildInputRow( + context, + 'Alcohol', + _formatAlcohol(behaviors.alcohol), + ), + _buildInputRow( + context, + 'Sleep', + _formatSleep(behaviors.sleepHours, behaviors.sleepConsistent), + ), + _buildInputRow( + context, + 'Physical Activity', + _formatActivity(behaviors.activity), + ), + const SizedBox(height: 24), + + // Lifestyle Section + _buildSectionHeader(context, 'Lifestyle'), + const SizedBox(height: 12), + _buildInputRow( + context, + 'Diet Quality', + _formatDiet(behaviors.diet), + ), + _buildInputRow( + context, + 'Processed Food', + _formatProcessedFood(behaviors.processedFood), + ), + _buildInputRow( + context, + 'Drug Use', + _formatDrugUse(behaviors.drugUse), + ), + _buildInputRow( + context, + 'Social Connection', + _formatSocial(behaviors.social), + ), + _buildInputRow( + context, + 'Stress Level', + _formatStress(behaviors.stress), + ), + _buildInputRow( + context, + 'Driving', + _formatDriving(behaviors.driving), + ), + _buildInputRow( + context, + 'Work Hours', + _formatWorkHours(behaviors.workHours), + ), + const SizedBox(height: 32), + ], + ), + ), + ), + ); + } + + Widget _buildSectionHeader(BuildContext context, String title) { + return Text( + title, + style: Theme.of(context).textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.w600, + ), + ); + } + + Widget _buildInputRow(BuildContext context, String label, String value) { + return Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + decoration: BoxDecoration( + color: AppColors.surfaceVariant, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: AppColors.textSecondary, + ), + ), + Flexible( + child: Text( + value, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.right, + ), + ), + ], + ), + ), + ); + } + + String _formatSex(Sex sex) { + switch (sex) { + case Sex.male: + return 'Male'; + case Sex.female: + return 'Female'; + } + } + + String _formatHeight(double cm) { + final feet = (cm / 30.48).floor(); + final inches = ((cm / 2.54) % 12).round(); + return "$feet'$inches\" (${cm.round()} cm)"; + } + + String _formatWeight(double kg) { + final lbs = (kg * 2.20462).round(); + return '$lbs lbs (${kg.round()} kg)'; + } + + String _formatDiagnosis(Diagnosis d) { + switch (d) { + case Diagnosis.cardiovascular: + return 'Cardiovascular'; + case Diagnosis.diabetes: + return 'Diabetes'; + case Diagnosis.cancer: + return 'Cancer'; + case Diagnosis.copd: + return 'COPD'; + case Diagnosis.hypertension: + return 'Hypertension'; + } + } + + String _formatSmoking(SmokingStatus status, int cigarettesPerDay) { + switch (status) { + case SmokingStatus.never: + return 'Never smoked'; + case SmokingStatus.former: + return 'Former smoker'; + case SmokingStatus.current: + return 'Current ($cigarettesPerDay/day)'; + } + } + + String _formatAlcohol(AlcoholLevel level) { + switch (level) { + case AlcoholLevel.none: + return 'None'; + case AlcoholLevel.light: + return 'Light (1-7/week)'; + case AlcoholLevel.moderate: + return 'Moderate (8-14/week)'; + case AlcoholLevel.heavy: + return 'Heavy (15-21/week)'; + case AlcoholLevel.veryHeavy: + return 'Very Heavy (21+/week)'; + } + } + + String _formatSleep(double hours, bool consistent) { + final hoursStr = hours == hours.roundToDouble() + ? hours.toInt().toString() + : hours.toString(); + final consistentStr = consistent ? ', consistent' : ', inconsistent'; + return '$hoursStr hours$consistentStr'; + } + + String _formatActivity(ActivityLevel level) { + switch (level) { + case ActivityLevel.sedentary: + return 'Sedentary'; + case ActivityLevel.light: + return 'Light'; + case ActivityLevel.moderate: + return 'Moderate'; + case ActivityLevel.high: + return 'High'; + } + } + + String _formatDiet(DietQuality diet) { + switch (diet) { + case DietQuality.poor: + return 'Poor'; + case DietQuality.fair: + return 'Fair'; + case DietQuality.good: + return 'Good'; + case DietQuality.excellent: + return 'Excellent'; + } + } + + String _formatProcessedFood(ProcessedFoodLevel level) { + switch (level) { + case ProcessedFoodLevel.daily: + return 'Daily'; + case ProcessedFoodLevel.frequent: + return 'Frequent'; + case ProcessedFoodLevel.occasional: + return 'Occasional'; + case ProcessedFoodLevel.rarely: + return 'Rarely'; + } + } + + String _formatDrugUse(DrugUse use) { + switch (use) { + case DrugUse.none: + return 'None'; + case DrugUse.occasional: + return 'Occasional'; + case DrugUse.regular: + return 'Regular'; + case DrugUse.daily: + return 'Daily'; + } + } + + String _formatSocial(SocialConnection level) { + switch (level) { + case SocialConnection.isolated: + return 'Isolated'; + case SocialConnection.limited: + return 'Limited'; + case SocialConnection.moderate: + return 'Moderate'; + case SocialConnection.strong: + return 'Strong'; + } + } + + String _formatStress(StressLevel level) { + switch (level) { + case StressLevel.low: + return 'Low'; + case StressLevel.moderate: + return 'Moderate'; + case StressLevel.high: + return 'High'; + case StressLevel.chronic: + return 'Chronic'; + } + } + + String _formatDriving(DrivingExposure level) { + switch (level) { + case DrivingExposure.low: + return 'Low (<50 mi/week)'; + case DrivingExposure.moderate: + return 'Moderate (50-150 mi/week)'; + case DrivingExposure.high: + return 'High (150-300 mi/week)'; + case DrivingExposure.veryHigh: + return 'Very High (300+ mi/week)'; + } + } + + String _formatWorkHours(WorkHoursLevel level) { + switch (level) { + case WorkHoursLevel.normal: + return 'Normal (<40/week)'; + case WorkHoursLevel.elevated: + return 'Elevated (40-55/week)'; + case WorkHoursLevel.high: + return 'High (55-70/week)'; + case WorkHoursLevel.extreme: + return 'Extreme (70+/week)'; + } + } +}