85 lines
2.7 KiB
Dart
85 lines
2.7 KiB
Dart
enum MealType { breakfast, lunch, dinner, snack }
|
|
|
|
enum MealSource { manual, photoAi }
|
|
|
|
enum MealSyncStatus { pending, synced, failed }
|
|
|
|
class MealEntry {
|
|
MealEntry({
|
|
required this.id,
|
|
required this.name,
|
|
required this.mealType,
|
|
required this.calories,
|
|
required this.proteinGrams,
|
|
required this.carbohydrateGrams,
|
|
required this.fatGrams,
|
|
required this.consumedAt,
|
|
this.source = MealSource.manual,
|
|
this.notes = '',
|
|
this.syncStatus = MealSyncStatus.pending,
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final MealType mealType;
|
|
final double calories;
|
|
final double proteinGrams;
|
|
final double carbohydrateGrams;
|
|
final double fatGrams;
|
|
final DateTime consumedAt;
|
|
final MealSource source;
|
|
final String notes;
|
|
MealSyncStatus syncStatus;
|
|
|
|
Map<String, dynamic> toMap() => {
|
|
'id': id,
|
|
'name': name,
|
|
'meal_type': mealType.name,
|
|
'calories': calories,
|
|
'protein_grams': proteinGrams,
|
|
'carbohydrate_grams': carbohydrateGrams,
|
|
'fat_grams': fatGrams,
|
|
'consumed_at': consumedAt.toUtc().toIso8601String(),
|
|
'source': source == MealSource.photoAi ? 'photo_ai' : 'manual',
|
|
'notes': notes,
|
|
'sync_status': syncStatus.name,
|
|
};
|
|
|
|
Map<String, dynamic> toApiPayload() => {
|
|
'client_meal_uuid': id,
|
|
'name': name,
|
|
'meal_type': mealType.name,
|
|
'calories': calories,
|
|
'protein_grams': proteinGrams,
|
|
'carbohydrate_grams': carbohydrateGrams,
|
|
'fat_grams': fatGrams,
|
|
'consumed_at': consumedAt.toUtc().toIso8601String(),
|
|
'source': source == MealSource.photoAi ? 'photo_ai' : 'manual',
|
|
'notes': notes,
|
|
};
|
|
|
|
factory MealEntry.fromMap(Map<String, dynamic> map) => MealEntry(
|
|
id: map['id'] as String,
|
|
name: map['name'] as String,
|
|
mealType: MealType.values.firstWhere(
|
|
(value) => value.name == map['meal_type'],
|
|
orElse: () => MealType.snack,
|
|
),
|
|
calories: _asDouble(map['calories']),
|
|
proteinGrams: _asDouble(map['protein_grams']),
|
|
carbohydrateGrams: _asDouble(map['carbohydrate_grams']),
|
|
fatGrams: _asDouble(map['fat_grams']),
|
|
consumedAt: DateTime.parse(map['consumed_at'] as String).toLocal(),
|
|
source: map['source'] == 'photo_ai' || map['source'] == 'photoAi'
|
|
? MealSource.photoAi
|
|
: MealSource.manual,
|
|
notes: map['notes'] as String? ?? '',
|
|
syncStatus: MealSyncStatus.values.firstWhere(
|
|
(value) => value.name == map['sync_status'],
|
|
orElse: () => MealSyncStatus.pending,
|
|
),
|
|
);
|
|
}
|
|
|
|
double _asDouble(dynamic value) => value is num ? value.toDouble() : 0;
|