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 <noreply@anthropic.com>
This commit is contained in:
parent
fb494a349c
commit
8bb1cc1e61
3 changed files with 338 additions and 4 deletions
|
|
@ -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<SavedRunDetailScreen> {
|
|||
}
|
||||
|
||||
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,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
333
lib/screens/view_inputs_screen.dart
Normal file
333
lib/screens/view_inputs_screen.dart
Normal file
|
|
@ -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)';
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue