fixed merge
continuous-integration/drone/push Build was killed Details

pull/65/head
Roxane ROSSETTO 2 years ago
commit 907eb84ba0

@ -85,7 +85,7 @@ steps:
- name: docker-image-console-app - name: docker-image-console-app
image: plugins/docker image: plugins/docker
settings: settings:
dockerfile: MCTG/Dockerfile dockerfile: MCTG/ConsoleApp/Dockerfile
context: MCTG/ context: MCTG/
registry: hub.codefirst.iut.uca.fr registry: hub.codefirst.iut.uca.fr
repo: hub.codefirst.iut.uca.fr/alexandre.agostinho/console-mctg repo: hub.codefirst.iut.uca.fr/alexandre.agostinho/console-mctg

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppException
{
public class NoRecipeSelectedException : RecipeException
{
public NoRecipeSelectedException() : base("No recipe is currently selected to perform this action.") { }
}
}

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace AppException
{
public class RecipeException : Exception
{
public RecipeException() : base("Something went wrong with a recipe or a collection of recipe.") { }
public RecipeException(string message) : base(message) { }
}
}

@ -0,0 +1,9 @@

namespace AppException
{
public class RecipeNotFoundException : RecipeException
{
public RecipeNotFoundException() : base("Recipe not found.") { }
public RecipeNotFoundException(int id) : base($"Recipe id: '{id}'not found.") { }
}
}

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppException
{
public class BadMailFormatException : UserException
{
public BadMailFormatException() : base("Invalid mail format.") { }
public BadMailFormatException(string mail) : base($"'{mail}' is an invalid format.") { }
}
}

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppException
{
public class NoUserConnectedException : UserException
{
public NoUserConnectedException() : base("No user is currently connected.") { }
}
}

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppException
{
public class UserAlreadyConnectedException : UserException
{
public UserAlreadyConnectedException() : base("An user is already connected.") { }
}
}

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppException
{
public class UserException : Exception
{
public UserException() : base("Somthing went wrong with an User.") { }
public UserException(string message) : base(message) { }
}
}

@ -0,0 +1,8 @@
namespace AppException
{
public class UserNotFoundException : UserException
{
public UserNotFoundException() : base("User not found.") { }
public UserNotFoundException(string userMail) : base($"User with mail: '{userMail}' not found.") { }
}
}

@ -3,7 +3,11 @@
"path": "SAE-2.01.sln", "path": "SAE-2.01.sln",
"projects": [ "projects": [
"ConsoleApp\\ConsoleApp.csproj", "ConsoleApp\\ConsoleApp.csproj",
"AppException\\AppException.csproj",
"Managers\\Managers.csproj",
"Model\\Model.csproj", "Model\\Model.csproj",
"Persistance\\DataPersistence\\DataPersistence.csproj",
"Persistance\\FakePersistance\\FakePersistance.csproj",
"Tests\\Model_UnitTests\\Model_UnitTests.csproj" "Tests\\Model_UnitTests\\Model_UnitTests.csproj"
] ]
} }

@ -7,9 +7,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\DataPersistence\DataPersistence.csproj" /> <ProjectReference Include="..\Managers\Managers.csproj" />
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\Persistance\DataPersistence\DataPersistence.csproj" />
<ProjectReference Include="..\Persistance\FakePersistance\FakePersistance.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -1,11 +1,5 @@
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model; using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -40,14 +34,15 @@ namespace ConsoleApp.Menu
Recipe recipe = new Recipe( Recipe recipe = new Recipe(
title: title, title: title,
type: RecipeType.Unspecified, type: RecipeType.Unspecified,
priority: Priority.Fast,
id: null, id: null,
authorMail: masterMgr.CurrentConnectedUser?.Mail, authorMail: masterMgr.User.CurrentConnected?.Mail,
picture: null) picture: null)
{ {
PreparationSteps = steps PreparationSteps = steps
}; };
masterMgr.AddRecipe(recipe); masterMgr.Recipe.AddRecipeToData(recipe);
return null; return null;
} }
} }

@ -1,11 +1,5 @@
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model; using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -30,14 +24,9 @@ namespace ConsoleApp.Menu
string surname = _selectList[2].Item.Input; string surname = _selectList[2].Item.Input;
string passwd = _selectList[3].Item.Input; string passwd = _selectList[3].Item.Input;
User user = new User( User user = masterMgr.User.CreateUser(mail, passwd, name, surname);
name: name,
surname: surname,
mail: mail,
password: passwd
);
masterMgr.Register(user); masterMgr.User.AddUserToData(user);
return null; return null;
} }
} }

@ -1,10 +1,5 @@
using System; using ConsoleApp.Menu.Core;
using System.Collections.Generic; using Model;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp.Menu.Core;
using Model.Managers;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -38,7 +33,7 @@ namespace ConsoleApp.Menu
string mail = _selectList[0].Item.Input; string mail = _selectList[0].Item.Input;
string password = _selectList[1].Item.Input; string password = _selectList[1].Item.Input;
if (!_masterMgr.Login(mail, password)) if (!_masterMgr.User.LogIn(mail, password))
{ {
_wrongInput = true; _wrongInput = true;
return this; return this;

@ -1,12 +1,5 @@
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model.Managers;
using Model; using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataPersistence;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -36,7 +29,7 @@ namespace ConsoleApp.Menu
try try
{ {
_masterMgr.DataMgr.Export(recipe, path); _masterMgr.Data.Export(recipe, path);
} }
catch (ArgumentNullException e) catch (ArgumentNullException e)
{ {

@ -1,11 +1,5 @@
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model; using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -25,7 +19,7 @@ namespace ConsoleApp.Menu
string path = _selectList[0].Item.Input; string path = _selectList[0].Item.Input;
try try
{ {
masterMgr.DataMgr.Import<Recipe>(path); masterMgr.Data.Import<Recipe>(path);
} }
catch(ArgumentNullException e) catch(ArgumentNullException e)
{ {

@ -1,10 +1,5 @@
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model.Managers; using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -20,7 +15,7 @@ namespace ConsoleApp.Menu
public override IMenu? Return() public override IMenu? Return()
{ {
_masterMgr.Logout(); _masterMgr.User.LogOut();
return base.Return(); return base.Return();
} }
} }

@ -1,12 +1,5 @@
using Model; using Model;
using DataPersistence;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model.Managers;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -47,7 +40,7 @@ namespace ConsoleApp.Menu
{ {
List<Selector<IMenu>> selectors = base.SearchInSelection(); List<Selector<IMenu>> selectors = base.SearchInSelection();
if (_masterMgr.CurrentConnectedUser == null) if (_masterMgr.User.CurrentConnected == null)
return selectors.Except(selectors.Where(s => s.Line == "User profile")) return selectors.Except(selectors.Where(s => s.Line == "User profile"))
.Except(selectors.Where(s => s.Line == "Logout")) .Except(selectors.Where(s => s.Line == "Logout"))
.Except(selectors.Where(s => s.Line == "Add recipe")).ToList(); .Except(selectors.Where(s => s.Line == "Add recipe")).ToList();

@ -1,11 +1,5 @@
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model.Managers;
using Model; using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {

@ -1,10 +1,4 @@
using Model; using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -16,7 +10,10 @@ namespace ConsoleApp.Menu
public override void Update() public override void Update()
{ {
_recipeCollectionOnSearch = _masterMgr.GetCurrentUserRecipes(); if (_masterMgr.User.CurrentConnected is null)
throw new ArgumentNullException();
_recipeCollectionOnSearch = _masterMgr.Recipe.GetRecipeByAuthor(_masterMgr.User.CurrentConnected.Mail);
_allSelectors = ConvertRecipeCollectionInSelectors(); _allSelectors = ConvertRecipeCollectionInSelectors();
_selectList = SearchInSelection(); _selectList = SearchInSelection();

@ -1,12 +1,5 @@
using System; using ConsoleApp.Menu.Core;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp.Menu.Core;
using Model; using Model;
using Model.Managers;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -36,7 +29,7 @@ namespace ConsoleApp.Menu
public override void Update() public override void Update()
{ {
_recipeCollectionOnSearch = _masterMgr.DataMgr.GetRecipes("all recipes"); _recipeCollectionOnSearch = _masterMgr.Recipe.GetAllRecipes();
_allSelectors = ConvertRecipeCollectionInSelectors(); _allSelectors = ConvertRecipeCollectionInSelectors();
base.Update(); base.Update();
} }
@ -46,7 +39,7 @@ namespace ConsoleApp.Menu
if (CurrentSelected == null) if (CurrentSelected == null)
return this; return this;
return new PlainText(CurrentSelected.ToString()); return new ShowRecipeInfos(CurrentSelected);
} }
#endregion #endregion
} }

@ -0,0 +1,37 @@
using ConsoleApp.Menu.Core;
using Model;
using System.Text;
namespace ConsoleApp.Menu
{
internal class ShowRecipeInfos : PlainText
{
public Recipe Recipe { get; private set; }
public ShowRecipeInfos(Recipe recipe)
: base("")
{
Recipe = recipe;
}
public override void Display()
{
StringBuilder sb = new StringBuilder($"[Recipe n°{Recipe.Id}] - {Recipe.Title}\n");
foreach (PreparationStep ps in Recipe.PreparationSteps)
{
sb.AppendFormat("\t* {0}\n", ps.ToString());
}
sb.AppendLine();
sb.AppendLine(Recipe.ConcatIngredients());
sb.AppendLine();
foreach (Review review in Recipe.Reviews)
{
sb.AppendLine(review.ToString());
}
sb.AppendLine();
sb.AppendLine($"Posted by: {Recipe.AuthorMail?.ToString()}");
Console.WriteLine(sb);
}
}
}

@ -1,11 +1,5 @@
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model; using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -22,10 +16,10 @@ namespace ConsoleApp.Menu
public override void Display() public override void Display()
{ {
Console.WriteLine( Console.WriteLine(
$"\nUser: {_masterMgr.CurrentConnectedUser}\n\n" $"\nUser: {_masterMgr.User.CurrentConnected}\n\n"
+ $"\tMail: {_masterMgr.CurrentConnectedUser?.Mail}\n" + $"\tMail: {_masterMgr.User.CurrentConnected?.Mail}\n"
+ $"\tName: {_masterMgr.CurrentConnectedUser?.Name}\n" + $"\tName: {_masterMgr.User.CurrentConnected?.Name}\n"
+ $"\tSurname: {_masterMgr.CurrentConnectedUser?.Surname}\n"); + $"\tSurname: {_masterMgr.User.CurrentConnected?.Surname}\n");
} }
} }
} }

@ -1,13 +1,7 @@
using ConsoleApp.Menu; using ConsoleApp.Menu;
using Model; using Model;
using DataPersistence; using DataPersistence;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp.Menu.Core; using ConsoleApp.Menu.Core;
using Model.Managers;
namespace ConsoleApp namespace ConsoleApp
{ {
@ -37,7 +31,6 @@ namespace ConsoleApp
public MenuManager(MasterManager masterManager, IMenu firstMenu) public MenuManager(MasterManager masterManager, IMenu firstMenu)
{ {
MasterMgr = masterManager; MasterMgr = masterManager;
MenuCallStack = new Stack<IMenu>(); MenuCallStack = new Stack<IMenu>();
MenuCallStack.Push(firstMenu); MenuCallStack.Push(firstMenu);
} }

@ -1,31 +1,52 @@
using ConsoleApp; using ConsoleApp;
using Model; using Model;
using DataPersistence; using DataPersistence;
using Model.Managers; using FakePersistance;
using Managers;
Console.WriteLine("Hello, World!\n\n");
string path = ""; // - path to the save file namespace ConsoleApp;
string strategy = "xml"; // - strategy is 'xml' or 'json' (/!\ this is case sensitive)
MasterManager masterMgr; public static class Program
IDataManager dataManager = (strategy == "xml") ?
new DataContractXML(path)
: new DataContractJSON(path);
if (!File.Exists(Path.Combine(path, $"data.{strategy}")))
{
masterMgr = new MasterManager(new Stubs());
masterMgr.DataMgr.Serializer = dataManager;
}
else
{ {
masterMgr = new MasterManager(dataManager); public static void Main(string[] args)
} {
Console.WriteLine("Hello, World!\n\n");
string path = ""; // - path to the save file
string strategy = "xml"; // - strategy is 'xml' or 'json' (/!\ this is case sensitive)
// Initialize the data serializer
IDataSerializer dataSerializer = (strategy == "xml") ?
new DataContractXML(path)
: new DataContractJSON(path);
MenuManager menuMgr = new MenuManager(masterMgr); // Initialize the data manager
menuMgr.Loop(); IDataManager dataManager = (!File.Exists(Path.Combine(path, $"data.{strategy}"))) ?
new DataDefaultManager(new Stubs())
: new DataDefaultManager(dataSerializer);
// Save data. // Initialize the other managers
Console.Write("[ --SAVE-- ]:\t"); masterMgr.DataMgr.Save(); Console.WriteLine("Done."); IRecipeManager recipeManager = new RecipeDefaultManager(dataManager);
IPasswordManager passwordManager = new PasswordSHA256Manager();
IUserManager userManager = new UserDefaultManager(dataManager, passwordManager);
// Initialize the master manager
MasterManager Master = new MasterManager(dataManager, recipeManager, userManager);
Master.Setup();
MenuManager menuMgr = new MenuManager(Master);
menuMgr.Loop();
// Change the data serializer if the one in place is 'Stubs'
if (Master.Data.Serializer.GetType() == typeof(Stubs))
{
var data = Master.Data.Data;
dataManager = new DataDefaultManager(dataSerializer, data);
Master = new MasterManager(dataManager, recipeManager, userManager);
}
// Save data.
Console.Write("[ --SAVE-- ]:\t"); Master.Data.SaveData(); Console.WriteLine("Done.");
}
}

@ -0,0 +1,56 @@
using Model;
namespace Managers
{
/// <summary>
/// Define the manager of the data. This is where all the data are put, and where we call the loading and the saving of them.
/// </summary>
public class DataDefaultManager : IDataManager
{
#region Attributes & Properties
public IDataSerializer Serializer { get; set; }
public Dictionary<string, List<object>> Data { get; private set; }
#endregion
#region Constructors
/// <summary>
/// Constructor of the DataDefaultManager class. Take a IDataManager that will provide methods for the serialisation of the data.
/// </summary>
/// <param name="dataManager">The data manager that know how to serialize a file.</param>
/// <param name="data">The data set of the application.</param>
public DataDefaultManager(IDataSerializer dataManager,
Dictionary<string, List<object>>? data = null)
{
Serializer = dataManager;
if (data is null)
Data = new Dictionary<string, List<object>>();
else
Data = data;
}
#endregion
#region Methods
public void LoadData()
=> Data = Serializer.Load();
public void SaveData()
=> Serializer.Save(Data);
public void Import<T>(string pathOfTheFile)
where T : class
{
KeyValuePair<string, T> import = Serializer.Import<T>(pathOfTheFile);
Data[import.Key].Add(import.Value);
}
public void Export<T>(T obj, string pathToExport)
where T : class
=> Serializer.Export<T>(obj, pathToExport);
public ICollection<T> GetFromData<T>() where T : class
=> new List<T>(Data[typeof(T).Name].Cast<T>());
#endregion
}
}

@ -1,16 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings>
<ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable>
<Nullable>enable</Nullable> </PropertyGroup>
<Configurations>Debug;Release;CI</Configurations>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\DataPersistence\DataPersistence.csproj" /> <ProjectReference Include="..\AppException\AppException.csproj" />
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace Model namespace Model
{ {
[DataContract(Name = "passmgr")] [DataContract(Name = "passmgr")]
public class PasswordSHA256 : IPasswordManager public class PasswordSHA256Manager : IPasswordManager
{ {
public string HashPassword(string password) public string HashPassword(string password)
{ {

@ -0,0 +1,112 @@
using AppException;
using Model;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Managers
{
public class RecipeDefaultManager : IRecipeManager
{
private IDataManager _dataManager;
public Recipe? CurrentSelected { get; set; } = null;
public RecipeDefaultManager(IDataManager dataManager)
{
_dataManager = dataManager;
}
public bool AddRecipeToData(Recipe recipe)
{
var recipeList = _dataManager.Data[nameof(Recipe)];
if (recipeList.Exists(r => r.Equals(recipe)))
return false;
_dataManager.Data[nameof(Recipe)].Add(recipe);
return true;
}
public RecipeCollection GetAllRecipes()
{
return new RecipeCollection(
"All recipes",
_dataManager.GetFromData<Recipe>().ToArray());
}
public RecipeCollection GetRecipeByAuthor(string authorMail)
{
User? author = _dataManager.GetFromData<User>()
.ToList()
.Find(u => u.Mail == authorMail);
if (author is null)
throw new UserNotFoundException(authorMail);
IEnumerable<Recipe> recipes = from Recipe r in _dataManager.GetFromData<Recipe>()
where r.AuthorMail == author.Mail
select r;
return new RecipeCollection(
$"{author.Name} {author.Surname}'s recipes", recipes.ToArray());
}
public RecipeCollection SearchRecipeByTitle(string title)
{
IEnumerable<Recipe> recipes = from Recipe recipe in _dataManager.GetFromData<Recipe>()
where recipe.Title.Contains(title)
select recipe;
return new RecipeCollection(
$"Search for '{title}'", recipes.ToArray());
}
public Recipe GetRecipeFromId(int id)
{
Recipe? recipe = _dataManager.GetFromData<Recipe>()
.ToList()
.Find(r => r.Id == id);
if (recipe is null)
throw new RecipeNotFoundException();
return recipe;
}
public RecipeCollection GetRecipesByPriorityOrder(IEnumerable<Priority> priorities)
{
List<Recipe> recipes = new List<Recipe>();
IEnumerable<Recipe> recipesWithCurrentPriority;
foreach (Priority priority in priorities)
{
recipesWithCurrentPriority = from Recipe recipe in _dataManager.GetFromData<Recipe>()
where recipe.Priority == priority
select recipe;
recipes.AddRange(recipesWithCurrentPriority);
}
return new RecipeCollection(
$"Suggestions", recipes.ToArray());
}
public bool ModifyCurrentSelected(Recipe newRecipe)
{
if (CurrentSelected is null)
throw new NoRecipeSelectedException();
try
{
var index = _dataManager.GetFromData<Recipe>().ToList()
.FindIndex(u => u.Equals(CurrentSelected));
_dataManager.Data[nameof(Recipe)][index] = newRecipe;
}
catch (ArgumentNullException e)
{
Debug.WriteLine("Recipe to modify not found.");
return false;
}
return true;
}
}
}

@ -0,0 +1,149 @@
using AppException;
using Model;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Managers
{
public class UserDefaultManager : IUserManager, INotifyPropertyChanging
{
private IDataManager _dataManager;
private IPasswordManager _passwordManager;
private User? _currentConnected = null;
public UserDefaultManager(IDataManager dataManager, IPasswordManager passwordManager)
{
_dataManager = dataManager;
_passwordManager = passwordManager;
}
public User? CurrentConnected
{
get => _currentConnected;
private set
{
_currentConnected = value;
OnPropertyChanged();
}
}
public IPasswordManager PasswordManager => _passwordManager;
public event PropertyChangingEventHandler? PropertyChanging;
public void OnPropertyChanged([CallerMemberName] string pname = "")
=> PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(pname));
public bool AddUserToData(User user)
{
var userList = _dataManager.Data[nameof(User)];
if (userList.Exists(r => r.Equals(user)))
return false;
_dataManager.Data[nameof(User)].Add(user);
return true;
}
public User CreateUser(string mail, string password,
string? name = null, string? surname = null, string? profilePict = null)
{
if (name is null) name = $"user{GetRandomInt()}";
if (surname is null) surname = "";
if (profilePict is null) profilePict = "default_user_picture.png";
const string mailRegex = @"^([\w\.-]+)@([\w\.-]+\.\w+)$";
if (!Regex.Match(mail, mailRegex).Success)
throw new BadMailFormatException();
string hashedPassword = PasswordManager.HashPassword(password);
return new User(name, surname, mail, hashedPassword, profilePict);
}
public ICollection<User> GetAllUsers()
{
return _dataManager.GetFromData<User>();
}
public User GetUserFromMail(string mail)
{
User? user = _dataManager.GetFromData<User>().ToList()
.Find(u => u.Mail == mail);
if (user is null)
throw new UserNotFoundException();
return user;
}
public bool LogIn(string mail, string password)
{
if (CurrentConnected is not null)
throw new UserAlreadyConnectedException();
#if DEBUG
if (mail == "admin")
{
CurrentConnected = _dataManager.GetFromData<User>()
.FirstOrDefault(u => u.Mail == "admin@mctg.fr");
return true;
}
#endif
User? user = _dataManager.GetFromData<User>().ToList()
.Find(u => u.Mail == mail);
if (user is null)
return false;
if (!_passwordManager.VerifyPassword(user.Password, password))
return false;
CurrentConnected = user;
return true;
}
public void LogOut()
{
if (CurrentConnected is null)
throw new NoUserConnectedException();
CurrentConnected = null;
}
public bool ModifyCurrentConnected(User newUser)
{
try
{
var index = _dataManager.GetFromData<User>().ToList()
.FindIndex(u => u.Equals(_currentConnected));
_dataManager.Data[nameof(User)][index] = newUser;
}
catch (ArgumentNullException e)
{
Debug.WriteLine("User to modify not found.");
return false;
}
return true;
}
private int GetRandomInt()
{
var randomGenerator = RandomNumberGenerator.Create();
byte[] data = new byte[16];
randomGenerator.GetBytes(data);
return Math.Abs(BitConverter.ToInt16(data));
}
}
}

@ -1,105 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
/// <summary>
/// Define the manager of the data. This is where all the data are put, and where we call the loading and the saving of them.
/// </summary>
public class DataManager
{
#region Attributes & Properties
/// <summary>
/// The data manager injected that know how to serialize the data.
/// <br/><remarks><i>The setter is actually public for testing purpose. It will be private after.</i></remarks>
/// <br/>See: <see cref="IDataManager"/>
/// </summary>
public IDataManager Serializer { get; set; }
/// <summary>
/// The collection of all data. Each line of this dictionary has the type of the data as it key and the data for values.
/// </summary>
public Dictionary<string, List<object>> Data { get; private set; }
#endregion
#region Constructors
/// <summary>
/// Constructor of the DataManager class. Take a IDataManager that will provide methods for the serialisation of the data.
/// </summary>
/// <param name="dataMgr">The data manager that know how to serialize a file.</param>
public DataManager(IDataManager dataMgr)
{
Serializer = dataMgr;
Data = Serializer.Load();
}
#endregion
#region Methods
/// <summary>
/// Reload the data. Useful to update new data written in the save file.
/// <br/>See: <see cref="IDataManager.Load"/>
/// </summary>
public void Reload()
=> Data = Serializer.Load();
/// <summary>
/// Save the data. Call the Save method of the serializer.
/// <br/>See: <see cref="IDataManager.Save(Dictionary{string, List{object}})"/>
/// </summary>
public void Save()
=> Serializer.Save(Data);
/// <summary>
/// Import data from a file.
/// <br/>See: <see cref="IDataManager.Import{T}(string)"/>
/// </summary>
/// <typeparam name="T">The type of data to import.</typeparam>
/// <param name="pathOfTheFile">The path containing the name of the file created.</param>
public void Import<T>(string pathOfTheFile)
where T : class
{
KeyValuePair<string, T> import = Serializer.Import<T>(pathOfTheFile);
Data[import.Key].Add(import.Value);
}
/// <summary>
/// Export the data from the collection of data.
/// <br/>See: <see cref="IDataManager.Export{T}(T, string)"/>
/// </summary>
/// <typeparam name="T">The type of data to export</typeparam>
/// <param name="obj">The object to export</param>
/// <param name="pathToExport">The path containing the name of the file created.</param>
public void Export<T>(T obj, string pathToExport)
where T : class
=> Serializer.Export<T>(obj, pathToExport);
/// <summary>
/// Get all the recipe from the data.
/// </summary>
/// <param name="rcTitle">The title to give for the Recipe Collection</param>
/// <returns>A RecipeCollection that contain all the recipe in the data.</returns>
public RecipeCollection GetRecipes(string rcTitle = "default")
=> new RecipeCollection(rcTitle, Data[nameof(Recipe)].Cast<Recipe>().ToArray());
/// <summary>
/// Get all the Users from the data.
/// </summary>
/// <returns>A list of all Users.</returns>
public List<User> GetUsers()
=> new List<User>(Data[nameof(User)].Cast<User>());
/// <summary>
/// Get a list of an item in the data.
/// </summary>
/// <typeparam name="T">The type of the item</typeparam>
/// <returns>The list of all the item found in the data.</returns>
public ICollection<T> GetFromData<T>() where T : class
=> new List<T>(Data[typeof(T).Name].Cast<T>());
#endregion
}
}

@ -1,44 +1,64 @@
using System; using System;
using System.Collections.Generic; using System.Collections;
using System.Linq; using System.Collections.Generic;
using System.Text; using System.Linq;
using System.Threading.Tasks; using System.Text;
using System.Threading.Tasks;
namespace Model
{ namespace Model
/// <summary> {
/// Interface that define the methods of a data serializer. /// <summary>
/// </summary> /// Define how to manage data.
public interface IDataManager /// </summary>
{ public interface IDataManager
/// <summary> {
/// Save all the data in a file. /// <summary>
/// </summary> /// The data manager injected that know how to serialize the data.
/// <param name="elements">The data to save.</param> /// <br/><remarks><i>The setter is actually public for testing purpose. It will be private after.</i></remarks>
void Save(Dictionary<string, List<object>> elements); /// <br/>See: <see cref="IDataSerializer"/>
/// </summary>
/// <summary> IDataSerializer Serializer { get; }
/// Load all the data from a file.
/// </summary> /// <summary>
/// <returns>The data loaded.</returns> /// The collection of all data. Each line of this dictionary has the type of the data as it key and the data for values.
Dictionary<string, List<object>> Load(); /// </summary>
Dictionary<string, List<object>> Data { get; }
/// <summary>
/// Import an element to the collection of data.
/// </summary> /// <summary>
/// <typeparam name="T">The type of the element to impoert</typeparam> /// Load the data. Used to update data written in the save file.
/// <param name="pathToImport">The path containing the name of the file.</param> /// <br/>See: <see cref="IDataSerializer.Load"/>
/// <returns>A pair where the key is the entry in the data and the value is the value to add on this entry.</returns> /// </summary>
public KeyValuePair<string, T> Import<T>(string pathToImport) void LoadData();
where T : class;
/// <summary>
/// <summary> /// Save the data. Call the Save method of the serializer.
/// Export an element from the collection of data. /// <br/>See: <see cref="IDataSerializer.Save(Dictionary{string, List{object}})"/>
/// </summary> /// </summary>
/// <typeparam name="T">The type of the exported object.</typeparam> void SaveData();
/// <param name="obj">The object to export.</param>
/// <param name="pathToExport">The path containing the name of the file created.</param> /// <summary>
public void Export<T>(T obj, string pathToExport) /// Import data from a file.
where T : class; /// <br/>See: <see cref="IDataSerializer.Import{T}(string)"/>
} /// </summary>
} /// <typeparam name="T">The type of data to import.</typeparam>
/// <param name="pathOfTheFile">The path containing the name of the file created.</param>
void Import<T>(string pathOfTheFile) where T : class;
/// <summary>
/// Export the data from the collection of data.
/// <br/>See: <see cref="IDataSerializer.Export{T}(T, string)"/>
/// </summary>
/// <typeparam name="T">The type of data to export</typeparam>
/// <param name="obj">The object to export</param>
/// <param name="pathToExport">The path containing the name of the file created.</param>
void Export<T>(T obj, string pathToExport) where T : class;
/// <summary>
/// Get a list of an item in the data.
/// </summary>
/// <typeparam name="T">The type of the item</typeparam>
/// <returns>The list of all the item found in the data.</returns>
ICollection<T> GetFromData<T>() where T : class;
}
}

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
/// <summary>
/// Interface that define the methods of a data serializer.
/// </summary>
public interface IDataSerializer
{
/// <summary>
/// Save all the data in a file.
/// </summary>
/// <param name="elements">The data to save.</param>
void Save(Dictionary<string, List<object>> elements);
/// <summary>
/// Load all the data from a file.
/// </summary>
/// <returns>The data loaded.</returns>
Dictionary<string, List<object>> Load();
/// <summary>
/// Import an element to the collection of data.
/// </summary>
/// <typeparam name="T">The type of the element to impoert</typeparam>
/// <param name="pathToImport">The path containing the name of the file.</param>
/// <returns>A pair where the key is the entry in the data and the value is the value to add on this entry.</returns>
public KeyValuePair<string, T> Import<T>(string pathToImport)
where T : class;
/// <summary>
/// Export an element from the collection of data.
/// </summary>
/// <typeparam name="T">The type of the exported object.</typeparam>
/// <param name="obj">The object to export.</param>
/// <param name="pathToExport">The path containing the name of the file created.</param>
public void Export<T>(T obj, string pathToExport)
where T : class;
}
}

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
/// <summary>
/// Define how to manage passwords.
/// </summary>
public interface IPasswordManager
{
/// <summary>
/// Hash a plain text password.
/// </summary>
/// <param name="password">The plain password to hash.</param>
/// <returns>The hashed password.</returns>
public string HashPassword(string password);
/// <summary>
/// Verify a plain text password with a hashed one.
/// </summary>
/// <param name="hashedPassword">The hashed password.</param>
/// <param name="password">The plain text password.</param>
/// <returns>True is the password is correct, false otherwise.</returns>
public bool VerifyPassword(string hashedPassword,string password);
}
}

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
/// <summary>
/// Define how to manage recipes.
/// </summary>
public interface IRecipeManager
{
/// <summary>
/// Get or set the currently selected recipe.
/// </summary>
Recipe? CurrentSelected { get; set; }
/// <summary>
/// Get all the recipe in the data.
/// </summary>
/// <returns>The RecipeCollection containing the recipes stored in the data.</returns>
RecipeCollection GetAllRecipes();
/// <summary>
/// Get the recipe corresponding to the id.
/// </summary>
/// <param name="id">The id of the recipe we want.</param>
/// <returns>The recipe corresponding to the id.</returns>
Recipe GetRecipeFromId(int id);
/// <summary>
/// Search in data the recipes containing this part of title.
/// </summary>
/// <param name="title">Search string.</param>
/// <returns>The RecipeCollection of recipes corresponding to the search.</returns>
RecipeCollection SearchRecipeByTitle(string title);
/// <summary>
/// Get all the recipes created by the author.
/// </summary>
/// <param name="authorMail">The author's mail.</param>
/// <returns>The RecipeCollection of the recipe created by the author.</returns>
RecipeCollection GetRecipeByAuthor(string authorMail);
/// <summary>
/// Get an ordored list of the recipes sorted by the priority list.
/// </summary>
/// <param name="priority">The priority list.</param>
/// <returns>The RecipeCollection ordored by the priority list.</returns>
RecipeCollection GetRecipesByPriorityOrder(IEnumerable<Priority> priority);
/// <summary>
/// Add a recipe to the data.
/// </summary>
/// <param name="recipe">The recipe to add.</param>
/// <returns>Weither the adding succed or not.</returns>
bool AddRecipeToData(Recipe recipe);
/// <summary>
/// Modify the <see cref="CurrentSelected"/> recipe with a new one in the data.
/// </summary>
/// <param name="newRecipe">The new recipe</param>
/// <returns>Weither the modification succed or not.</returns>
bool ModifyCurrentSelected(Recipe newRecipe);
}
}

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
/// <summary>
/// Define how to manage an user.
/// </summary>
public interface IUserManager
{
/// <summary>
/// Get the current connected user. Null if no user is connected.
/// </summary>
User? CurrentConnected { get; }
/// <summary>
/// Get the password manager used to hash passords.
/// </summary>
IPasswordManager PasswordManager { get; }
/// <summary>
/// Get a collection of all users in the data.
/// </summary>
/// <returns>A collection of all user.</returns>
ICollection<User> GetAllUsers();
/// <summary>
/// Get an user by his email.
/// </summary>
/// <param name="mail">The user's mail.</param>
/// <returns>The user corresponding to the mail.</returns>
User GetUserFromMail(string mail);
/// <summary>
/// Create a new user. The mail and the password are required. Other can be null.
/// <br/>This function use the password manager to hash the plain text password.
/// </summary>
/// <param name="mail">The user's mail address.</param>
/// <param name="password">The user's plain text password.</param>
/// <param name="name">The user's name.</param>
/// <param name="surname">The user's surname.</param>
/// <param name="profilePict">The user's profile picture.</param>
/// <returns>A new user.</returns>
User CreateUser(string mail, string password,
string? name = null, string? surname = null, string? profilePict = null);
/// <summary>
/// Add an user in the data.
/// </summary>
/// <param name="user">The user to add.</param>
/// <returns>True is the user was correctly added to the data. False otherwise.</returns>
bool AddUserToData(User user);
/// <summary>
/// Modify the currently connected user.
/// </summary>
/// <param name="newUser">An user containing new user's properties to changes.</param>
/// <returns></returns>
bool ModifyCurrentConnected(User newUser);
/// <summary>
/// Log in an user. If the connection succed, pass the connected user to <see cref="CurrentConnected"/>.
/// </summary>
/// <param name="mail">The User's mail.</param>
/// <param name="password">The User's (plain text) password.</param>
/// <returns>True if the connection succed, false otherwise.</returns>
bool LogIn(string mail, string password);
/// <summary>
/// Log out the current connected user.
/// </summary>
void LogOut();
}
}

@ -1,161 +1,57 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Model.Managers
namespace Model
{ {
/// <summary> /// <summary>
/// The Main manager of the model. /// The Main manager of the model.
/// </summary> /// </summary>
public class MasterManager : INotifyPropertyChanged public class MasterManager
{ {
#region Attributes & Properties #region Attributes & Properties
public event PropertyChangedEventHandler? PropertyChanged;
private RecipeCollection _recipesInSearch = new RecipeCollection("");
/// <summary>
/// The currently connected user. 'null' if no user is connected.
/// </summary>
public User? CurrentConnectedUser { get; private set; }
public RecipeCollection RecipesInSearch
{
get => _recipesInSearch;
set
{
_recipesInSearch = value;
OnPropertyChange();
}
}
/// <summary> /// <summary>
/// The collection of all recipes loaded. /// Manage the data of the application.
/// </summary> /// </summary>
public RecipeCollection Recipes { get; private set; } public IDataManager Data { get; private set; }
/// <summary> /// <summary>
/// The collection of all users loaded. /// Manage the recipes of the application.
/// </summary> /// </summary>
public List<User> Users { get; private set; } public IRecipeManager Recipe { get; private set; }
/// <summary> /// <summary>
/// The data manager for load, save, export and import data. /// Manage the users of the application.
/// </summary> /// </summary>
public DataManager DataMgr { get; private set; } public IUserManager User { get; private set; }
#endregion #endregion
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Constructor of the MasterManager. /// Constructor of the MasterManager.
/// </summary> /// </summary>
/// <param name="dataManager">The serializer for the data.</param> /// <param name="dataManager">The data manager.</param>
public MasterManager(IDataManager dataManager) /// <param name="recipeManager">The recipes manager.</param>
/// <param name="userManager">The users manager.</param>
public MasterManager(IDataManager dataManager,
IRecipeManager recipeManager,
IUserManager userManager)
{ {
DataMgr = new DataManager(dataManager); Data = dataManager;
CurrentConnectedUser = null; Recipe = recipeManager;
Recipes = DataMgr.GetRecipes("all recipes"); User = userManager;
RecipesInSearch = DataMgr.GetRecipes("search on");
Users = DataMgr.GetUsers();
} }
#endregion #endregion
#region Methods #region Methods
/// <summary> /// <summary>
/// Log in an user. Test if the log in information are correct then connect the user. /// Setup all the necessary parameters before start.
/// </summary> /// </summary>
/// <param name="mail">The user's mail</param> public void Setup()
/// <param name="password">The user's password.</param>
/// <returns>True if the user was correctly connected, false if there is something wrong.</returns>
/// <exception cref="ArgumentNullException"></exception>
public bool Login(string mail, string password)
{ {
if (Users is null || Users.Count == 0) Data.LoadData();
throw new ArgumentNullException("There is no users registred.");
#if DEBUG
if (mail == "admin")
{
CurrentConnectedUser = Users.FirstOrDefault(u => u.Mail == "admin@mctg.fr");
return true;
}
#endif
User? user = Users.Find(u => u.Mail == mail);
if (user is null || !user.psswMgr.VerifyPassword(user.Password, password))
return false;
CurrentConnectedUser = user;
return true;
}
/// <summary>
/// Log out an user.
/// </summary>
/// <returns>True if the user is correctly diconnected, false otherwise.</returns>
public bool Logout()
{
if (CurrentConnectedUser is null)
return false;
CurrentConnectedUser = null;
return true;
} }
#endregion
/// <summary>
/// Register an user.
/// </summary>
/// <param name="newuser">The new user to add in the database.</param>
/// <returns>False if there is a problem with the registerement, true otherwise.</returns>
public bool Register(User newuser)
{
try
{
User user = newuser;
DataMgr.Data[nameof(User)].Add(user);
Users = DataMgr.GetUsers();
}
catch (ArgumentException e)
{
Debug.WriteLine(e.Message);
return false;
}
return true;
}
/// <summary>
/// Add a recipe to the database.
/// </summary>
/// <param name="recipe">The recipe to add.</param>
public void AddRecipe(Recipe recipe)
{
DataMgr.Data[nameof(Recipe)].Add(recipe);
Recipes = DataMgr.GetRecipes();
}
/// <summary>
/// Get the current connected user's personal recipes.
/// </summary>
/// <returns>The current connected user's personal recipes.</returns>
public RecipeCollection GetCurrentUserRecipes()
=> new RecipeCollection("User recipes",
DataMgr.GetRecipes().ToList().FindAll(r => r.AuthorMail == CurrentConnectedUser?.Mail).ToArray());
/// <summary>
/// Notify property change handler.
/// </summary>
/// <param name="propertyName">the name of the property that change.</param>
public void OnPropertyChange([CallerMemberName] string propertyName = "")
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
#endregion
} }

@ -1,10 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Configurations>Debug;Release;CI</Configurations> <Configurations>Debug;Release;CI</Configurations>
</PropertyGroup> </PropertyGroup>
</Project> <ItemGroup>
<ProjectReference Include="..\AppException\AppException.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
public class ReadOnlyObservableRecipeCollection : ReadOnlyObservableCollection<Recipe>
{
private RecipeCollection _recipeObserved;
public string Description => _recipeObserved.Description;
public ReadOnlyObservableRecipeCollection(RecipeCollection recipeCollection)
: base(recipeCollection)
{
_recipeObserved = recipeCollection;
}
}
}

@ -52,6 +52,12 @@ namespace Model
} }
} }
/// <summary>
/// Priority of this recipe.
/// </summary>
[DataMember(Name = "priority")]
public Priority Priority { get; private set; }
/// <summary> /// <summary>
/// The Title of the recipe. <br/> /// The Title of the recipe. <br/>
/// Set to "No title." when the value passed is null, empty or contain white spaces. /// Set to "No title." when the value passed is null, empty or contain white spaces.
@ -110,13 +116,15 @@ namespace Model
/// </summary> /// </summary>
/// <param name="title">The title of the recipe</param> /// <param name="title">The title of the recipe</param>
/// <param name="type">The type of the recipe.</param> /// <param name="type">The type of the recipe.</param>
/// <param name="priority">The priority of this recipe.</param>
/// <param name="id">The id of the recipe. If not given, get a new id.</param> /// <param name="id">The id of the recipe. If not given, get a new id.</param>
/// <param name="authorMail">The name of the user that create this recipe.</param> /// <param name="authorMail">The name of the user that create this recipe.</param>
/// <param name="picture"> The image that represent the recipe</param> /// <param name="picture"> The image that represent the recipe</param>
public Recipe(string title, RecipeType type, int? id, string? authorMail, string? picture) public Recipe(string title, RecipeType type, Priority priority, int? id, string? authorMail, string? picture)
{ {
Title = title; Title = title;
Type = type; Type = type;
Priority = priority;
Image = picture; Image = picture;
AuthorMail = authorMail; AuthorMail = authorMail;
@ -134,18 +142,21 @@ namespace Model
else Id = (int)id; else Id = (int)id;
} }
public Recipe(string title, RecipeType type, int? id, string? authorMail) /// <inheritdoc cref="Recipe.Recipe(string, RecipeType, Priority, int?, string?, string?)"/>
: this(title, type, id, authorMail, null) public Recipe(string title, RecipeType type, Priority priority, int? id, string? authorMail)
: this(title, type, priority, id, authorMail, null)
{ {
} }
public Recipe(string title, RecipeType type) /// <inheritdoc cref="Recipe.Recipe(string, RecipeType, Priority, int?, string?, string?)"/>
: this(title, type, null, null) public Recipe(string title, RecipeType type, Priority priority)
: this(title, type, priority, null, null)
{ {
} }
/// <inheritdoc cref="Recipe.Recipe(string, RecipeType, Priority, int?, string?, string?)"/>
public Recipe(string title) public Recipe(string title)
: this(title, RecipeType.Unspecified) : this(title, RecipeType.Unspecified, Priority.Fast)
{ {
} }
#endregion #endregion
@ -176,7 +187,7 @@ namespace Model
/// Concatenate the list of ingredients in a single string /// Concatenate the list of ingredients in a single string
/// </summary> /// </summary>
/// <returns>The list of ingredients in string format</returns> /// <returns>The list of ingredients in string format</returns>
private string ConcatIngredients() public string ConcatIngredients()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
foreach (Ingredient ingredient in Ingredients) foreach (Ingredient ingredient in Ingredients)
@ -197,9 +208,11 @@ namespace Model
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
var item = obj as Recipe; if (ReferenceEquals(obj, null)) return false;
if (item == null) return false; if (ReferenceEquals(obj, this)) return true;
return Equals(obj); if (GetType() != obj.GetType()) return false;
return Equals(obj as Recipe);
} }
public override int GetHashCode() public override int GetHashCode()
@ -209,21 +222,7 @@ namespace Model
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new StringBuilder($"[Recipe n°{Id}] - {Title}\n"); return $"'{Title}' [{Id}] - {Type}, {Priority} | {AuthorMail} | {Image}";
foreach (PreparationStep ps in PreparationSteps)
{
sb.AppendFormat("\t* {0}\n", ps.ToString());
}
sb.AppendLine();
sb.AppendLine(ConcatIngredients());
sb.AppendLine();
foreach (Review review in Reviews)
{
sb.AppendLine(review.ToString());
}
sb.AppendLine();
sb.AppendLine($"Posted by: {AuthorMail?.ToString()}");
return sb.ToString();
} }
#endregion #endregion
} }

@ -2,6 +2,7 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text; using System.Text;
namespace Model namespace Model
@ -31,53 +32,32 @@ namespace Model
_description = "No description."; _description = "No description.";
else else
_description = value; _description = value;
OnPropertyChanged(new PropertyChangedEventArgs("Description"));
} }
} }
#endregion #endregion
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Construct a new collection of _recipes. /// Construct a new collection of recipes.
/// </summary> /// </summary>
/// <param _name="description">A short description of what this list will contain</param> /// <param name="description">A short description of what this list will contain.</param>
/// <param _name="recipes">Recipes to add in this new collection</param> /// <param name="recipes">Recipes to add in this new collection.</param>
public RecipeCollection(string description, params Recipe[] recipes) public RecipeCollection(string description, ICollection<Recipe> recipes)
: base(recipes) : base(recipes)
{ {
Description = description; Description = description;
} }
#endregion
#region Methods /// <inheritdoc cref="RecipeCollection.RecipeCollection(string, ICollection{Recipe})"/>
/// <summary> public RecipeCollection(string description)
/// Find a recipe in this list by giving the id. : base()
/// </summary>
/// <param _name="id">The id of the list we are looking for</param>
/// <returns>The recipe of the id given</returns>
/// <exception cref="ArgumentException"/>
public Recipe? GetRecipeById(int id)
{ {
Recipe? recipe = this.ToList().Find(r => r.Id == id);
if (recipe == null) throw new ArgumentException("No _recipes match the given id.");
return recipe;
}
/// <summary>
/// Utility to find a recipe by his _name.
/// </summary>
/// <param _name="str">The string for the search</param>
/// <returns>A collection of Recipe where their Title contain the string.</returns>
public RecipeCollection ResearchByName(string str)
{
if (string.IsNullOrEmpty(str))
return this;
return new RecipeCollection(
description: $"Results of the research: {str}",
recipes: this.ToList().FindAll(x => x.Title.ToLower().Contains(str.ToLower())).ToArray());
} }
#endregion
#region Methods
public virtual bool Equals(RecipeCollection? other) public virtual bool Equals(RecipeCollection? other)
{ {
if (other == null) return false; if (other == null) return false;

@ -1,4 +1,4 @@
using Model.Managers; using Model;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
public interface IPasswordManager
{
public string HashPassword(string password);
public bool VerifyPassword(string hashedPassword,string password);
}
}

@ -1,205 +1,184 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.ComponentModel; using System.ComponentModel;
using System.Collections.ObjectModel;
namespace Model
{ namespace Model
/// <summary> {
/// A user is an entity with a _name, a surname, mail, profilePict and a list of priority. /// <summary>
/// This user can login with an Id and a password /// A user is an entity with a name, a surname, mail, profilePict and a list of priority.
/// </summary> /// This user can login with an Id and a password
[DataContract(Name = "user")] /// </summary>
public class User : IEquatable<User> , INotifyPropertyChanged [DataContract(Name = "user")]
{ public class User : IEquatable<User> , INotifyPropertyChanged
#region Private Attributes {
#region Private Attributes
[DataMember] private string name=""; [DataMember] private string _name = "";
[DataMember] private string surname=""; [DataMember] private string _surname = "";
[DataMember] private string mail = ""; [DataMember] private string _mail = "";
[DataMember] private string picture = "";
[DataMember] private string password = ""; [DataMember(Name = "priorities")]
[DataMember] private List<Priority> priorities; public ObservableCollection<Priority> _priorities { get; private set; } = new ObservableCollection<Priority>
{
public event PropertyChangedEventHandler? PropertyChanged; Priority.Gourmet,
#endregion Priority.Economic,
Priority.Fast,
#region Properties Priority.Light,
Priority.Easy
/// <summary> };
/// Property to get Name of users and a setter
/// </summary> public event PropertyChangedEventHandler? PropertyChanged;
/// <exception cref="ArgumentException" >Setter have Exception which is trigger when Name is null</exception> #endregion
public string Name
{ #region Properties
get { return name; } /// <summary>
set /// Property to get Name of users and a setter
{ /// </summary>
/// <exception cref="ArgumentException" >Setter have Exception which is trigger when Name is null</exception>
name = value; public string Name
OnPropertyChanged(); {
} get { return _name; }
} set
{
/// <summary>
/// Property to get Surname of users and a setter _name = value;
/// </summary> OnPropertyChanged();
/// <exception cref="ArgumentException" >Setter have Exception which is trigger when Surname is null</exception> }
public string Surname }
{
get { return surname; } /// <summary>
set /// Property to get Surname of users and a setter
{ /// </summary>
/// <exception cref="ArgumentException" >Setter have Exception which is trigger when Surname is null</exception>
surname = value; public string Surname
OnPropertyChanged(); {
} get { return _surname; }
} set
{
/// <summary>
/// Property to get mail of users and a setter _surname = value;
/// </summary> OnPropertyChanged();
/// <exception cref="ArgumentException" >User's mail will serve to log the user. So there's no setter, just an init. User will enter one time his email at his }
/// account creation.</exception> }
public string Mail
{ /// <summary>
get { return mail; } /// Property to get mail of users and a setter
private init /// </summary>
{ /// <exception cref="ArgumentException" >User's mail will serve to log the user. So there's no setter, just an init. User will enter one time his email at his
if (string.IsNullOrWhiteSpace(value)) /// account creation.</exception>
{ public string Mail
throw new ArgumentException("Impossible d'avoir un champ Email vide!"); {
} get { return _mail; }
mail = value; private init
} {
} if (string.IsNullOrWhiteSpace(value))
{
public string Password throw new ArgumentException("Impossible d'avoir un champ Email vide!");
{ }
get => password; _mail = value;
set => password = value; }
}
}
/// <summary>
/// The user's hashed password. The hashed method is defined with the PasswordManager.
/// <summary> /// <br/>See: <see cref="IPasswordManager"/>.
/// For now, we define the ProfilPict as a string which is "PhotoParDefaut" /// </summary>
/// when the value is null. [DataMember(Name = "hashedpass")]
/// </summary> public string Password { get; private set; } = "";
public string ProfilPict
{ /// <summary>
get => picture; /// For now, we define the ProfilePict as a string which is "PhotoParDefaut"
set => picture = value; /// when the value is null.
/// </summary>
} [DataMember(Name = "profilepic")]
public string ProfilePict { get; private set; } = "default_picture.png";
/// <summary>
/// This is the list of priorities specific tu the user. This list is initiate /// <summary>
/// by default. User could change it at will. /// This is the list of priorities specific tu the user. This list is initiate
/// </summary> /// by default. User could change it at will.
/// </summary>
public List<Priority> Priorities public ReadOnlyObservableCollection<Priority> Priorities { get; private set; }
{ #endregion
get => priorities;
set=> priorities = value; #region Methods
} public override bool Equals(object? other)
{
public override bool Equals(object? other) if (ReferenceEquals(other, null)) return false;
{ if (ReferenceEquals(other, this)) return true;
if (other == null) return false; if (GetType() != other.GetType()) return false;
if (other == this) return true;
return Equals(other); return Equals(other as User);
} }
public bool Equals(User? other) public bool Equals(User? other)
{ {
if (other == null) return false; if (other == null) return false;
return Name.Equals(other.Name) && Surname.Equals(other.Surname) && Mail.Equals(other.Mail); if (other == this) return true;
}
return Name.Equals(other.Name) && Surname.Equals(other.Surname) && Mail.Equals(other.Mail);
public override int GetHashCode() }
{
throw new NotImplementedException(); public override int GetHashCode()
} {
throw new NotImplementedException();
}
protected void OnPropertyChanged ([CallerMemberName] string? propertyName = null)
{ protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
if (PropertyChanged != null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); if (PropertyChanged != null)
} PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{ public override string ToString()
return $"{Name} {Surname}"; {
} return $"{Name} {Surname}";
}
[DataMember(Name = "passmgr")] #endregion
public IPasswordManager psswMgr { get; private set; }
#region Constructors
/// <summary>
#endregion /// Construtors of user.
/// </summary>
#region Constructors /// <param name="name">The name of the user</param>
/// <param name="surname">The surname of the user</param>
/// <summary> /// <param name="mail">The user needs an email to login.</param>
/// Construtors of user. /// <param name="hashedPassword">The password of the new user.</param>
/// </summary> public User(string name, string surname, string mail, string hashedPassword)
/// <param name="name">The name of the user</param> {
/// <param name="surname">The surname of the user</param> Name = name;
/// <param name="mail">The user needs an email to login.</param> Surname = surname;
/// <param name="password">The password of the new user.</param> Mail = mail;
/// <param name="passwordManager">The password manager to manage the user password.</param> Password = hashedPassword;
public User(string name, string surname, string mail, string password, IPasswordManager passwordManager) Priorities = new ReadOnlyObservableCollection<Priority>(_priorities);
{ }
Name = name;
Surname = surname; /// <inheritdoc cref="User.User"/>
Mail = mail; /// <param name="profilePict">Profile picture of the new user.</param>
psswMgr = passwordManager; public User(string name, string surname, string mail, string hashedPassword, string profilePict)
Password = psswMgr.HashPassword(password); : this(name, surname, mail, hashedPassword)
priorities = new List<Priority> { {
Priority.Gourmet, ProfilePict = profilePict;
Priority.Economic, }
Priority.Fast,
Priority.Light, /// <inheritdoc cref="User.User"/>
Priority.Easy}; public User()
ProfilPict = picture; : this("John", "Doe", "truc@gmail.com", "mdp")
{
} }
/// <summary> /// <inheritdoc cref="User.User"/>
/// <inheritdoc cref="User.User"/> /// <param name="user">The user to copy.</param>
/// </summary> public User(User user)
public User(string name, string surname, string mail, string password) {
: this(name, surname,mail, password, new PasswordSHA256()) Name = user.Name;
{ Surname = user.Surname;
Mail = user.Mail;
} Password = user.Password;
_priorities = user._priorities;
/// <summary> Priorities = new ReadOnlyObservableCollection<Priority>(_priorities);
/// <inheritdoc cref="User.User"/> ProfilePict = user.ProfilePict;
/// </summary> }
public User() #endregion
: this("John", "Doe", "truc@gmail.com", "mdp") }
{ }
}
/// <summary>
/// <inheritdoc cref="User.User"/>
/// </summary>
public User (User user)
{
Name = user.Name;
Surname = user.Surname;
Mail = user.Mail;
psswMgr = user.psswMgr;
Password = user.Password;
priorities = user.Priorities;
ProfilPict = user.ProfilPict;
}
#endregion
}
}

@ -1,20 +1,12 @@
using Model; using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json; using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace DataPersistence namespace DataPersistence
{ {
/// <summary> /// <summary>
/// Define a serializer to manage JSON files. /// Define a serializer to manage JSON files.
/// </summary> /// </summary>
public class DataContractJSON : IDataManager public class DataContractJSON : IDataSerializer
{ {
#region Attributes #region Attributes
private string _jsonFolderPath; private string _jsonFolderPath;
@ -38,6 +30,7 @@ namespace DataPersistence
{ {
typeof(Recipe), typeof(Recipe),
typeof(RecipeType), typeof(RecipeType),
typeof(Priority),
typeof(Review), typeof(Review),
typeof(User), typeof(User),
typeof(Ingredient), typeof(Ingredient),

@ -1,19 +1,13 @@
using Model; using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Xml; using System.Xml;
using System.Xml.Linq;
namespace DataPersistence namespace DataPersistence
{ {
/// <summary> /// <summary>
/// Define a serializer to manage XML files. /// Define a serializer to manage XML files.
/// </summary> /// </summary>
public class DataContractXML : IDataManager public class DataContractXML : IDataSerializer
{ {
#region Attributes #region Attributes
private string _xmlFolderPath; private string _xmlFolderPath;
@ -46,11 +40,11 @@ namespace DataPersistence
{ {
typeof(Recipe), typeof(Recipe),
typeof(RecipeType), typeof(RecipeType),
typeof(Priority),
typeof(Review), typeof(Review),
typeof(User), typeof(User),
typeof(Ingredient), typeof(Ingredient),
typeof(Quantity), typeof(Quantity)
typeof(PasswordSHA256)
}, },
PreserveObjectReferences = true PreserveObjectReferences = true
}; };

@ -6,8 +6,8 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\..\Model\Model.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Managers\Managers.csproj" />
<ProjectReference Include="..\..\Model\Model.csproj" />
</ItemGroup>
</Project>

@ -1,18 +1,18 @@
using Model; using Managers;
using Model;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace DataPersistence
namespace FakePersistance
{ {
/// <summary> /// <summary>
/// The subs class is a group of prefabricated object that can only be loaded. It only use is for testing. /// The subs class is a group of prefabricated object that can only be loaded. It only use is for testing.
/// </summary> /// </summary>
public class Stubs : IDataManager public class Stubs : IDataSerializer
{ {
private IPasswordManager psswdMgr = new PasswordSHA256Manager();
public Dictionary<string, List<object>> Load() public Dictionary<string, List<object>> Load()
{ {
Dictionary<string, List<object>> data = new Dictionary<string, List<object>> Dictionary<string, List<object>> data = new Dictionary<string, List<object>>
@ -22,7 +22,7 @@ namespace DataPersistence
nameof(Recipe), nameof(Recipe),
new List<object>(new[] new List<object>(new[]
{ {
new Recipe("Cookies classiques", RecipeType.Dessert, null, "admin@mctg.fr", "") new Recipe("Cookies classiques", RecipeType.Dessert, Priority.Easy, null, "admin@mctg.fr", "")
{ {
Ingredients = new List<Ingredient> Ingredients = new List<Ingredient>
{ {
@ -42,7 +42,8 @@ namespace DataPersistence
}, },
new Recipe( new Recipe(
title: "Cookies au chocolat", title: "Cookies au chocolat",
type: RecipeType.Dessert) type: RecipeType.Dessert,
priority: Priority.Fast)
{ {
Ingredients = new List<Ingredient> Ingredients = new List<Ingredient>
{ {
@ -57,7 +58,8 @@ namespace DataPersistence
}, },
new Recipe( new Recipe(
title: "Gateau nature", title: "Gateau nature",
type: RecipeType.Dessert) type: RecipeType.Dessert,
priority: Priority.Gourmet)
{ {
Ingredients = new List<Ingredient> Ingredients = new List<Ingredient>
{ {
@ -77,7 +79,8 @@ namespace DataPersistence
}, },
new Recipe( new Recipe(
title: "Gateau au pommes", title: "Gateau au pommes",
type: RecipeType.Dessert) type: RecipeType.Dessert,
priority: Priority.Light)
{ {
PreparationSteps = new List<PreparationStep> PreparationSteps = new List<PreparationStep>
{ {
@ -90,6 +93,7 @@ namespace DataPersistence
new Recipe( new Recipe(
title: "Gateau au chocolat", title: "Gateau au chocolat",
type: RecipeType.Dessert, type: RecipeType.Dessert,
priority: Priority.Economic,
id: null, authorMail: "pedrosamigos@hotmail.com") id: null, authorMail: "pedrosamigos@hotmail.com")
{ {
Ingredients = new List<Ingredient> Ingredients = new List<Ingredient>
@ -110,6 +114,7 @@ namespace DataPersistence
new Recipe( new Recipe(
title: "Dinde au jambon", title: "Dinde au jambon",
type: RecipeType.Dish, type: RecipeType.Dish,
priority: Priority.Easy,
id: null, authorMail: "pedrosamigos@hotmail.com") id: null, authorMail: "pedrosamigos@hotmail.com")
{ {
Ingredients = new List<Ingredient> Ingredients = new List<Ingredient>
@ -130,6 +135,7 @@ namespace DataPersistence
new Recipe( new Recipe(
title: "Poulet au curry", title: "Poulet au curry",
type: RecipeType.Dish, type: RecipeType.Dish,
priority: Priority.Gourmet,
id: null, authorMail: "pedrosamigos@hotmail.com") id: null, authorMail: "pedrosamigos@hotmail.com")
{ {
Ingredients = new List<Ingredient> Ingredients = new List<Ingredient>
@ -165,12 +171,12 @@ namespace DataPersistence
name: "Admin", name: "Admin",
surname: "Admin", surname: "Admin",
mail: "admin@mctg.fr", mail: "admin@mctg.fr",
password: "admin"), hashedPassword: psswdMgr.HashPassword("admin")),
new User( new User(
name: "Pedros", name: "Pedros",
surname: "Amigos", surname: "Amigos",
mail: "pedrosamigos@hotmail.com", mail: "pedrosamigos@hotmail.com",
password: "pamigos") hashedPassword: psswdMgr.HashPassword("pamigos"))
}) })
#endregion #endregion

@ -1,55 +1,77 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.5.33516.290 VisualStudioVersion = 17.5.33516.290
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "ConsoleApp\ConsoleApp.csproj", "{666C2211-8EBB-4FC8-9484-CB93BC854153}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "ConsoleApp\ConsoleApp.csproj", "{666C2211-8EBB-4FC8-9484-CB93BC854153}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{42FF86BD-92F9-4A32-A938-68515905378F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{42FF86BD-92F9-4A32-A938-68515905378F}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Views", "Views\Views.csproj", "{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Views", "Views\Views.csproj", "{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model_UnitTests", "Tests\Model_UnitTests\Model_UnitTests.csproj", "{45AB746A-194B-4E43-81EB-83B06F35AA33}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model_UnitTests", "Tests\Model_UnitTests\Model_UnitTests.csproj", "{45AB746A-194B-4E43-81EB-83B06F35AA33}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{08B80CE8-A01D-4D86-8989-AF225D5DA48C}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{08B80CE8-A01D-4D86-8989-AF225D5DA48C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPersistence", "DataPersistence\DataPersistence.csproj", "{432F9D12-B1F7-4A79-8720-4971BB10B831}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataPersistence", "Persistance\DataPersistence\DataPersistence.csproj", "{432F9D12-B1F7-4A79-8720-4971BB10B831}"
EndProject EndProject
Global Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Managers", "Managers\Managers.csproj", "{A3703A19-687C-4F63-A5DE-18E6D8995C77}"
GlobalSection(SolutionConfigurationPlatforms) = preSolution EndProject
Debug|Any CPU = Debug|Any CPU Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppException", "AppException\AppException.csproj", "{77E6BD97-B1E5-45F5-ABFB-9A1D985A8EDE}"
Release|Any CPU = Release|Any CPU EndProject
EndGlobalSection Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FakePersistance", "Persistance\FakePersistance\FakePersistance.csproj", "{7C340CB2-8925-4BC4-9D8C-9058D9657F3F}"
GlobalSection(ProjectConfigurationPlatforms) = postSolution EndProject
{666C2211-8EBB-4FC8-9484-CB93BC854153}.Debug|Any CPU.ActiveCfg = Debug|Any CPU Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Persistance", "Persistance", "{F6413DA3-CE67-4097-8FF7-8D221AF2A5E8}"
{666C2211-8EBB-4FC8-9484-CB93BC854153}.Debug|Any CPU.Build.0 = Debug|Any CPU EndProject
{666C2211-8EBB-4FC8-9484-CB93BC854153}.Release|Any CPU.ActiveCfg = Release|Any CPU Global
{666C2211-8EBB-4FC8-9484-CB93BC854153}.Release|Any CPU.Build.0 = Release|Any CPU GlobalSection(SolutionConfigurationPlatforms) = preSolution
{42FF86BD-92F9-4A32-A938-68515905378F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
{42FF86BD-92F9-4A32-A938-68515905378F}.Debug|Any CPU.Build.0 = Debug|Any CPU Release|Any CPU = Release|Any CPU
{42FF86BD-92F9-4A32-A938-68515905378F}.Release|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection
{42FF86BD-92F9-4A32-A938-68515905378F}.Release|Any CPU.Build.0 = Release|Any CPU GlobalSection(ProjectConfigurationPlatforms) = postSolution
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {666C2211-8EBB-4FC8-9484-CB93BC854153}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.Build.0 = Debug|Any CPU {666C2211-8EBB-4FC8-9484-CB93BC854153}.Debug|Any CPU.Build.0 = Debug|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.Deploy.0 = Debug|Any CPU {666C2211-8EBB-4FC8-9484-CB93BC854153}.Release|Any CPU.ActiveCfg = Release|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.ActiveCfg = Release|Any CPU {666C2211-8EBB-4FC8-9484-CB93BC854153}.Release|Any CPU.Build.0 = Release|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.Build.0 = Release|Any CPU {42FF86BD-92F9-4A32-A938-68515905378F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.Deploy.0 = Release|Any CPU {42FF86BD-92F9-4A32-A938-68515905378F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {42FF86BD-92F9-4A32-A938-68515905378F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.Debug|Any CPU.Build.0 = Debug|Any CPU {42FF86BD-92F9-4A32-A938-68515905378F}.Release|Any CPU.Build.0 = Release|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.Release|Any CPU.ActiveCfg = Release|Any CPU {508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.Release|Any CPU.Build.0 = Release|Any CPU {508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{432F9D12-B1F7-4A79-8720-4971BB10B831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{432F9D12-B1F7-4A79-8720-4971BB10B831}.Debug|Any CPU.Build.0 = Debug|Any CPU {508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{432F9D12-B1F7-4A79-8720-4971BB10B831}.Release|Any CPU.ActiveCfg = Release|Any CPU {508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.Build.0 = Release|Any CPU
{432F9D12-B1F7-4A79-8720-4971BB10B831}.Release|Any CPU.Build.0 = Release|Any CPU {508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection {45AB746A-194B-4E43-81EB-83B06F35AA33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
GlobalSection(SolutionProperties) = preSolution {45AB746A-194B-4E43-81EB-83B06F35AA33}.Debug|Any CPU.Build.0 = Debug|Any CPU
HideSolutionNode = FALSE {45AB746A-194B-4E43-81EB-83B06F35AA33}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection {45AB746A-194B-4E43-81EB-83B06F35AA33}.Release|Any CPU.Build.0 = Release|Any CPU
GlobalSection(NestedProjects) = preSolution {432F9D12-B1F7-4A79-8720-4971BB10B831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33} = {08B80CE8-A01D-4D86-8989-AF225D5DA48C} {432F9D12-B1F7-4A79-8720-4971BB10B831}.Debug|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection {432F9D12-B1F7-4A79-8720-4971BB10B831}.Release|Any CPU.ActiveCfg = Release|Any CPU
GlobalSection(ExtensibilityGlobals) = postSolution {432F9D12-B1F7-4A79-8720-4971BB10B831}.Release|Any CPU.Build.0 = Release|Any CPU
SolutionGuid = {ADEA5603-1EF6-4D43-9493-7D6D9DE7FA3F} {A3703A19-687C-4F63-A5DE-18E6D8995C77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
EndGlobalSection {A3703A19-687C-4F63-A5DE-18E6D8995C77}.Debug|Any CPU.Build.0 = Debug|Any CPU
EndGlobal {A3703A19-687C-4F63-A5DE-18E6D8995C77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A3703A19-687C-4F63-A5DE-18E6D8995C77}.Release|Any CPU.Build.0 = Release|Any CPU
{77E6BD97-B1E5-45F5-ABFB-9A1D985A8EDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77E6BD97-B1E5-45F5-ABFB-9A1D985A8EDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77E6BD97-B1E5-45F5-ABFB-9A1D985A8EDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77E6BD97-B1E5-45F5-ABFB-9A1D985A8EDE}.Release|Any CPU.Build.0 = Release|Any CPU
{7C340CB2-8925-4BC4-9D8C-9058D9657F3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C340CB2-8925-4BC4-9D8C-9058D9657F3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C340CB2-8925-4BC4-9D8C-9058D9657F3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C340CB2-8925-4BC4-9D8C-9058D9657F3F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{45AB746A-194B-4E43-81EB-83B06F35AA33} = {08B80CE8-A01D-4D86-8989-AF225D5DA48C}
{432F9D12-B1F7-4A79-8720-4971BB10B831} = {F6413DA3-CE67-4097-8FF7-8D221AF2A5E8}
{7C340CB2-8925-4BC4-9D8C-9058D9657F3F} = {F6413DA3-CE67-4097-8FF7-8D221AF2A5E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {ADEA5603-1EF6-4D43-9493-7D6D9DE7FA3F}
EndGlobalSection
EndGlobal

@ -1,27 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject> <IsTestProject>true</IsTestProject>
<Configurations>Debug;Release;CI</Configurations> <Configurations>Debug;Release;CI</Configurations>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2"> <PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Model\Model.csproj" /> <ItemGroup>
<ProjectReference Include="..\..\DataPersistence\DataPersistence.csproj" /> <ProjectReference Include="..\..\Managers\Managers.csproj" />
</ItemGroup> <ProjectReference Include="..\..\Persistance\DataPersistence\DataPersistence.csproj" />
</Project> <ProjectReference Include="..\..\Persistance\FakePersistance\FakePersistance.csproj" />
</ItemGroup>
</Project>

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataPersistence;
using Model;
using Model.Managers;
namespace Model_UnitTests
{
public class RecipeCollection_UT
{
[Fact]
public void TestResearchByName()
{
MasterManager masterManager = new MasterManager(new Stubs());
RecipeCollection recipes = masterManager.DataMgr.GetRecipes("test rc");
Recipe? search_result = recipes.ResearchByName("chocolat").FirstOrDefault();
Assert.NotNull(search_result);
Assert.Equal("Cookies au chocolat", search_result.Title);
}
}
}

@ -8,7 +8,7 @@ namespace Model_UnitTests
public void TestVoidConstructor() public void TestVoidConstructor()
{ {
Recipe r = new Recipe( Recipe r = new Recipe(
title: "test recipe", type: RecipeType.Unspecified); title: "test recipe", type: RecipeType.Unspecified, priority: Priority.Easy);
Assert.NotNull(r.Title); Assert.NotNull(r.Title);
} }

@ -12,8 +12,8 @@ namespace Model_UnitTests
[Fact] [Fact]
public void TestConstructUser() public void TestConstructUser()
{ {
PasswordSHA256 passwordManager = new PasswordSHA256(); PasswordSHA256Manager passwordManager = new PasswordSHA256Manager();
User user = new User("Bob", "Dylan", "bd@gmail.com", "bobby"); User user = new User("Bob", "Dylan", "bd@gmail.com", passwordManager.HashPassword("bobby"));
Assert.Equal("Bob", user.Name); Assert.Equal("Bob", user.Name);
Assert.Equal("Dylan", user.Surname); Assert.Equal("Dylan", user.Surname);
Assert.Equal("bd@gmail.com", user.Mail); Assert.Equal("bd@gmail.com", user.Mail);

@ -1,52 +1,74 @@
#if WINDOWS using Model;
using Microsoft.UI; using FakePersistance;
using Microsoft.UI.Windowing;
using Windows.Graphics;
#endif
using DataPersistence; using DataPersistence;
using Model; using Managers;
using System.Collections.ObjectModel; using System.Diagnostics;
using Model.Managers;
using Microsoft.Maui.Controls;
using System.Linq;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Views namespace Views
{ {
public partial class App : Application public partial class App : Application
{ {
//Point d'entrée de l'application /// <summary>
public MasterManager MasterMgr { get; private set; } = new MasterManager(new Stubs()); /// Master manager - access to the Model.
//L'utilisateur courant de l'application /// </summary>
public User CurrentUser { get; set; } public MasterManager Master { get; private set; }
private Recipe currentRecipe { get; set; }
public Recipe CurrentRecipe public App()
{ {
get => currentRecipe; Debug.WriteLine("Hello, World!\n\n");
set
string path = FileSystem.Current.AppDataDirectory; // - path to the save file
string strategy = "xml"; // - strategy is 'xml' or 'json' (/!\ this is case sensitive)
// Initialize the data serializer
IDataSerializer dataSerializer = (strategy == "xml") ?
new DataContractXML(path)
: new DataContractJSON(path);
// Initialize the data manager
IDataManager dataManager = (!File.Exists(Path.Combine(path, $"data.{strategy}"))) ?
new DataDefaultManager(new Stubs())
: new DataDefaultManager(dataSerializer);
// Initialize the other managers
IRecipeManager recipeManager = new RecipeDefaultManager(dataManager);
IPasswordManager passwordManager = new PasswordSHA256Manager();
IUserManager userManager = new UserDefaultManager(dataManager, passwordManager);
// Initialize the master manager
Master = new MasterManager(dataManager, recipeManager, userManager);
Master.Setup();
// Change the data serializer if the one in place is 'Stubs'
if (Master.Data.Serializer.GetType() == typeof(Stubs))
{ {
currentRecipe = value; var data = Master.Data.Data;
OnPropertyChanged(nameof(CurrentRecipe)); dataManager = new DataDefaultManager(dataSerializer, data);
Master = new MasterManager(dataManager, recipeManager, userManager);
} }
}
//collection de recette de l'application
public RecipeCollection AllRecipes { get; set; }
// Save data.
Debug.Write("[ --SAVE-- ]:\t");
Master.Data.SaveData();
Debug.WriteLine("Done.");
public App()
{
CurrentUser = MasterMgr.CurrentConnectedUser;
AllRecipes = MasterMgr.DataMgr.GetRecipes("All recipes");
CurrentRecipe = MasterMgr.DataMgr.GetRecipes().First();
InitializeComponent(); InitializeComponent();
UserAppTheme = AppTheme.Light; UserAppTheme = AppTheme.Light;
MainPage = new Home(); MainPage = new Home();
//MainPage = new MyPosts(); //MainPage = new MyPosts();
} }
protected override void OnSleep()
{
// Save data.
Debug.Write("[ --SAVE-- ]:\t");
Master.Data.SaveData();
Debug.WriteLine("Done.");
Debug.WriteLine(FileSystem.Current.AppDataDirectory);
base.OnSleep();
}
} }
} }

@ -1,5 +1,3 @@
using CommunityToolkit.Maui.Behaviors;
using DataPersistence;
using Model; using Model;
using Model.Managers; using Model.Managers;
using System.Diagnostics; using System.Diagnostics;
@ -9,7 +7,8 @@ namespace Views
{ {
public partial class AddRecipe : ContentPage public partial class AddRecipe : ContentPage
{ {
public MasterManager MasterMgr => (App.Current as App).MasterMgr; public MasterManager Master => (Application.Current as App).Master;
public List<Unit> UnitList { get; set; } = new List<Unit> { Unit.unit, Unit.kG, Unit.mG, Unit.G, Unit.L, Unit.cL, Unit.mL }; public List<Unit> UnitList { get; set; } = new List<Unit> { Unit.unit, Unit.kG, Unit.mG, Unit.G, Unit.L, Unit.cL, Unit.mL };
public bool IsCaptureSupported => throw new NotImplementedException(); public bool IsCaptureSupported => throw new NotImplementedException();

@ -1,89 +1,89 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:local="clr-namespace:Views" xmlns:local="clr-namespace:Views"
xmlns:model="clr-namespace:Model;assembly=Model" xmlns:model="clr-namespace:Model;assembly=Model"
x:Class="Views.Home" x:Class="Views.Home"
x:Name="homepage"> x:Name="homepage">
<local:ContainerBase <local:ContainerBase x:Name="container_base"
IsNotConnected="{Binding IsNotConnected, Source={x:Reference homepage}}" NeedReturn="False">
NeedReturn="{Binding NeedReturn, Source={x:Reference homepage}}">
<!-- Flyout -->
<!-- Flyout --> <local:ContainerBase.MyFlyoutContent>
<local:ContainerBase.MyFlyoutContent> <VerticalStackLayout Grid.Row="1">
<VerticalStackLayout Grid.Row="1"> <!-- Research -->
<!-- Research --> <Label
<Label Text="Recherche de recettes :" FontSize="14"
Text="Recherche de recettes :" FontSize="14" Margin="20, 10, 15, 0"/>
Margin="20, 10, 15, 0"/> <SearchBar
<SearchBar Placeholder="Mots-clés (ex.: rapide, fromage)"
Placeholder="Mots-clés (ex.: rapide, fromage)" TextColor="Black"
FontAttributes="Italic" TextColor="Black" BackgroundColor="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray300}}"
BackgroundColor="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray300}}" Margin="15, 10, 15, 40"
Margin="15, 10, 15, 40" SearchButtonPressed="SearchBar_SearchButtonPressed"/>
SearchButtonPressed="SearchBar_SearchButtonPressed"/>
<!-- Direct research -->
<!-- Direct research --> <Button
<Button Text="Toutes les recettes"
Text="Toutes les recettes" ImageSource="home_icon.png"
ImageSource="home_icon.png" Style="{StaticResource button1}"
Style="{StaticResource button1}" Clicked="AllRecipes_Clicked"/>
Clicked="AllRecipes_Clicked"/> <Button
<Button Text="Entrées"
Text="Entrées" ImageSource="flatware_icon.png"
ImageSource="flatware_icon.png" Style="{StaticResource button1}"
Style="{StaticResource button1}" Clicked="Entrees_Clicked"/>
Clicked="Entrees_Clicked"/> <Button
<Button Text="Plats"
Text="Plats" ImageSource="room_service_icon.png"
ImageSource="room_service_icon.png" Style="{StaticResource button1}"
Style="{StaticResource button1}" Clicked="Plats_Clicked"/>
Clicked="Plats_Clicked"/> <Button
<Button Text="Desserts"
Text="Desserts" ImageSource="coffee_icon.png"
ImageSource="coffee_icon.png" Style="{StaticResource button1}"
Style="{StaticResource button1}" Clicked="Desserts_Clicked"/>
Clicked="Desserts_Clicked"/> </VerticalStackLayout>
</VerticalStackLayout> </local:ContainerBase.MyFlyoutContent>
</local:ContainerBase.MyFlyoutContent>
<!-- Master -->
<!-- Master --> <local:ContainerBase.MyContent>
<local:ContainerBase.MyContent> <ScrollView>
<ScrollView> <StackLayout BindingContext="{Binding ., Source={x:Reference homepage}}"
<StackLayout BindingContext="{Binding RecipesDisplayed}" MinimumWidthRequest="400"> MinimumWidthRequest="400">
<!--Modification du prof apportée sur le stacklayout pour empecher l'affichage d'une seule case recipe--> <!--Modification du prof apportée sur le stacklayout pour empecher l'affichage d'une seule case recipe-->
<Label <Label
Text="{Binding Description}" Text="{Binding RecipesDisplayed.Description}"
TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}"
FontSize="24" FontSize="24"
Padding="15"/> Padding="15"/>
<FlexLayout <FlexLayout
Margin="0, 15" Margin="0, 15"
Wrap="Wrap" Wrap="Wrap"
JustifyContent="Start" JustifyContent="Start"
AlignItems="Center" AlignItems="Center"
AlignContent="SpaceEvenly" AlignContent="SpaceEvenly"
HorizontalOptions="Center" HorizontalOptions="Center"
BindableLayout.ItemsSource="{Binding}"> BindableLayout.ItemsSource="{Binding RecipesDisplayed}">
<BindableLayout.ItemTemplate> <BindableLayout.ItemTemplate>
<DataTemplate x:DataType="model:Recipe"> <DataTemplate x:DataType="model:Recipe">
<local:RecipeCase <local:RecipeCase
CaseImageSource="{Binding Image}" CaseImageSource="{Binding Image}"
RecipeTitle="{Binding Title}"/> RecipeTitle="{Binding Title}"/>
</DataTemplate> </DataTemplate>
</BindableLayout.ItemTemplate> </BindableLayout.ItemTemplate>
</FlexLayout> </FlexLayout>
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</local:ContainerBase.MyContent> </local:ContainerBase.MyContent>
</local:ContainerBase> </local:ContainerBase>
</ContentPage> </ContentPage>

@ -0,0 +1,80 @@
using Model;
using System.Collections.ObjectModel;
namespace Views
{
public partial class Home : ContentPage
{
public MasterManager Master => (Application.Current as App).Master;
private readonly RecipeCollection _recipesDisplayed;
public ReadOnlyObservableRecipeCollection RecipesDisplayed { get; private set; }
public string Description => _recipesDisplayed.Description;
public Home()
{
_recipesDisplayed = Master.Recipe.GetAllRecipes();
RecipesDisplayed = new ReadOnlyObservableRecipeCollection(_recipesDisplayed);
InitializeComponent();
BindingContext = this;
container_base.IsConnected = Master.User.CurrentConnected is not null;
}
private void ModifyRecipesDisplayed(RecipeCollection recipes)
{
_recipesDisplayed.Clear();
_recipesDisplayed.Description = recipes.Description;
foreach (Recipe recipe in recipes)
{
_recipesDisplayed.Add(recipe);
}
}
private void SearchBar_SearchButtonPressed(object sender, EventArgs e)
{
string searchStr = (sender as SearchBar).Text;
ModifyRecipesDisplayed(Master.Recipe.SearchRecipeByTitle(searchStr));
}
public void OnImageClicked(object sender, EventArgs e)
{
Master.Recipe.CurrentSelected = (Recipe)(sender as ImageButton).BindingContext;
Navigation.PushModalAsync(new ViewRecette());
}
private void Entrees_Clicked(object sender, EventArgs e)
{
ModifyRecipesDisplayed(new RecipeCollection("Entrées",
Master.Recipe.GetAllRecipes()
.ToList()
.FindAll(r => r.Type == RecipeType.Starter)
.ToArray()));
}
private void Plats_Clicked(object sender, EventArgs e)
{
ModifyRecipesDisplayed(new RecipeCollection("Plats",
Master.Recipe.GetAllRecipes()
.ToList()
.FindAll(r => r.Type == RecipeType.Dish)
.ToArray()));
}
private void Desserts_Clicked(object sender, EventArgs e)
{
ModifyRecipesDisplayed(new RecipeCollection("Desserts",
Master.Recipe.GetAllRecipes()
.ToList()
.FindAll(r => r.Type == RecipeType.Dessert)
.ToArray()));
}
private void AllRecipes_Clicked(object sender, EventArgs e)
{
ModifyRecipesDisplayed(Master.Recipe.GetAllRecipes());
}
}
}

@ -6,7 +6,7 @@
Title="MyPosts"> Title="MyPosts">
<local:ContainerBase <local:ContainerBase
IsNotConnected="False" IsConnected="False"
NeedReturn="True"> NeedReturn="True">
<local:ContainerBase.MyFlyoutContent> <local:ContainerBase.MyFlyoutContent>

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Views" xmlns:local="clr-namespace:Views"
xmlns:model="clr-namespace:Model;assembly=Model" xmlns:model="clr-namespace:Model;assembly=Model"
x:Class="Views.MyProfil" x:Class="Views.MyProfil"
Title="MyProfil"> Title="MyProfil">
<ContentPage.Resources> <ContentPage.Resources>
<local:EnumToValuesConverter x:Key="musicTypeToValueConverter" <local:EnumToValuesConverter x:Key="musicTypeToValueConverter"
x:TypeArguments="model:Priority"/> x:TypeArguments="model:Priority"/>
</ContentPage.Resources> </ContentPage.Resources>
<local:ContainerBase <local:ContainerBase
IsNotConnected="False" IsConnected="False"
NeedReturn="True"> NeedReturn="True">
<local:ContainerBase.MyFlyoutContent> <local:ContainerBase.MyFlyoutContent>
<Grid RowDefinitions="250, *, *" VerticalOptions="Fill"> <Grid RowDefinitions="250, *, *" VerticalOptions="Fill">
<VerticalStackLayout Grid.Row="1"> <VerticalStackLayout Grid.Row="1">
<Button Text="Mes Recettes" <Button Text="Mes Recettes"
ImageSource="person_default.png" ImageSource="person_default.png"
Style="{StaticResource button1}" Style="{StaticResource button1}"
@ -25,44 +25,44 @@
Style="{StaticResource button1}" Style="{StaticResource button1}"
Grid.Row="2" Grid.Row="2"
Clicked="OnAddRecipeClicked"/> Clicked="OnAddRecipeClicked"/>
</VerticalStackLayout> </VerticalStackLayout>
</Grid> </Grid>
</local:ContainerBase.MyFlyoutContent> </local:ContainerBase.MyFlyoutContent>
<local:ContainerBase.MyContent> <local:ContainerBase.MyContent>
<ScrollView> <ScrollView>
<StackLayout > <StackLayout >
<!--user's informations--> <!--user's informations-->
<Label Text="Mon profil" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}" <Label Text="Mon profil" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}"
FontAttributes="Bold" FontAttributes="Bold"
FontSize="24" Padding="15, 15, 20, 5"/> FontSize="24" Padding="15, 15, 20, 5"/>
<HorizontalStackLayout> <HorizontalStackLayout>
<VerticalStackLayout > <VerticalStackLayout >
<Label Text="Informations personnelles :" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}" <Label Text="Informations personnelles :" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}"
FontSize="20" Padding="15"/> FontSize="20" Padding="15"/>
<Label Text="Nom :" <Label Text="Nom :"
Padding="50,0,0,0" Padding="50,0,0,0"
FontSize="18"/> FontSize="18"/>
<Entry BackgroundColor="#D1E8E2" <Entry BackgroundColor="#D1E8E2"
Margin="50,10,0,20" Margin="50,10,0,20"
Text="{Binding CurrentUser.Name}"/> Text="{Binding CurrentUser.Name}"/>
<Label Text="Prénom :" <Label Text="Prénom :"
Padding="50,0,0,0" Padding="50,0,0,0"
FontSize="18"/> FontSize="18"/>
<Entry BackgroundColor="#D1E8E2" <Entry BackgroundColor="#D1E8E2"
Margin="50,10,0,20" Margin="50,10,0,20"
Text="{Binding CurrentUser.Surname} "/> Text="{Binding CurrentUser.Surname} "/>
<Label Text="Mail :" <Label Text="Mail :"
Padding="50,0,0,0" Padding="50,0,0,0"
FontSize="18"/> FontSize="18"/>
<Entry BackgroundColor="#D1E8E2" <Entry BackgroundColor="#D1E8E2"
Margin="50,10,0,20" Margin="50,10,0,20"
IsEnabled="False" IsEnabled="False"
Text="{Binding CurrentUser.Mail}"/> Text="{Binding CurrentUser.Mail}"/>
<!--liste drag and drop--> <!--liste drag and drop-->
</VerticalStackLayout> </VerticalStackLayout>
<VerticalStackLayout Padding="100,0,0,0"> <VerticalStackLayout Padding="100,0,0,0">
<Label Text="Priorités du compte : " TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}" <Label Text="Priorités du compte : " TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}"
FontSize="20" Padding="15"/> FontSize="20" Padding="15"/>
<FlexLayout BindableLayout.ItemsSource="{Binding PriorityList}" MinimumHeightRequest="80" <FlexLayout BindableLayout.ItemsSource="{Binding PriorityList}" MinimumHeightRequest="80"
BackgroundColor="{StaticResource Primary}" AlignItems="Center" Wrap="Wrap"> BackgroundColor="{StaticResource Primary}" AlignItems="Center" Wrap="Wrap">
<BindableLayout.ItemTemplate> <BindableLayout.ItemTemplate>
@ -77,10 +77,10 @@
</DataTemplate> </DataTemplate>
</BindableLayout.ItemTemplate> </BindableLayout.ItemTemplate>
</FlexLayout> </FlexLayout>
</VerticalStackLayout> </VerticalStackLayout>
</HorizontalStackLayout> </HorizontalStackLayout>
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</local:ContainerBase.MyContent> </local:ContainerBase.MyContent>
</local:ContainerBase> </local:ContainerBase>
</ContentPage> </ContentPage>

@ -0,0 +1,16 @@
using Model;
namespace Views;
public partial class MyProfil : ContentPage
{
public MasterManager Master => (Application.Current as App).Master;
public User user => Master.User.CurrentConnected;
public MyProfil()
{
InitializeComponent();
BindingContext = this;
}
}

@ -0,0 +1,19 @@
using Model;
namespace Views;
/// <summary>
/// Classe de la page contenant le detail de la recette
///
/// </summary>
public partial class ViewRecette : ContentPage
{
public MasterManager Master => (Application.Current as App).Master;
public User user => Master.User.CurrentConnected;
public Recipe Recipe => Master.Recipe.CurrentSelected;
public RecipeCollection AllRecipes => Master.Recipe.GetAllRecipes();
public ViewRecette()
{
InitializeComponent();
BindingContext = this;
}
}

@ -17,8 +17,7 @@
Grid.RowSpan="2" Grid.RowSpan="2"
MinimumWidthRequest="300" MinimumWidthRequest="300"
HorizontalOptions="StartAndExpand" HorizontalOptions="StartAndExpand"
IsNotConnected="{Binding IsNotConnected, Source={x:Reference root}}" x:Name="container_flayout">
NeedReturn="{Binding NeedReturn, Source={x:Reference root}}">
<local:ContainerFlyout.MyFlyoutContent> <local:ContainerFlyout.MyFlyoutContent>
<ContentView <ContentView
Content="{Binding MyFlyoutContent, Source={x:Reference root}}"/> Content="{Binding MyFlyoutContent, Source={x:Reference root}}"/>

@ -2,11 +2,25 @@ namespace Views;
public partial class ContainerBase : ContentView public partial class ContainerBase : ContentView
{ {
public bool IsConnected
{
get => container_flayout.IsConnected;
set => container_flayout.IsConnected = value;
}
public bool NeedReturn
{
get => container_flayout.NeedReturn;
set => container_flayout.NeedReturn = value;
}
public ContainerBase() public ContainerBase()
{ {
InitializeComponent(); InitializeComponent();
BindingContext = this;
} }
// Bind MyContent // Bind MyContent
public static readonly BindableProperty MyContentProperty = public static readonly BindableProperty MyContentProperty =
BindableProperty.Create("MyContent", typeof(View), typeof(ContainerBase), new Grid()); BindableProperty.Create("MyContent", typeof(View), typeof(ContainerBase), new Grid());
@ -26,24 +40,4 @@ public partial class ContainerBase : ContentView
get => (View)GetValue(MyFlyoutContentProperty); get => (View)GetValue(MyFlyoutContentProperty);
set => SetValue(MyFlyoutContentProperty, value); set => SetValue(MyFlyoutContentProperty, value);
} }
// Bind IsNotConnected
public static readonly BindableProperty IsNotConnectedProperty =
BindableProperty.Create("IsNotConnected", typeof(bool), typeof(Button), true);
public bool IsNotConnected
{
get => (bool)GetValue(IsNotConnectedProperty);
set => SetValue(IsNotConnectedProperty, value);
}
// bind NeedReturn
public static readonly BindableProperty NeedReturnProperty =
BindableProperty.Create("NeedReturn", typeof(bool), typeof(Border), false);
public bool NeedReturn
{
get => (bool)GetValue(NeedReturnProperty);
set => SetValue(NeedReturnProperty, value);
}
} }

@ -20,27 +20,29 @@
WidthRequest="100" HeightRequest="100" WidthRequest="100" HeightRequest="100"
CornerRadius="50" Margin="0, 30, 0, 10" CornerRadius="50" Margin="0, 30, 0, 10"
BorderWidth="5" BorderColor="Black" BorderWidth="5" BorderColor="Black"
IsEnabled="{Binding IsNotConnected, Source={x:Reference fl}}" IsVisible="{Binding IsConnected, Source={x:Reference fl}}"
Grid.RowSpan="2" Grid.RowSpan="2"
Clicked="ProfileButton_Clicked"/> Clicked="ProfileButton_Clicked"/>
</Grid> </Grid>
<!-- Connection button -->
<Button Text="Connection" ImageSource="login_icon.png" <Button Text="Connection" ImageSource="login_icon.png"
Style="{StaticResource button2}" Style="{StaticResource button2}"
IsVisible="{Binding IsNotConnected, Source={x:Reference fl}}" Margin="15, 120"
IsEnabled="{Binding IsNotConnected, Source={x:Reference fl}}" IsVisible="{Binding IsConnected, Converter={toolkit:InvertedBoolConverter}, Source={x:Reference fl}}"
Clicked="ConnectionButton_Clicked"/> Clicked="ConnectionButton_Clicked"/>
<StackLayout BindingContext="{Binding user}">
<!-- Display name -->
<StackLayout BindingContext="{Binding ConnectedUser}"
IsVisible="{Binding IsConnected, Source={x:Reference fl}}">
<Label Text="{Binding Name}" <Label Text="{Binding Name}"
HorizontalOptions="Center" Margin="0,15" HorizontalOptions="Center" Margin="0,15"
FontSize="20" FontAttributes="Bold" HorizontalTextAlignment="Center" FontSize="20" FontAttributes="Bold" HorizontalTextAlignment="Center"
TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}"/>
IsVisible="{Binding IsNotConnected, Converter={toolkit:InvertedBoolConverter} ,Source={x:Reference fl}}"/>
<Label Text="{Binding Surname}" <Label Text="{Binding Surname}"
HorizontalOptions="Center" HorizontalOptions="Center"
FontSize="20" FontAttributes="Bold" HorizontalTextAlignment="Center" FontSize="20" FontAttributes="Bold" HorizontalTextAlignment="Center"
TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}"/>
IsVisible="{Binding IsNotConnected, Converter={toolkit:InvertedBoolConverter} ,Source={x:Reference fl}}"/>
</StackLayout> </StackLayout>
</VerticalStackLayout> </VerticalStackLayout>
@ -56,7 +58,7 @@
<!-- Footer --> <!-- Footer -->
<Button Text="Déconnection" ImageSource="logout_icon.png" <Button Text="Déconnection" ImageSource="logout_icon.png"
Style="{StaticResource button2}" Style="{StaticResource button2}"
IsVisible="{Binding IsNotConnected, Converter={toolkit:InvertedBoolConverter}, Source={x:Reference fl}}"/> IsVisible="{Binding IsConnected, Source={x:Reference fl}}"/>
</VerticalStackLayout> </VerticalStackLayout>
</Grid> </Grid>

@ -1,61 +1,60 @@
using DataPersistence; using DataPersistence;
using Model; using Model;
using Model.Managers;
namespace Views;
namespace Views;
public partial class ContainerFlyout : ContentView
public partial class ContainerFlyout : ContentView {
{ public MasterManager Master => (Application.Current as App).Master;
public MasterManager MasterMgr => (App.Current as App).MasterMgr; public User ConnectedUser => Master.User.CurrentConnected;
public User user => (App.Current as App).CurrentUser;
public ContainerFlyout()
public ContainerFlyout() {
{
InitializeComponent(); InitializeComponent();
BindingContext = this; BindingContext = this;
}
}
#region Bindable XAML Properties
#region Bindable XAML Properties // Bind MyFlyoutContent
// Bind MyFlyoutContent public static readonly BindableProperty MyFlyoutContentProperty =
public static readonly BindableProperty MyFlyoutContentProperty = BindableProperty.Create("MyFlyoutContent", typeof(View), typeof(ContainerFlyout), new Grid());
BindableProperty.Create("MyFlyoutContent", typeof(View), typeof(ContainerFlyout), new Grid());
public View MyFlyoutContent
public View MyFlyoutContent {
{ get => (View)GetValue(MyFlyoutContentProperty);
get => (View)GetValue(MyFlyoutContentProperty); set => SetValue(MyFlyoutContentProperty, value);
set => SetValue(MyFlyoutContentProperty, value); }
}
// Bind IsNotConnected
// Bind IsNotConnected public static readonly BindableProperty IsConnectedProperty =
public static readonly BindableProperty IsNotConnectedProperty = BindableProperty.Create("IsConnected", typeof(bool), typeof(Button), true);
BindableProperty.Create("IsNotConnected", typeof(bool), typeof(Button), true);
public bool IsConnected
public bool IsNotConnected {
{ get => (bool)GetValue(IsConnectedProperty);
get => (bool)GetValue(IsNotConnectedProperty); set => SetValue(IsConnectedProperty, value);
set => SetValue(IsNotConnectedProperty, value); }
}
// bind NeedReturn
// bind NeedReturn public static readonly BindableProperty NeedReturnProperty =
public static readonly BindableProperty NeedReturnProperty = BindableProperty.Create("NeedReturn", typeof(bool), typeof(Border), false);
BindableProperty.Create("NeedReturn", typeof(bool), typeof(Border), false);
public bool NeedReturn
public bool NeedReturn {
{ get => (bool)GetValue(NeedReturnProperty);
get => (bool)GetValue(NeedReturnProperty); set => SetValue(NeedReturnProperty, value);
set => SetValue(NeedReturnProperty, value); }
} #endregion
#endregion
public async void ProfileButton_Clicked(object sender, EventArgs e)
public async void ProfileButton_Clicked(object sender, EventArgs e) {
{ await Navigation.PushModalAsync(new MyProfil());
await Navigation.PushModalAsync(new MyProfil()); }
}
public async void ConnectionButton_Clicked(object sender, EventArgs e)
public async void ConnectionButton_Clicked(object sender, EventArgs e) {
{ await Navigation.PushModalAsync(new Login());
await Navigation.PushModalAsync(new Login()); }
} }
}

@ -1,27 +1,27 @@
namespace Views; namespace Views;
public partial class MiniHeader : ContentView public partial class MiniHeader : ContentView
{ {
public MiniHeader() public MiniHeader()
{ {
InitializeComponent(); InitializeComponent();
} }
public static readonly BindableProperty TitleMiniProperty = public static readonly BindableProperty TitleMiniProperty =
BindableProperty.Create(nameof(TitleMini), typeof(string), typeof(Label), "Erreur de titre"); BindableProperty.Create(nameof(TitleMini), typeof(string), typeof(Label), "Erreur de titre");
public string TitleMini public string TitleMini
{ {
get => (string)GetValue(TitleMiniProperty); get => (string)GetValue(TitleMiniProperty);
set => SetValue(TitleMiniProperty, value); set => SetValue(TitleMiniProperty, value);
} }
// bind NeedReturn // bind NeedReturn
public static readonly BindableProperty NeedReturnProperty = public static readonly BindableProperty NeedReturnProperty =
BindableProperty.Create("NeedReturn", typeof(bool), typeof(Border), false); BindableProperty.Create("NeedReturn", typeof(bool), typeof(Border), false);
public bool NeedReturn public bool NeedReturn
{ {
get => (bool)GetValue(NeedReturnProperty); get => (bool)GetValue(NeedReturnProperty);
set => SetValue(NeedReturnProperty, value); set => SetValue(NeedReturnProperty, value);
} }
} }

@ -1,32 +1,32 @@
namespace Views; namespace Views;
public partial class RecipeCase : ContentView public partial class RecipeCase : ContentView
{ {
public RecipeCase() public RecipeCase()
{ {
InitializeComponent(); InitializeComponent();
} }
public static readonly BindableProperty CaseImageSourceProperty = public static readonly BindableProperty CaseImageSourceProperty =
BindableProperty.Create("CaseImageSource", typeof(ImageSource), typeof(Image)); BindableProperty.Create("CaseImageSource", typeof(ImageSource), typeof(Image));
public ImageSource CaseImageSource public ImageSource CaseImageSource
{ {
get => (ImageSource)GetValue(CaseImageSourceProperty); get => (ImageSource)GetValue(CaseImageSourceProperty);
set => SetValue(CaseImageSourceProperty, value); set => SetValue(CaseImageSourceProperty, value);
} }
public static readonly BindableProperty RecipeTitleProperty = public static readonly BindableProperty RecipeTitleProperty =
BindableProperty.Create("RecipeTitle", typeof(string), typeof(Label)); BindableProperty.Create("RecipeTitle", typeof(string), typeof(Label));
public string RecipeTitle public string RecipeTitle
{ {
get => (string)GetValue(RecipeTitleProperty); get => (string)GetValue(RecipeTitleProperty);
set => SetValue(RecipeTitleProperty, value); set => SetValue(RecipeTitleProperty, value);
} }
private async void ImageButton_Clicked(object sender, EventArgs e) private async void ImageButton_Clicked(object sender, EventArgs e)
{ {
await Navigation.PushModalAsync(new ViewRecette()); await Navigation.PushModalAsync(new ViewRecette());
} }
} }

@ -1,98 +0,0 @@
//using Android.Media;
using DataPersistence;
using Model;
using Model.Managers;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace Views
{
public partial class Home : ContentPage
{
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
public User? user => (App.Current as App).CurrentUser;
public RecipeCollection AllRecipe => (App.Current as App).AllRecipes;
private readonly RecipeCollection _recipesDisplayed;
public ReadOnlyObservableCollection<Recipe> RecipesDisplayed { get; private set; }
public static readonly BindableProperty IsNotConnectedProperty =
BindableProperty.Create("IsNotConnected", typeof(bool), typeof(bool));
public bool IsNotConnected
{
get => (bool)GetValue(IsNotConnectedProperty);
set => SetValue(IsNotConnectedProperty, value);
}
public static readonly BindableProperty NeedReturnProperty =
BindableProperty.Create("NeedReturn", typeof(bool), typeof(bool));
public bool NeedReturn
{
get => (bool)GetValue(NeedReturnProperty);
set => SetValue(NeedReturnProperty, value);
}
public Home()
{
_recipesDisplayed = (RecipeCollection)AllRecipe.Clone();
RecipesDisplayed = new ReadOnlyObservableCollection<Recipe>(_recipesDisplayed);
InitializeComponent();
BindingContext = this;
IsNotConnected = true;
NeedReturn = false;
}
public Home(RecipeCollection recipesDisplayed)
{
_recipesDisplayed = recipesDisplayed;
InitializeComponent();
BindingContext = this;
IsNotConnected = true;
NeedReturn = true;
}
private void ModifyRecipesDisplayed(RecipeCollection recipes)
{
_recipesDisplayed.Clear();
_recipesDisplayed.Description = recipes.Description;
foreach (Recipe recipe in recipes)
{
_recipesDisplayed.Add(recipe);
}
}
private void SearchBar_SearchButtonPressed(object sender, EventArgs e)
{
string searchStr = (sender as SearchBar).Text;
ModifyRecipesDisplayed(AllRecipe.ResearchByName(searchStr));
}
public void OnImageClicked(object sender, EventArgs e)
{
(App.Current as App).CurrentRecipe = (Recipe)(sender as ImageButton).BindingContext;
Navigation.PushModalAsync(new ViewRecette());
}
private void Entrees_Clicked(object sender, EventArgs e)
{
ModifyRecipesDisplayed(new RecipeCollection("Entrées", AllRecipe.ToList().FindAll(r => r.Type == RecipeType.Starter).ToArray()));
}
private void Plats_Clicked(object sender, EventArgs e)
{
ModifyRecipesDisplayed(new RecipeCollection("Plats", AllRecipe.ToList().FindAll(r => r.Type == RecipeType.Dish).ToArray()));
}
private void Desserts_Clicked(object sender, EventArgs e)
{
ModifyRecipesDisplayed(new RecipeCollection("Desserts", AllRecipe.ToList().FindAll(r => r.Type == RecipeType.Dessert).ToArray()));
}
private void AllRecipes_Clicked(object sender, EventArgs e)
{
ModifyRecipesDisplayed(AllRecipe);
}
}
}

@ -1,51 +0,0 @@
using CommunityToolkit.Maui.Behaviors;
using DataPersistence;
using Model;
using Model.Managers;
using System.Collections.ObjectModel;
using System.Diagnostics;
namespace Views;
public partial class MyProfil : ContentPage
{
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
public User CurrentUser => (App.Current as App).CurrentUser;
public MyProfil()
{
InitializeComponent();
BindingContext = this;
}
public ObservableCollection<Priority> PriorityList { get; private set; } = new ObservableCollection<Priority>()
{ Priority.Economic, Priority.Fast, Priority.Easy, Priority.Light, Priority.Gourmet };
void DragGestureRecognizer_DragStarting2(System.Object sender, Microsoft.Maui.Controls.DragStartingEventArgs e)
{
e.Data.Properties["value"] = (sender as Element).Parent.BindingContext;
}
void DropGestureRecognizer_Drop2(System.Object sender, Microsoft.Maui.Controls.DropEventArgs e)
{
var receivingElement = (Priority)((sender as Element).Parent.BindingContext);
var draggedElement = (Priority)e.Data.Properties["value"];
int draggedIndex = PriorityList.IndexOf(draggedElement);
PriorityList.RemoveAt(draggedIndex);
int receivingIndex = PriorityList.IndexOf(receivingElement);
PriorityList.Insert(receivingIndex + 1, draggedElement);
}
private void OnMyRecipeClicked(object sender, EventArgs e)
{
Navigation.PushModalAsync(new MyPosts());
}
private void OnAddRecipeClicked(object sender, EventArgs e)
{
Navigation.PushModalAsync(new AddRecipe());
}
}

@ -1,21 +0,0 @@
using Model.Managers;
using Model;
namespace Views;
/// <summary>
/// Classe de la page contenant le detail de la recette
///
/// </summary>
public partial class ViewRecette : ContentPage
{
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
public User user => (App.Current as App).CurrentUser;
public Recipe Recipe => (App.Current as App).CurrentRecipe;
public RecipeCollection AllRecipes => (App.Current as App).AllRecipes;
public ViewRecette()
{
InitializeComponent();
BindingContext = this;
}
}

@ -57,48 +57,52 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\DataPersistence\DataPersistence.csproj" /> <ProjectReference Include="..\AppException\AppException.csproj" />
<ProjectReference Include="..\Managers\Managers.csproj" />
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\Persistance\DataPersistence\DataPersistence.csproj" />
<ProjectReference Include="..\Persistance\FakePersistance\FakePersistance.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MauiXaml Update="AddRecipe.xaml"> <MauiXaml Update="ContentPages\AddRecipe.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="ContainerBase.xaml"> <MauiXaml Update="ContentViews\ContainerBase.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="ContainerFlyout.xaml"> <MauiXaml Update="ContentViews\ContainerFlyout.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="CustomHeader.xaml"> <MauiXaml Update="ContentViews\CustomHeader.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="Login.xaml"> <MauiXaml Update="ContentPages\Login.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="MiniHeader.xaml"> <MauiXaml Update="ContentViews\MiniHeader.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="MyPosts.xaml"> <MauiXaml Update="ContentPages\MyPosts.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="MyProfil.xaml"> <MauiXaml Update="ContentPages\MyProfil.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="RecipeCase.xaml"> <MauiXaml Update="ContentViews\RecipeCase.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="RecipeReviews.xaml"> <MauiXaml Update="ContentViews\RecipeReviews.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="ReturnButton.xaml"> <MauiXaml Update="ContentViews\ReturnButton.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="UserReview.xaml"> <MauiXaml Update="ContentPages\UserReview.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
<MauiXaml Update="ViewRecette.xaml"> <MauiXaml Update="ContentPages\ViewRecette.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>
</ItemGroup> </ItemGroup>

Loading…
Cancel
Save