mirror of
https://github.com/kuhyx/diet-guard.git
synced 2026-11-10 19:27:14 +01:00
Body: 2-column tiles, each opens its card in a sheet. Food bank: paged 3-column tiles, tap for macros. Pixel 6a widget test asserts no vertical scroll on log, calendar, food bank (250 foods) and body. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWVUTaKFW8m7YrvWbzV
79 lines
2.7 KiB
Dart
79 lines
2.7 KiB
Dart
/// Pure data helpers behind the Body screen (split out for the 250-line cap).
|
|
library;
|
|
|
|
import 'package:diet_guard_app/services/activity_kcal.dart';
|
|
import 'package:diet_guard_app/services/body_calc.dart';
|
|
import 'package:diet_guard_app/services/body_service.dart';
|
|
import 'package:diet_guard_app/services/body_steps.dart';
|
|
import 'package:diet_guard_app/services/log_storage_service.dart';
|
|
|
|
/// Builds the person from the stored profile and newest weight, or null
|
|
/// when anything the formulas need is missing.
|
|
Biometrics? currentBiometrics(BodyService body, DateTime today) {
|
|
final birth = DateTime.tryParse(body.birth ?? '');
|
|
final height = body.heightCm;
|
|
final sex = body.sex;
|
|
final weight = body.latestWeight;
|
|
if (birth == null || height == null || sex == null || weight == null) {
|
|
return null;
|
|
}
|
|
return Biometrics(
|
|
weightKg: weight.$2,
|
|
heightCm: height,
|
|
ageYears: ageOn(birth, today).toDouble(),
|
|
isMale: sex == 'm',
|
|
);
|
|
}
|
|
|
|
/// Steps outside workouts by day, as stored.
|
|
Map<String, int> stepsByDay(BodyService body) =>
|
|
body.document.steps.map((day, entry) => MapEntry(day, entry.n));
|
|
|
|
/// Mean daily exercise per formula (steps included), the steps' own share,
|
|
/// and the number of full days averaged -- like the PC's `_body_view`: the
|
|
/// two means are null without a person, or without any published workout
|
|
/// or step count.
|
|
(Map<String, double>?, double?, int) bodyExercise(
|
|
BodyService body,
|
|
Biometrics? bio,
|
|
DateTime today,
|
|
) {
|
|
final sessions = body.sessions;
|
|
final steps = stepsByDay(body);
|
|
if (bio == null || (sessions == null && steps.isEmpty)) {
|
|
return (null, null, 0);
|
|
}
|
|
final byDay = steps.map((day, n) => MapEntry(day, stepKcal(n, bio)));
|
|
final weight = bio.weightKg;
|
|
final all = sessions ?? const <Session>[];
|
|
return (
|
|
dailyExercise(all, weight, today, byDay),
|
|
extraShare(all, today, byDay),
|
|
windowDays(all, today, byDay),
|
|
);
|
|
}
|
|
|
|
/// Sums each day's non-deleted kcal.
|
|
Map<String, double> kcalByDay(DayLog log) => {
|
|
for (final entry in log.entries)
|
|
entry.key: entry.value
|
|
.where((food) => !food.deleted)
|
|
.fold<double>(0, (sum, food) => sum + food.kcal),
|
|
};
|
|
|
|
/// Why the numbers are missing.
|
|
String bodyMissingNote(BodyService body) {
|
|
if (body.latestWeight == null && body.birth == null) {
|
|
return 'Set your profile and enter your weight to see BMI, ideal '
|
|
'weight and calorie targets.';
|
|
}
|
|
if (body.latestWeight == null) return 'Enter your weight to see the numbers.';
|
|
return 'Set your profile (birth date, height, sex) to see the numbers.';
|
|
}
|
|
|
|
/// The age line value.
|
|
String bodyAgeText(BodyService body, DateTime today) {
|
|
final birth = DateTime.tryParse(body.birth ?? '');
|
|
return birth == null ? 'unknown' : '${ageOn(birth, today)}';
|
|
}
|