app/lib/models/saved_run.dart
John Mizerek 85e8e1a290 Add saved runs feature with history, comparison, and about screen (v1.2)
Features:
- Save calculation runs with custom labels for later retrieval
- View saved runs list with dominant factor summary
- View detailed results of any saved run
- View original inputs in read-only mode
- Use any saved run as starting point for new calculation
- Compare two saved runs side-by-side
- About screen with app info, help links, privacy policy
- Metric/Imperial unit toggle persisted across sessions
- Info icon in app bar on all screens

Technical:
- New SavedRun model with full serialization
- SQLite saved_runs table with CRUD operations
- readOnly mode for all input screens
- Unit preference stored in LocalStorage
- Database schema upgraded to v2

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-21 09:59:58 -08:00

80 lines
2.2 KiB
Dart

import 'behavioral_inputs.dart';
import 'result.dart';
import 'user_profile.dart';
class SavedRun {
final String id;
final String label;
final CalculationResult result;
final UserProfile profile;
final BehavioralInputs behaviors;
final DateTime createdAt;
const SavedRun({
required this.id,
required this.label,
required this.result,
required this.profile,
required this.behaviors,
required this.createdAt,
});
String get displayDate {
final now = DateTime.now();
final diff = now.difference(createdAt);
if (diff.inDays == 0) {
return 'Today';
} else if (diff.inDays == 1) {
return 'Yesterday';
} else if (diff.inDays < 7) {
return '${diff.inDays} days ago';
} else {
return '${createdAt.month}/${createdAt.day}/${createdAt.year}';
}
}
String get dominantFactorSummary {
final factor = result.dominantFactor;
if (factor == null) return 'Optimal';
return '${factor.displayName}: ${factor.delta.rangeDisplay} mo';
}
Map<String, dynamic> toJson() => {
'id': id,
'label': label,
'result': result.toJson(),
'profile': profile.toJson(),
'behaviors': behaviors.toJson(),
'createdAt': createdAt.toIso8601String(),
};
factory SavedRun.fromJson(Map<String, dynamic> json) => SavedRun(
id: json['id'] as String,
label: json['label'] as String,
result:
CalculationResult.fromJson(json['result'] as Map<String, dynamic>),
profile:
UserProfile.fromJson(json['profile'] as Map<String, dynamic>),
behaviors: BehavioralInputs.fromJson(
json['behaviors'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['createdAt'] as String),
);
SavedRun copyWith({
String? id,
String? label,
CalculationResult? result,
UserProfile? profile,
BehavioralInputs? behaviors,
DateTime? createdAt,
}) =>
SavedRun(
id: id ?? this.id,
label: label ?? this.label,
result: result ?? this.result,
profile: profile ?? this.profile,
behaviors: behaviors ?? this.behaviors,
createdAt: createdAt ?? this.createdAt,
);
}