glp-companion/lib/features/meal_planner/domain/entities/recipe.dart

94 lines
2.9 KiB
Dart

import 'macro_profile.dart';
import 'recipe_ingredient.dart';
/// Immutable recipe imported from the web (schema.org/JSON-LD or
/// OpenGraph fallback) or saved manually.
///
/// Pure Dart (no framework imports) so the entity can be shared by the
/// scraper use case, the drift-backed repository, and the Riverpod
/// presentation layer without leaking infrastructure concerns into the
/// domain.
class Recipe {
const Recipe({
required this.id,
required this.title,
required this.sourceUrl,
this.imageUrl,
this.description,
this.prepTimeMinutes = 0,
this.cookTimeMinutes = 0,
this.servings = 1,
this.ingredients = const [],
this.instructions = const [],
required this.macrosPerServing,
});
/// UUID primary key assigned when the recipe is first materialized.
final String id;
/// Human-readable recipe title (`name` / `og:title`).
final String title;
/// URL the recipe was imported from; also used to de-duplicate re-imports.
final String sourceUrl;
/// Representative image URL (`image` / `og:image`), if any.
final String? imageUrl;
/// Optional summary (`description` / `og:description`).
final String? description;
/// Preparation time in minutes (`prepTime`, ISO-8601 duration decoded);
/// `0` when unknown.
final int prepTimeMinutes;
/// Cook time in minutes (`cookTime`); `0` when unknown.
final int cookTimeMinutes;
/// Yield parsed from `recipeYield` (defaults to 4 when unparsable).
final int servings;
/// Parsed ingredient lines (raw text preserved).
final List<RecipeIngredient> ingredients;
/// Instruction steps with `HowToStep` / `HowToSection` wrappers flattened.
final List<String> instructions;
/// Nutrition facts per serving (`nutrition` block).
final MacroProfile macrosPerServing;
/// Total active time (prep + cook) in minutes.
int get totalMinutes => prepTimeMinutes + cookTimeMinutes;
Recipe copyWith({
String? id,
String? title,
String? sourceUrl,
String? imageUrl,
String? description,
int? prepTimeMinutes,
int? cookTimeMinutes,
int? servings,
List<RecipeIngredient>? ingredients,
List<String>? instructions,
MacroProfile? macrosPerServing,
}) =>
Recipe(
id: id ?? this.id,
title: title ?? this.title,
sourceUrl: sourceUrl ?? this.sourceUrl,
imageUrl: imageUrl ?? this.imageUrl,
description: description ?? this.description,
prepTimeMinutes: prepTimeMinutes ?? this.prepTimeMinutes,
cookTimeMinutes: cookTimeMinutes ?? this.cookTimeMinutes,
servings: servings ?? this.servings,
ingredients: ingredients ?? this.ingredients,
instructions: instructions ?? this.instructions,
macrosPerServing: macrosPerServing ?? this.macrosPerServing,
);
@override
String toString() => 'Recipe($id, "$title", '
'${macrosPerServing.proteinGrams}g protein/serving)';
}