1use crate::utils::{get_recipe_out_path, input_msg, print_table, title};
3use crate::{Ingredient, IngredientRow, Recipe, StepRow};
4use colored::*;
5use dialoguer::Input;
6use std::fs;
7use std::io;
8use std::str::FromStr;
9
10pub fn add_recipe(recipe_dir: &String) -> io::Result<()> {
13 title("\t\u{21F8} Recipe Name\n\n");
14 let name: String = Input::new()
15 .with_prompt("Enter recipe name")
16 .interact_text()?;
17 let recipe_path = get_recipe_out_path(&recipe_dir, &name);
18 let tags = add_tags().expect("Failed to parse tags");
19 let ingredients = add_ingredients().expect("Failed adding ingredients");
20 let steps = add_steps().expect("Failed adding steps");
21 let recipe = Recipe {
22 name,
23 tags,
24 ingredients,
25 steps,
26 };
27 let serialized = serde_yaml::to_string(&recipe).expect("Failed to serialize recipe");
28 fs::write(&recipe_path, &serialized).expect("Failed to save recipe");
29 println!("Recipe saved to {}", recipe_path.to_str().unwrap());
30 Ok(())
31}
32
33fn add_tags() -> io::Result<Vec<String>> {
35 title("\t\u{21F8} Tags\n\n");
36 Ok(input_msg("Enter associated tags (e.g. soup, mealprep)")?
37 .split(", ")
38 .map(|s| s.to_owned())
39 .collect())
40}
41
42fn add_ingredients() -> io::Result<Vec<Ingredient>> {
44 let base = "\t\u{21F8} Ingredients\n\n";
45 let mut rows: Vec<IngredientRow> = vec![];
46 let mut ingredients: Vec<Ingredient> = vec![];
47 title(&format!(
48 "{}<AMOUNT> <UNIT> <INGREDIENT> (Ex: 1 lb beef)",
49 base
50 ));
51 loop {
52 if !ingredients.is_empty() {
53 print_table(&rows);
54 }
55 let ingredient_string: String = input_msg("Enter ingredient (or ENTER to continue)")?;
56 if ingredient_string.is_empty() {
57 break;
58 }
59 let ingredient = match Ingredient::from_str(&ingredient_string) {
60 Ok(ingr) => ingr,
61 Err(e) => {
62 title(&format!("{} (or ENTER to continue)", base));
63 println!("{e}\n{}\n", "...Please try again.".red());
64 continue;
65 }
66 };
67 ingredients.push(ingredient.clone());
68 rows.push(ingredient.try_into().expect("IngredientRow failed"));
69 title(&format!("{} (or ENTER to continue)", base));
70 }
71 Ok(ingredients)
72}
73
74fn add_steps() -> io::Result<Vec<String>> {
76 let msg = "\t\u{21F8} Steps\n\n";
77 title(msg);
78 let mut steps: Vec<String> = vec![];
79 let mut rows: Vec<StepRow> = vec![];
80 let mut i: u16 = 1;
81 loop {
82 if !steps.is_empty() {
83 print_table(&rows);
84 }
85 let step: String = input_msg("Enter step (or ENTER to quit)")?;
86 if step.is_empty() {
87 break;
88 };
89 steps.push(step.clone());
90 rows.push(StepRow {
91 Step: i,
92 Details: step,
93 });
94 i += 1;
95 title(msg);
96 }
97 Ok(steps)
98}