From 4638b3efd621a7303efdd4de66ebdc694aa9b50a Mon Sep 17 00:00:00 2001 From: "maxime.BATISTA@etu.uca.fr" Date: Thu, 11 May 2023 18:25:06 +0200 Subject: [PATCH] add favorite list handlings on app side and LocalEnpoint. Add 'RecipeDatabase' class to simulate a Recipe database --- Endpoint/IAccountOwnedRecipes.cs | 23 +++++ ...cipes.cs => IAccountRecipesPreferences.cs} | 19 ++-- Endpoint/IRecipesService.cs | 6 +- LocalEndpoint/AccountData.cs | 11 +++ LocalEndpoint/AccountManager.cs | 38 -------- LocalEndpoint/AccountOwnedRecipes.cs | 52 +++++++++++ LocalEndpoint/AccountRecipes.cs | 84 ----------------- LocalEndpoint/AccountRecipesPreferences.cs | 91 +++++++++++++++++++ LocalEndpoint/ConnectionManager.cs | 33 +++++++ LocalEndpoint/Constants.cs | 20 ++++ LocalEndpoint/LocalEndpoint.cs | 27 +++++- LocalEndpoint/RecipesDatabase.cs | 43 +++++++++ LocalEndpoint/RecipesService.cs | 50 +++++----- MainAppShell.xaml.cs | 6 +- Models/AccountRecipeRate.cs | 2 +- Views/FavoritesPage.xaml | 3 +- Views/FavoritesPage.xaml.cs | 29 ++++-- Views/HomePage.xaml.cs | 9 +- Views/MyListPage.xaml.cs | 9 +- Views/MyRecipesPage.xaml.cs | 21 +++-- Views/RecipePage.xaml | 7 +- Views/RecipePage.xaml.cs | 40 ++++++-- 22 files changed, 425 insertions(+), 198 deletions(-) create mode 100644 Endpoint/IAccountOwnedRecipes.cs rename Endpoint/{IAccountRecipes.cs => IAccountRecipesPreferences.cs} (54%) create mode 100644 LocalEndpoint/AccountData.cs delete mode 100644 LocalEndpoint/AccountManager.cs create mode 100644 LocalEndpoint/AccountOwnedRecipes.cs delete mode 100644 LocalEndpoint/AccountRecipes.cs create mode 100644 LocalEndpoint/AccountRecipesPreferences.cs create mode 100644 LocalEndpoint/ConnectionManager.cs create mode 100644 LocalEndpoint/Constants.cs create mode 100644 LocalEndpoint/RecipesDatabase.cs diff --git a/Endpoint/IAccountOwnedRecipes.cs b/Endpoint/IAccountOwnedRecipes.cs new file mode 100644 index 0000000..69d6b7b --- /dev/null +++ b/Endpoint/IAccountOwnedRecipes.cs @@ -0,0 +1,23 @@ +using Models; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LocalEndpoint +{ + public interface IAccountOwnedRecipes + { + + public Account Account { get; } + + public bool UploadRecipe(Recipe recipe); + + public bool RemoveRecipe(RecipeInfo info); + + + public ImmutableList GetAccountRecipes(); + } +} diff --git a/Endpoint/IAccountRecipes.cs b/Endpoint/IAccountRecipesPreferences.cs similarity index 54% rename from Endpoint/IAccountRecipes.cs rename to Endpoint/IAccountRecipesPreferences.cs index fd61153..cc2ae12 100644 --- a/Endpoint/IAccountRecipes.cs +++ b/Endpoint/IAccountRecipesPreferences.cs @@ -6,27 +6,24 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace LocalEndpoint +namespace Endpoint { - public interface IAccountRecipes + public interface IAccountRecipesPreferences { - public Account Account { get; } - public bool UploadRecipe(Recipe recipe); - - public bool RemoveRecipe(RecipeInfo info); - public void SetRate(RecipeInfo info, AccountRecipeRate rate); + public void AddToFavorites(RecipeInfo info); + public void RemoveFromFavorites(RecipeInfo info); + public void SetReviewScore(RecipeInfo info, uint score); - public AccountRecipeRate? FindRate(RecipeInfo info); + public AccountRecipeRate GetRate(RecipeInfo info); - public ImmutableList GetAccountRecipes(); + public ImmutableList GetFavorites(); public ImmutableList GetRecommendedRecipes(); - public ImmutableList GetFavorites(); - public ImmutableList<(RecipeInfo, uint)> GetWeeklyList(); + } } diff --git a/Endpoint/IRecipesService.cs b/Endpoint/IRecipesService.cs index df7d16a..f9159c2 100644 --- a/Endpoint/IRecipesService.cs +++ b/Endpoint/IRecipesService.cs @@ -2,6 +2,7 @@ using Models; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,11 +11,12 @@ namespace Endpoint { public interface IRecipesService { - public List PopularRecipes(); + public ImmutableList PopularRecipes(); public Recipe GetRecipe(RecipeInfo info); - public IAccountRecipes GetRecipesOf(Account account); + public IAccountOwnedRecipes GetRecipesOf(Account account); + public IAccountRecipesPreferences GetPreferencesOf(Account account); } diff --git a/LocalEndpoint/AccountData.cs b/LocalEndpoint/AccountData.cs new file mode 100644 index 0000000..cf84b07 --- /dev/null +++ b/LocalEndpoint/AccountData.cs @@ -0,0 +1,11 @@ +using Endpoint; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LocalEndpoint +{ + internal record AccountData(IAccountOwnedRecipes Recipes, IAccountRecipesPreferences Preferences); +} diff --git a/LocalEndpoint/AccountManager.cs b/LocalEndpoint/AccountManager.cs deleted file mode 100644 index e3df8fc..0000000 --- a/LocalEndpoint/AccountManager.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Models; -using Endpoint; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LocalEndpoint -{ - internal class AccountManager : IAccountManager - { - private static readonly Uri DEFAULT_ACCOUNT_IMAGE = new Uri("https://www.pngkey.com/png/full/115-1150152_default-profile-picture-avatar-png-green.png"); - - private Account userAccount = new Account(new User(DEFAULT_ACCOUNT_IMAGE, "Stub Account"), "test@example.com"); - private string userPassword = "123456"; - - public Account? Login(string email, string password) - { - if (userAccount.Email == email && userPassword == password) - { - return userAccount; - } - return null; - } - - - public Account? Register(string email, string username, string password) - { - if (email == null || username == null || password == null) - return null; - - userAccount = new Account(new User(DEFAULT_ACCOUNT_IMAGE, username), email); - userPassword = password; - return userAccount; - } - } -} diff --git a/LocalEndpoint/AccountOwnedRecipes.cs b/LocalEndpoint/AccountOwnedRecipes.cs new file mode 100644 index 0000000..e3d8059 --- /dev/null +++ b/LocalEndpoint/AccountOwnedRecipes.cs @@ -0,0 +1,52 @@ +using LocalEndpoint; +using Models; +using System.Collections.Immutable; + +namespace Endpoint +{ + internal class AccountOwnedRecipes : IAccountOwnedRecipes + { + + public Account Account { get; init; } + + private readonly Dictionary ownedRecipes = new Dictionary(); + private readonly RecipesDatabase db; + + public AccountOwnedRecipes(Account account, RecipesDatabase db) + { + Account = account; + this.db = db; + + //Retrieve all owned recipes from database. + db.ListAll().ForEach(recipe => + { + if (recipe.Owner == account.User) ownedRecipes[recipe.Info.Id] = recipe; + }); + } + + public bool UploadRecipe(Recipe recipe) + { + Guid id = recipe.Info.Id; + if (ownedRecipes.ContainsKey(id)) + { + return false; + } + db.Insert(recipe); + ownedRecipes.Add(id, recipe); + return true; + } + + public bool RemoveRecipe(RecipeInfo info) + { + db.Remove(info.Id); + return ownedRecipes.Remove(info.Id); + } + + public ImmutableList GetAccountRecipes() + { + return ownedRecipes.Values.ToImmutableList().ConvertAll(r => r.Info); + } + + + } +} diff --git a/LocalEndpoint/AccountRecipes.cs b/LocalEndpoint/AccountRecipes.cs deleted file mode 100644 index 12c7aa4..0000000 --- a/LocalEndpoint/AccountRecipes.cs +++ /dev/null @@ -1,84 +0,0 @@ -using LocalEndpoint; -using Models; -using System.Collections.Immutable; - -namespace Endpoint -{ - internal class AccountRecipes : IAccountRecipes - { - - public Account Account { get; init; } - - private readonly Dictionary ownedRecipes = new Dictionary(); - private readonly Dictionary ratedRecipes = new Dictionary(); - - public AccountRecipes(Account account) - { - Account = account; - } - - public bool UploadRecipe(Recipe recipe) - { - Guid id = recipe.Info.Id; - if (ownedRecipes.ContainsKey(id)) - { - return false; - } - ownedRecipes.Add(id, recipe); - return true; - } - - public bool RemoveRecipe(RecipeInfo info) - { - return ownedRecipes.Remove(info.Id); - } - - public ImmutableList GetAccountRecipes() - { - return ownedRecipes.Values.ToImmutableList().ConvertAll(r => r.Info); - } - - - public ImmutableList GetRecommendedRecipes() - { - return new List { - new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), - new RecipeInfo("Chocolate Cake", 2500, 10, new Uri("https://bakewithshivesh.com/wp-content/uploads/2022/08/IMG_0248-scaled.jpg"), 3, Guid.NewGuid()), - new RecipeInfo("Salmon", 20, 10, new Uri("https://www.wholesomeyum.com/wp-content/uploads/2021/06/wholesomeyum-Pan-Seared-Salmon-Recipe-13.jpg"), 4, Guid.NewGuid()), - new RecipeInfo("Fish", 50, 30, new Uri("https://www.ciaanet.org/wp-content/uploads/2022/07/Atlantic-and-Pacific-whole-salmon-1024x683.jpg"), 4.5F, Guid.NewGuid()), - new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()) - }.ToImmutableList(); - } - - public ImmutableList GetFavorites() - { - return new List { - new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), - new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), - new RecipeInfo("Fish And Ships", 450, 15, new Uri("https://upload.wikimedia.org/wikipedia/commons/f/ff/Fish_and_chips_blackpool.jpg"), 4, Guid.NewGuid()), - new RecipeInfo("Caesar Salad", 150, 20, new Uri("https://www.galbani.fr/wp-content/uploads/2020/04/AdobeStock_157570276-2.jpeg"), 1, Guid.NewGuid()) - }.ToImmutableList(); - } - - public ImmutableList<(RecipeInfo, uint)> GetWeeklyList() - { - return new List<(RecipeInfo, uint)> { - (new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), 4), - (new RecipeInfo("Chicken Curry", 500, 45, new Uri("https://cdn.chefclub.tools/uploads/recipes/cover-thumbnail/f287b191-dc8e-4c85-bbb6-e26387c354d3.jpg"), 3, Guid.NewGuid()), 4), - (new RecipeInfo("Spaghetti Bolognese", 1000, 30, new Uri("https://media.istockphoto.com/id/1144823591/fr/photo/spaghetti-dans-un-plat-sur-un-fond-blanc.jpg?s=612x612&w=0&k=20&c=qFzd8iE185mpsX7hWqYaieOWlzJVCkzFdYsxmwUT3-Q="), 1, Guid.NewGuid()), 1), - }.ToImmutableList(); - } - - public void SetRate(RecipeInfo info, AccountRecipeRate rate) - { - ratedRecipes.Add(info.Id, rate); - } - - public AccountRecipeRate? FindRate(RecipeInfo info) - { - AccountRecipeRate? rate = null; - ratedRecipes.TryGetValue(info.Id, out rate); - return rate; - } - } -} diff --git a/LocalEndpoint/AccountRecipesPreferences.cs b/LocalEndpoint/AccountRecipesPreferences.cs new file mode 100644 index 0000000..65b41b9 --- /dev/null +++ b/LocalEndpoint/AccountRecipesPreferences.cs @@ -0,0 +1,91 @@ +using Endpoint; +using Models; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LocalEndpoint +{ + internal class AccountRecipesPreferences : IAccountRecipesPreferences + { + //Binds a recipe's id to it's account review ratings. + private readonly Dictionary ratings = new Dictionary(); + + //Binds a recipe's id to its amount of person stored in the account's weekly list + private readonly Dictionary weekly = new Dictionary(); + + private readonly RecipesDatabase db; + public AccountRecipesPreferences(Account account, RecipesDatabase db) + { + Account = account; + this.db = db; + } + + public Account Account { get; init; } + + public ImmutableList GetRecommendedRecipes() + { + return db.ListAll().ConvertAll(recipe => recipe.Info); + } + + public ImmutableList GetFavorites() + { + List favorites = new List(); + foreach (Recipe recipe in db.ListAll()) + { + if (ratings.TryGetValue(recipe.Info.Id, out AccountRecipeRate? rate)) + { + if (rate.IsFavorite) + favorites.Add(recipe.Info); + } + } + return favorites.ToImmutableList(); + } + + public ImmutableList<(RecipeInfo, uint)> GetWeeklyList() + { + List<(RecipeInfo, uint)> weekly = new List<(RecipeInfo, uint)>(); + foreach (Recipe recipe in db.ListAll()) + { + if (this.weekly.TryGetValue(recipe.Info.Id, out uint personAmmount)) + { + weekly.Add((recipe.Info, personAmmount)); + } + } + return weekly.ToImmutableList(); + } + + + public AccountRecipeRate GetRate(RecipeInfo info) + { + AccountRecipeRate rate = null; + if (!ratings.TryGetValue(info.Id, out rate)) + { + rate = new AccountRecipeRate(); + ratings.Add(info.Id, rate); + } + return rate; + } + + public void AddToFavorites(RecipeInfo info) + { + AccountRecipeRate rate = GetRate(info); + ratings[info.Id] = new AccountRecipeRate(true, rate.Rate); + } + + public void RemoveFromFavorites(RecipeInfo info) + { + AccountRecipeRate rate = GetRate(info); + ratings[info.Id] = new AccountRecipeRate(false, rate.Rate); + } + + public void SetReviewScore(RecipeInfo info, uint score) + { + AccountRecipeRate rate = GetRate(info); + ratings[info.Id] = new AccountRecipeRate(rate.IsFavorite, score); + } + } +} diff --git a/LocalEndpoint/ConnectionManager.cs b/LocalEndpoint/ConnectionManager.cs new file mode 100644 index 0000000..427814e --- /dev/null +++ b/LocalEndpoint/ConnectionManager.cs @@ -0,0 +1,33 @@ +using Models; +using Endpoint; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LocalEndpoint +{ + internal class ConnectionManager : IAccountManager + { + private Account userAccount = Constants.MAIN_USER_ACCOUNT; + private string userPassword = Constants.MAIN_USER_PASSWORD; + public Account? Login(string email, string password) + { + if (Constants.MAIN_USER_ACCOUNT.Email == email && Constants.MAIN_USER_PASSWORD == password) + return Constants.MAIN_USER_ACCOUNT; + return null; + } + + + public Account? Register(string email, string username, string password) + { + if (email == null || username == null || password == null) + return null; + + userAccount = new Account(new User(Constants.DEFAULT_ACCOUNT_IMAGE, username), email); + userPassword = password; + return userAccount; + } + } +} diff --git a/LocalEndpoint/Constants.cs b/LocalEndpoint/Constants.cs new file mode 100644 index 0000000..249a016 --- /dev/null +++ b/LocalEndpoint/Constants.cs @@ -0,0 +1,20 @@ +using Models; + +namespace LocalEndpoint +{ + internal class Constants + { + + public static readonly Uri DEFAULT_ACCOUNT_IMAGE = new Uri("https://www.pngkey.com/png/full/115-1150152_default-profile-picture-avatar-png-green.png"); + + // User account for tests + public static readonly Account MAIN_USER_ACCOUNT = new Account(new User(DEFAULT_ACCOUNT_IMAGE, "Example Account"), "test@example.com"); + public static readonly string MAIN_USER_PASSWORD = "123456"; + + // other user samples + public static readonly User USER1 = new User(new Uri("https://i.ibb.co/L6t6bGR/DALL-E-2023-05-10-20-27-31-cook-looking-at-the-camera-with-a-chef-s-hat-laughing-in-an-exaggerated-w.png"), "The Funny Chief"); + public static readonly User USER2 = new User(DEFAULT_ACCOUNT_IMAGE, "Yanis"); + public static readonly User USER3 = new User(DEFAULT_ACCOUNT_IMAGE, "Leo"); + + } +} diff --git a/LocalEndpoint/LocalEndpoint.cs b/LocalEndpoint/LocalEndpoint.cs index dd5a112..9b27f1e 100644 --- a/LocalEndpoint/LocalEndpoint.cs +++ b/LocalEndpoint/LocalEndpoint.cs @@ -1,11 +1,34 @@ using Endpoint; +using Models; +using System.Collections.Immutable; namespace LocalEndpoint { + + /// + /// The local endpoint is an implementation of the Endpoint API definition. + /// + /// public class LocalEndpoint : IEndpoint { - private IAccountManager accountManager = new AccountManager(); - private IRecipesService recipesService = new RecipesService(); + private readonly IAccountManager accountManager = new ConnectionManager(); + private readonly IRecipesService recipesService; + + + public LocalEndpoint() + { + RecipesDatabase db = new RecipesDatabase(); + + //miam + db.Insert(new Recipe(new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), Constants.USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.Insert(new Recipe(new RecipeInfo("Chocolate Cake", 2500, 10, new Uri("https://bakewithshivesh.com/wp-content/uploads/2022/08/IMG_0248-scaled.jpg"), 3, Guid.NewGuid()), Constants.USER2, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.Insert(new Recipe(new RecipeInfo("Salmon", 20, 10, new Uri("https://www.wholesomeyum.com/wp-content/uploads/2021/06/wholesomeyum-Pan-Seared-Salmon-Recipe-13.jpg"), 4, Guid.NewGuid()), Constants.MAIN_USER_ACCOUNT.User, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.Insert(new Recipe(new RecipeInfo("Fish", 50, 30, new Uri("https://www.ciaanet.org/wp-content/uploads/2022/07/Atlantic-and-Pacific-whole-salmon-1024x683.jpg"), 4.5F, Guid.NewGuid()), Constants.MAIN_USER_ACCOUNT.User, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.Insert(new Recipe(new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), Constants.USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + + recipesService = new RecipesService(db); + } + public IAccountManager AccountManager => accountManager; public IRecipesService RecipesService => recipesService; diff --git a/LocalEndpoint/RecipesDatabase.cs b/LocalEndpoint/RecipesDatabase.cs new file mode 100644 index 0000000..511cd80 --- /dev/null +++ b/LocalEndpoint/RecipesDatabase.cs @@ -0,0 +1,43 @@ +using Models; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace LocalEndpoint +{ + + //Simple class to simulate a recipe database + internal class RecipesDatabase + { + + private Dictionary recipes = new Dictionary(); + + public Recipe? Lookup(Guid id) + { + Recipe? recipe; + recipes.TryGetValue(id, out recipe); + return recipe; + } + + + public Recipe Get(Guid id) + { + return recipes[id]; + } + + public void Insert(Recipe recipe) + { + recipes[recipe.Info.Id] = recipe; + } + + public void Remove(Guid id) + { + recipes.Remove(id); + } + + public ImmutableList ListAll() + { + return recipes.Values.ToImmutableList(); + } + + } +} diff --git a/LocalEndpoint/RecipesService.cs b/LocalEndpoint/RecipesService.cs index 37f6c8e..9684e02 100644 --- a/LocalEndpoint/RecipesService.cs +++ b/LocalEndpoint/RecipesService.cs @@ -7,41 +7,49 @@ namespace LocalEndpoint internal class RecipesService : IRecipesService { - private readonly Dictionary accountsRecipes = new Dictionary(); + private readonly RecipesDatabase db; + private readonly Dictionary accountsData = new Dictionary(); - public List PopularRecipes() + public RecipesService(RecipesDatabase db) { - return new List { - new RecipeInfo("Chicken Curry", 500, 45, new Uri("https://cdn.chefclub.tools/uploads/recipes/cover-thumbnail/f287b191-dc8e-4c85-bbb6-e26387c354d3.jpg"), 3, Guid.NewGuid()), - new RecipeInfo("Spaghetti Bolognese", 1000, 30, new Uri("https://media.istockphoto.com/id/1144823591/fr/photo/spaghetti-dans-un-plat-sur-un-fond-blanc.jpg?s=612x612&w=0&k=20&c=qFzd8iE185mpsX7hWqYaieOWlzJVCkzFdYsxmwUT3-Q="), 1, Guid.NewGuid()), - new RecipeInfo("Beef Stroganoff", 100, 10, new Uri("https://www.cookwithnabeela.com/wp-content/uploads/2023/02/BeefStroganoff.webp"), 5, Guid.NewGuid()), - new RecipeInfo("Fish And Ships", 450, 15, new Uri("https://upload.wikimedia.org/wikipedia/commons/f/ff/Fish_and_chips_blackpool.jpg"), 4, Guid.NewGuid()), - new RecipeInfo("Caesar Salad", 150, 20, new Uri("https://www.galbani.fr/wp-content/uploads/2020/04/AdobeStock_157570276-2.jpeg"), 1, Guid.NewGuid()) - }; + this.db = db; + } + + public ImmutableList PopularRecipes() + { + return db.ListAll().Take(4).ToImmutableList().ConvertAll(v => v.Info); } public Recipe GetRecipe(RecipeInfo info) { - User owner = new User(new Uri("https://i.ibb.co/L6t6bGR/DALL-E-2023-05-10-20-27-31-cook-looking-at-the-camera-with-a-chef-s-hat-laughing-in-an-exaggerated-w.png"), "The Funny Chief"); - var ingredients = new List { new Ingredient("Banana", 12), new Ingredient("Apple", 2) }.ToImmutableList(); - var steps = new List { new PreparationStep("Step 1", "This step is an hardcoded step from a stub implementation of IRecipesSeervice") }.ToImmutableList(); - return new Recipe(info, owner, ingredients, steps); + return db.Get(info.Id); } - public IAccountRecipes GetRecipesOf(Account account) + public IAccountOwnedRecipes GetRecipesOf(Account account) + { + return GetOrInitData(account).Recipes; + } + public IAccountRecipesPreferences GetPreferencesOf(Account account) { - IAccountRecipes? recipes; - accountsRecipes.TryGetValue(account, out recipes); + return GetOrInitData(account).Preferences; + } + + private AccountData GetOrInitData(Account account) + { + AccountData? data; + accountsData.TryGetValue(account, out data); - if (recipes == null) { - recipes = new AccountRecipes(account); + if (data == null) + { + AccountOwnedRecipes recipes = new AccountOwnedRecipes(account, db); recipes.UploadRecipe(new Recipe(new RecipeInfo("Cupcake", 500, 12, new Uri("https://www.mycake.fr/wp-content/uploads/2015/12/rs_cupcake_4x3.jpg"), 4.2F, Guid.NewGuid()), account.User, new List { new Ingredient("Chocolate", 4) }.ToImmutableList(), new List { new PreparationStep("Eat Chocolate", "Eat the chocolate") }.ToImmutableList())); - accountsRecipes.Add(account, recipes); + AccountRecipesPreferences preferences = new AccountRecipesPreferences(account, db); + data = new AccountData(recipes, preferences); + accountsData.Add(account, data); } - return recipes; + return data; } - } } diff --git a/MainAppShell.xaml.cs b/MainAppShell.xaml.cs index decb72a..d3f6bc1 100644 --- a/MainAppShell.xaml.cs +++ b/MainAppShell.xaml.cs @@ -9,9 +9,9 @@ public partial class MainAppShell : Shell public MainAppShell(Account account, IEndpoint endpoint, IApp app) { InitializeComponent(); - HomeTab.ContentTemplate = new DataTemplate(() => new HomePage(account, endpoint)); - FavoritesTab.ContentTemplate = new DataTemplate(() => new FavoritesPage(account, endpoint.RecipesService)); - MyListTab.ContentTemplate = new DataTemplate(() => new MyListPage(account, endpoint.RecipesService)); + HomeTab.ContentTemplate = new DataTemplate(() => new HomePage(account, app.Notifier, endpoint)); + FavoritesTab.ContentTemplate = new DataTemplate(() => new FavoritesPage(account, app.Notifier, endpoint.RecipesService)); + MyListTab.ContentTemplate = new DataTemplate(() => new MyListPage(account, app.Notifier, endpoint.RecipesService)); MoreTab.ContentTemplate = new DataTemplate(() => new MorePage(account, new MorePageController(account, endpoint, app))); } } diff --git a/Models/AccountRecipeRate.cs b/Models/AccountRecipeRate.cs index c23fdf9..caf7658 100644 --- a/Models/AccountRecipeRate.cs +++ b/Models/AccountRecipeRate.cs @@ -1,5 +1,5 @@  namespace Models { - public record AccountRecipeRate(bool IsFavorite, uint Rate); + public record AccountRecipeRate(bool IsFavorite = false, uint Rate = 0); } diff --git a/Views/FavoritesPage.xaml b/Views/FavoritesPage.xaml index ca8b233..6f7bd4f 100644 --- a/Views/FavoritesPage.xaml +++ b/Views/FavoritesPage.xaml @@ -4,7 +4,8 @@ x:Class="ShoopNCook.Pages.FavoritesPage" Title="FavoritesPage" xmlns:views="clr-namespace:ShoopNCook.Views" - BackgroundColor="{StaticResource BackgroundPrimary}"> + BackgroundColor="{StaticResource BackgroundPrimary}" + NavigatedTo="ContentPage_NavigatedTo"> diff --git a/Views/FavoritesPage.xaml.cs b/Views/FavoritesPage.xaml.cs index ae667ed..8282f86 100644 --- a/Views/FavoritesPage.xaml.cs +++ b/Views/FavoritesPage.xaml.cs @@ -6,24 +6,41 @@ using Endpoint; using LocalEndpoint; using Models; using ShoopNCook.Views; +using System.Security.Principal; public partial class FavoritesPage : ContentPage { - public FavoritesPage(Account account, IRecipesService service) + + private readonly Account account; + private readonly IUserNotifier notifier; + private IRecipesService service; + + public FavoritesPage(Account account, IUserNotifier notifier, IRecipesService service) { InitializeComponent(); + this.account = account; + this.notifier = notifier; + this.service = service; + + UpdateFavorites(); + } - IAccountRecipes recipes = service.GetRecipesOf(account); - recipes.GetFavorites().ForEach(info => + private void UpdateFavorites() + { + IAccountRecipesPreferences preferences = service.GetPreferencesOf(account); + RecipeViewLayout.Children.Clear(); + preferences.GetFavorites().ForEach(info => { RecipeViewLayout.Children.Add(new RecipeView(info, () => { Recipe recipe = service.GetRecipe(info); - AccountRecipeRate? rate = recipes.FindRate(info); - Shell.Current.Navigation.PushAsync(new RecipePage(recipe, rate, 1)); + Shell.Current.Navigation.PushAsync(new RecipePage(recipe, notifier, preferences, 1)); })); }); + } + private void ContentPage_NavigatedTo(object sender, NavigatedToEventArgs e) + { + UpdateFavorites(); } - } \ No newline at end of file diff --git a/Views/HomePage.xaml.cs b/Views/HomePage.xaml.cs index 2082d1f..b74cfd2 100644 --- a/Views/HomePage.xaml.cs +++ b/Views/HomePage.xaml.cs @@ -7,12 +7,12 @@ using LocalEndpoint; public partial class HomePage : ContentPage { - public HomePage(Account account, IEndpoint endpoint) + public HomePage(Account account, IUserNotifier notifier, IEndpoint endpoint) { InitializeComponent(); IRecipesService service = endpoint.RecipesService; - IAccountRecipes recipes = service.GetRecipesOf(account); + IAccountRecipesPreferences preferences = service.GetPreferencesOf(account); //TODO this code can be factorised @@ -21,13 +21,12 @@ public partial class HomePage : ContentPage layout.Children.Add(new RecipeView(info, () => { Recipe recipe = service.GetRecipe(info); - AccountRecipeRate rate = recipes.FindRate(info); - Shell.Current.Navigation.PushAsync(new RecipePage(recipe, rate, 1)); + Shell.Current.Navigation.PushAsync(new RecipePage(recipe, notifier, preferences, 1)); })); } service.PopularRecipes().ForEach(recipe => PushRecipe(PopularsList, recipe)); - recipes.GetRecommendedRecipes().ForEach(recipe => PushRecipe(RecommendedList, recipe)); + preferences.GetRecommendedRecipes().ForEach(recipe => PushRecipe(RecommendedList, recipe)); ProfilePictureImage.Source = ImageSource.FromUri(account.User.ProfilePicture); ProfilePictureName.Text = account.User.Name; diff --git a/Views/MyListPage.xaml.cs b/Views/MyListPage.xaml.cs index f09d1c7..973dde1 100644 --- a/Views/MyListPage.xaml.cs +++ b/Views/MyListPage.xaml.cs @@ -7,19 +7,18 @@ namespace ShoopNCook.Pages; public partial class MyListPage : ContentPage { - public MyListPage(Account account, IRecipesService service) + public MyListPage(Account account, IUserNotifier notifier, IRecipesService service) { InitializeComponent(); - IAccountRecipes recipes = service.GetRecipesOf(account); - recipes.GetWeeklyList().ForEach(tuple => + IAccountRecipesPreferences preferences = service.GetPreferencesOf(account); + preferences.GetWeeklyList().ForEach(tuple => { RecipeInfo info = tuple.Item1; RecipesLayout.Children.Add(new StoredRecipeView(info, tuple.Item2, amount => { Recipe recipe = service.GetRecipe(info); - AccountRecipeRate? rate = recipes.FindRate(info); - Shell.Current.Navigation.PushAsync(new RecipePage(recipe, rate, amount)); + Shell.Current.Navigation.PushAsync(new RecipePage(recipe, notifier, preferences, amount)); })); }); diff --git a/Views/MyRecipesPage.xaml.cs b/Views/MyRecipesPage.xaml.cs index 1754c71..952d786 100644 --- a/Views/MyRecipesPage.xaml.cs +++ b/Views/MyRecipesPage.xaml.cs @@ -10,7 +10,7 @@ public partial class MyRecipesPage : ContentPage private IUserNotifier notifier; private IRecipesService service; - private IAccountRecipes recipes; + private Account account; public MyRecipesPage( Account account, @@ -21,9 +21,12 @@ public partial class MyRecipesPage : ContentPage this.notifier = notifier; this.service = service; - this.recipes = service.GetRecipesOf(account); - - recipes.GetAccountRecipes().ForEach(AddRecipeView); + this.account = account; + + service + .GetRecipesOf(account) + .GetAccountRecipes() + .ForEach(AddRecipeView); } private void AddRecipeView(RecipeInfo info) @@ -31,8 +34,8 @@ public partial class MyRecipesPage : ContentPage RecipesLayout.Children.Add(new OwnedRecipeView(info, () => { Recipe recipe = service.GetRecipe(info); - AccountRecipeRate? rate = recipes.FindRate(info); - Shell.Current.Navigation.PushAsync(new RecipePage(recipe, rate, 1)); + IAccountRecipesPreferences preferences = service.GetPreferencesOf(account); + Shell.Current.Navigation.PushAsync(new RecipePage(recipe, notifier, preferences, 1)); }, () => RemoveRecipe(info) )); @@ -40,6 +43,8 @@ public partial class MyRecipesPage : ContentPage private void RemoveRecipe(RecipeInfo info) { + IAccountOwnedRecipes recipes = service.GetRecipesOf(account); + if (!recipes.RemoveRecipe(info)) { notifier.Error("Could not remove recipe"); @@ -62,7 +67,9 @@ public partial class MyRecipesPage : ContentPage } private void OnAddRecipeButtonClicked(object sender, EventArgs e) { - var page = new CreateRecipePage(recipes.Account.User, notifier, recipe => + IAccountOwnedRecipes recipes = service.GetRecipesOf(account); + + var page = new CreateRecipePage(account.User, notifier, recipe => { if (!recipes.UploadRecipe(recipe)) { diff --git a/Views/RecipePage.xaml b/Views/RecipePage.xaml index 32679e9..dbb8080 100644 --- a/Views/RecipePage.xaml +++ b/Views/RecipePage.xaml @@ -8,7 +8,6 @@ BackgroundColor="{StaticResource BackgroundPrimary}"> @@ -51,7 +50,8 @@ StrokeShape="RoundRectangle 20" BackgroundColor="{StaticResource ImageBackground}"> + HeightRequest="250" + x:Name="RecipeImage"/> @@ -146,7 +146,8 @@ BackgroundColor="{StaticResource Selected}" VerticalOptions="Center" HorizontalOptions="Center" - Text="Submit"/> + Text="Submit" + Clicked="OnSubmitReviewClicked"/> diff --git a/Views/RecipePage.xaml.cs b/Views/RecipePage.xaml.cs index e0df08b..5e650cb 100644 --- a/Views/RecipePage.xaml.cs +++ b/Views/RecipePage.xaml.cs @@ -1,6 +1,9 @@ using ShoopNCook.Views; using System.Windows.Input; using Models; +using LocalEndpoint; +using Endpoint; + namespace ShoopNCook.Pages; public partial class RecipePage : ContentPage @@ -9,27 +12,39 @@ public partial class RecipePage : ContentPage private uint note; private bool isFavorite; - public ICommand StarCommand => new Command(count => SetNote(uint.Parse(count))); + private IAccountRecipesPreferences preferences; + private IUserNotifier notifier; + private RecipeInfo info; + + public ICommand StarCommand => new Command(count => SetNote(uint.Parse(count))); - public RecipePage(Recipe recipe, AccountRecipeRate? rate, uint amount) + public RecipePage(Recipe recipe, IUserNotifier notifier, IAccountRecipesPreferences preferences, uint amount) { InitializeComponent(); - Counter.Count = amount; + this.preferences = preferences; + this.notifier = notifier; + this.info = recipe.Info; + + AccountRecipeRate rate = preferences.GetRate(recipe.Info); - note = rate?.Rate ?? 0; - isFavorite = rate?.IsFavorite ?? false; + note = rate.Rate; + isFavorite = rate.IsFavorite; SetFavorite(isFavorite); SetNote(note); RecipeInfo info = recipe.Info; + Counter.Count = amount; CookTime.Text = info.CookTimeMins.ToString(); Energy.Text = info.CalPerPers.ToString() + " cal/pers"; RecipeName.Text = info.Name; + if (info.Image != null) + RecipeImage.Source = ImageSource.FromUri(info.Image); + foreach (Ingredient ingredient in recipe.Ingredients) IngredientList.Add(new IngredientView(ingredient)); @@ -58,9 +73,7 @@ public partial class RecipePage : ContentPage i++; } else - { img.Source = ImageSource.FromFile("star_empty.svg"); - } } } @@ -69,21 +82,30 @@ public partial class RecipePage : ContentPage SetFavorite(!isFavorite); } + private void OnSubmitReviewClicked(object o, EventArgs e) + { + preferences.SetReviewScore(info, note); + notifier.Success("Your review has been successfuly submited"); + } + private void SetFavorite(bool isFavorite) { this.isFavorite = isFavorite; if (isFavorite) { Favorite.Source = ImageSource.FromFile("hearth_on.svg"); + preferences.AddToFavorites(info); } else { Favorite.Source = ImageSource.FromFile("hearth_off.svg"); + preferences.RemoveFromFavorites(info); } } - private async void OnBackButtonClicked(object sender, EventArgs e) + private void OnBackButtonClicked(object sender, EventArgs e) { - await Navigation.PopAsync(); + + Navigation.PopAsync(); } } \ No newline at end of file