94 lines
2.9 KiB
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)';
|
|
}
|