Merge pull request 'Modèle version complète n°1 + Console' (#48) from feature/31-menu-console into dev
continuous-integration/drone/push Build is passing Details

Reviewed-on: #48
pull/49/head
Alexandre AGOSTINHO 2 years ago
commit cdaa2290fb

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

@ -5,7 +5,6 @@
<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>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

@ -0,0 +1,53 @@
using ConsoleApp.Menu.Core;
using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu
{
internal class AddRecipeMenu : Entry
{
MasterManager masterMgr;
public AddRecipeMenu(MasterManager masterManager)
: base("Add recipe",
new Entry.EntryStep("Title: ", typeof(string)),
new Entry.EntryStep("new step: ", typeof(string)),
new Entry.EntryStep("new step: ", typeof(string)),
new Entry.EntryStep("new step: ", typeof(string)),
new Entry.EntryStep("new step: ", typeof(string)))
{
masterMgr = masterManager;
}
public override IMenu? Return()
{
string title = _selectList[0].Item.Input;
int order = 1;
List<PreparationStep> steps = new List<PreparationStep>();
for (int i = 1; i <= 4; i++)
{
if (string.IsNullOrEmpty(_selectList[i].Item.Input))
continue;
steps.Add(new PreparationStep(order++, _selectList[i].Item.Input));
}
Recipe recipe = new Recipe(
title: title,
id: null,
authorMail: masterMgr.CurrentConnectedUser?.Mail,
picture: "",
ingredients: new List<Ingredient>(),
preparationSteps: steps.ToArray()
);
masterMgr.AddRecipe(recipe);
return null;
}
}
}

@ -0,0 +1,44 @@
using ConsoleApp.Menu.Core;
using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu
{
internal class AddUserMenu : Entry
{
MasterManager masterMgr;
public AddUserMenu(MasterManager masterManager)
: base("Add Manager",
new Entry.EntryStep("Mail: ", typeof(string)),
new Entry.EntryStep("Name: ", typeof(string)),
new Entry.EntryStep("Surname: ", typeof(string)),
new Entry.EntryStep("Password: ", typeof(string), true))
{
masterMgr = masterManager;
}
public override IMenu? Return()
{
string mail = _selectList[0].Item.Input;
string name = _selectList[1].Item.Input;
string surname = _selectList[2].Item.Input;
string passwd = _selectList[3].Item.Input;
User user = new User(
name: name,
surname: surname,
mail: mail,
password: passwd
);
masterMgr.Register(user);
return null;
}
}
}

@ -3,22 +3,48 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ConsoleApp.Menu.Core;
using Model.Managers;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
internal class ConnectionMenu : Entry internal class ConnectionMenu : Entry
{ {
public ConnectionMenu() private MasterManager _masterMgr;
private bool _wrongInput = false;
public ConnectionMenu(MasterManager masterManager)
: base("Connection", : base("Connection",
new Entry.EntryStep("Username: ", typeof(string)), new Entry.EntryStep("Mail: ", typeof(string)),
new Entry.EntryStep("Password: ", typeof(string))) new Entry.EntryStep("Password: ", typeof(string), true))
{ } {
_masterMgr = masterManager;
}
public override void Display()
{
base.Display();
if (_wrongInput)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Wrong input...");
Console.ResetColor();
}
}
public override IMenu? Return() public override IMenu? Return()
{ {
string username = _selectList[0].Item.Input; string mail = _selectList[0].Item.Input;
string password = _selectList[1].Item.Input; string password = _selectList[1].Item.Input;
return new PlainText($"User: {username} connected with password: {password}");
if (!_masterMgr.Login(mail, password))
{
_wrongInput = true;
return this;
}
else
return null;
} }
} }
} }

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu.Core
{ {
internal abstract partial class Entry internal abstract partial class Entry
{ {
@ -25,6 +25,11 @@ namespace ConsoleApp.Menu
/// Contain the input gave by the menu. /// Contain the input gave by the menu.
/// </summary> /// </summary>
public string Input { get; internal set; } public string Input { get; internal set; }
/// <summary>
/// Define whether the input need to be hidden. Useful for password.
/// </summary>
public bool Hidden { get; private set; }
#endregion #endregion
#region Constructors #region Constructors
@ -33,11 +38,12 @@ namespace ConsoleApp.Menu
/// </summary> /// </summary>
/// <param name="description">The text generally placed before the input in the menu.</param> /// <param name="description">The text generally placed before the input in the menu.</param>
/// <param name="type">The type of the returned input.</param> /// <param name="type">The type of the returned input.</param>
public EntryStep(string description, Type type) public EntryStep(string description, Type type, bool hidden = false)
{ {
Description = description; Description = description;
Input = ""; Input = "";
_entryType = type; _entryType = type;
Hidden = hidden;
} }
#endregion #endregion

@ -1,10 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ConsoleApp.Menu.Core;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu.Core
{ {
/// <summary> /// <summary>
/// Define an Entry menu. /// Define an Entry menu.
@ -22,7 +24,8 @@ namespace ConsoleApp.Menu
/// </summary> /// </summary>
/// <param name="title">The title of this menu.</param> /// <param name="title">The title of this menu.</param>
/// <param name="entrySteps">All the entries of this menu.</param> /// <param name="entrySteps">All the entries of this menu.</param>
protected Entry(string title, params EntryStep[] entrySteps) : base(title) protected Entry(string title, params EntryStep[] entrySteps)
: base(title)
{ {
_steps = entrySteps.ToList(); _steps = entrySteps.ToList();
_allSelectors = ConvertEntryStepsInSelector(); _allSelectors = ConvertEntryStepsInSelector();
@ -48,6 +51,11 @@ namespace ConsoleApp.Menu
if (!WriteMode && cki.Key == ConsoleKey.R) if (!WriteMode && cki.Key == ConsoleKey.R)
{ {
EnableWriteMode(); EnableWriteMode();
if (CurrentSelected is null)
return;
InputStr.Append(CurrentSelected.Input);
CurrentSelected.Input = "";
return; return;
} }
@ -64,9 +72,9 @@ namespace ConsoleApp.Menu
return; return;
} }
if (cki.Key == ConsoleKey.Backspace && InputStr.Length > 0) if (cki.Key == ConsoleKey.Backspace)
{ {
InputStr.Remove(InputStr.Length - 1, 1); if (InputStr.Length > 0) InputStr.Remove(InputStr.Length - 1, 1);
return; return;
} }
@ -86,6 +94,9 @@ namespace ConsoleApp.Menu
public override void Display() public override void Display()
{ {
StringBuilder displayItem = new StringBuilder();
_screenDisplay.Clear(); _screenDisplay.Clear();
Console.Clear(); Console.Clear();
@ -94,24 +105,45 @@ namespace ConsoleApp.Menu
for (int i = 0; i < _selectList.Count; i++) for (int i = 0; i < _selectList.Count; i++)
{ {
if (_selectList[i].Item.Hidden)
for (int _ = 0; _ < _selectList[i].Item.Input.Length; _++)
displayItem.Append('*');
else
displayItem.Append(_selectList[i].Item.Input);
if (CurrentLine == i) if (CurrentLine == i)
{
if (WriteMode)
_screenDisplay.Append($"W ");
else
_screenDisplay.Append($"> "); _screenDisplay.Append($"> ");
}
else else
_screenDisplay.Append($" "); _screenDisplay.Append($" ");
_screenDisplay.Append($"{_selectList[i].Line} {_selectList[i].Item.Input}"); _screenDisplay.Append($"{_selectList[i].Line} {displayItem}");
if (CurrentLine == i && WriteMode) if (CurrentLine == i && WriteMode)
{
if (_selectList[i].Item.Hidden)
for (int _ = 0; _ < InputStr.Length; _++) _screenDisplay.Append('*');
else
_screenDisplay.Append(InputStr); _screenDisplay.Append(InputStr);
}
_screenDisplay.AppendLine(); _screenDisplay.AppendLine();
displayItem.Clear();
} }
if (_selectList.Count == 0) if (_selectList.Count == 0)
_screenDisplay.AppendLine("Empty..."); _screenDisplay.AppendLine("Empty...");
_screenDisplay.AppendLine( _screenDisplay.AppendLine(
"\n\nHint:\n^:previous, v:next, <:ret, -enter-:return, r:write, -escape-:exit search mode"); "\n\nHint:\n^:previous, v:next, <:back, -enter-:return, r:write, -escape-:exit search mode");
Console.WriteLine(_screenDisplay); Console.WriteLine(_screenDisplay);
} }
#endregion #endregion

@ -5,7 +5,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu.Core
{ {
/// <summary> /// <summary>
/// Define a console menu with element selection. /// Define a console menu with element selection.

@ -7,7 +7,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu.Core
{ {
/// <summary> /// <summary>
/// Define a selection menu. /// Define a selection menu.
@ -127,9 +127,9 @@ namespace ConsoleApp.Menu
return; return;
} }
if (cki.Key == ConsoleKey.Backspace && InputStr.Length > 0) if (cki.Key == ConsoleKey.Backspace)
{ {
InputStr.Remove(InputStr.Length - 1, 1); if (InputStr.Length > 0) InputStr.Remove(InputStr.Length - 1, 1);
return; return;
} }
@ -177,7 +177,7 @@ namespace ConsoleApp.Menu
_screenDisplay.AppendLine("Empty..."); _screenDisplay.AppendLine("Empty...");
_screenDisplay.AppendLine( _screenDisplay.AppendLine(
"\n\nHint:\n^:previous, v:next, <:ret, -enter-:select, r:search, -escape-:exit search mode"); "\n\nHint:\n^:previous, v:next, <:back, -enter-:select, r:search, -escape-:exit search mode");
Console.WriteLine(_screenDisplay); Console.WriteLine(_screenDisplay);
} }

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu.Core
{ {
/// <summary> /// <summary>
/// Define a Plain text menu. /// Define a Plain text menu.
@ -25,8 +25,8 @@ namespace ConsoleApp.Menu
#endregion #endregion
#region IMenu implementation #region IMenu implementation
public IMenu? Return() { return null; } public virtual IMenu? Return() { return null; }
public void Display() public virtual void Display()
{ {
Console.Clear(); Console.Clear();
Console.WriteLine(InputStr); Console.WriteLine(InputStr);

@ -7,7 +7,7 @@ using System.Reflection.Emit;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu.Core
{ {
/// <summary> /// <summary>
/// The selector of a menu. /// The selector of a menu.
@ -22,7 +22,8 @@ namespace ConsoleApp.Menu
/// <summary> /// <summary>
/// The string that are displayed on the menu. /// The string that are displayed on the menu.
/// </summary> /// </summary>
public string Line { public string Line
{
get => _line; get => _line;
private set private set
{ {
@ -57,7 +58,7 @@ namespace ConsoleApp.Menu
{ {
if (other == null) return false; if (other == null) return false;
if (other == this) return true; if (other == this) return true;
return other.Line.Equals(this.Line); return other.Line.Equals(Line);
} }
public override bool Equals(object? obj) public override bool Equals(object? obj)

@ -0,0 +1,51 @@
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;
using DataPersistence;
namespace ConsoleApp.Menu
{
internal class ExportRecipeMenu : SearcherRecipe
{
public ExportRecipeMenu(MasterManager masterManager)
: base(masterManager)
{
}
public override IMenu? Return()
{
if (CurrentSelected is null)
throw new ArgumentNullException();
Recipe recipe = CurrentSelected;
string path = $"export_{string.Concat(CurrentSelected.Title.Where(c => !char.IsWhiteSpace(c)))}";
// -- trying to put the right extention by checking the type of the DataManager...
//if (object.ReferenceEquals(_masterMgr.DataMgr.GetType(), typeof(DataContractXML)))
// path += ".xml";
//else if (object.ReferenceEquals(_masterMgr.DataMgr.GetType(), typeof(DataContractJSON)))
// path += ".json";
path += ".xml";
try
{
_masterMgr.DataMgr.Export(recipe, path);
}
catch (ArgumentNullException e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("error: " + e.Message);
Console.ResetColor();
return this;
}
return null;
}
}
}

@ -0,0 +1,40 @@
using ConsoleApp.Menu.Core;
using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu
{
internal class ImportRecipeMenu : Entry
{
MasterManager masterMgr;
public ImportRecipeMenu(MasterManager masterManager)
: base("Import recipe",
new Entry.EntryStep("Path file: ", typeof(string)))
{
masterMgr = masterManager;
}
public override IMenu? Return()
{
string path = _selectList[0].Item.Input;
try
{
masterMgr.DataMgr.Import<Recipe>(path);
}
catch(ArgumentNullException e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("error: " + e.Message);
Console.ResetColor();
return this;
}
return null;
}
}
}

@ -0,0 +1,27 @@
using ConsoleApp.Menu.Core;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu
{
internal class LogoutButton : PlainText
{
MasterManager _masterMgr;
public LogoutButton(MasterManager masterManager)
: base("Logout ? ('ENTER' yes, '<' no)")
{
_masterMgr = masterManager;
}
public override IMenu? Return()
{
_masterMgr.Logout();
return base.Return();
}
}
}

@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ConsoleApp.Menu.Core;
using Model.Managers;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -13,12 +15,44 @@ namespace ConsoleApp.Menu
/// </summary> /// </summary>
internal class MainMenu : Menu<IMenu> internal class MainMenu : Menu<IMenu>
{ {
public MainMenu(DataManager dataMgr) private MasterManager _masterMgr;
: base("Main menu",
new Selector<IMenu>( public MainMenu(MasterManager masterManager)
new SearcherRecipe(new RecipeCollection("search", dataMgr.Data[nameof(Recipe)].Cast<Recipe>().ToArray())), "Recipe search"), : base("Main menu")
new Selector<IMenu>( {
new ConnectionMenu(), "Connection")) _masterMgr = masterManager;
{ }
_allSelectors.Add(
new Selector<IMenu>(new SearcherRecipe(_masterMgr), "Recipe search"));
_allSelectors.Add(
new Selector<IMenu>(new ConnectionMenu(_masterMgr), "Connection"));
_allSelectors.Add(
new Selector<IMenu>(new ProfileMenu(_masterMgr), "User profile"));
_allSelectors.Add(
new Selector<IMenu>(new LogoutButton(_masterMgr), "Logout"));
_allSelectors.Add(
new Selector<IMenu>(new AddRecipeMenu(_masterMgr), "Add recipe"));
_allSelectors.Add(
new Selector<IMenu>(new AddUserMenu(_masterMgr), "Add user"));
_allSelectors.Add(
new Selector<IMenu>(new ImportRecipeMenu(_masterMgr), "Import recipe"));
_allSelectors.Add(
new Selector<IMenu>(new ExportRecipeMenu(_masterMgr), "Export recipe"));
}
protected override List<Selector<IMenu>> SearchInSelection()
{
List<Selector<IMenu>> selectors = base.SearchInSelection();
if (_masterMgr.CurrentConnectedUser == null)
return selectors.Except(selectors.Where(s => s.Line == "User profile"))
.Except(selectors.Where(s => s.Line == "Logout"))
.Except(selectors.Where(s => s.Line == "Add recipe")).ToList();
else
return selectors.Except(selectors.Where(s => s.Line == "Connection")).ToList();
}
} }
} }

@ -0,0 +1,27 @@
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
{
internal class ProfileMenu : Menu<IMenu>
{
public ProfileMenu(MasterManager masterManager)
: base("Profile")
{
_allSelectors.Add(new Selector<IMenu>(
new ShowUserInfos(masterManager),
"My informations"));
_allSelectors.Add(new Selector<IMenu>(
new SearchUserRecipes(masterManager),
"My recipes"));
}
}
}

@ -0,0 +1,32 @@
using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu
{
internal class SearchUserRecipes : SearcherRecipe
{
public SearchUserRecipes(MasterManager masterManager) : base(masterManager)
{
}
public override void Update()
{
_recipeCollectionOnSearch = _masterMgr.GetCurrentUserRecipes();
_allSelectors = ConvertRecipeCollectionInSelectors();
_selectList = SearchInSelection();
if (_selectList.Count == 0)
{
CurrentSelected = default;
return;
}
CurrentSelected = _selectList[CurrentLine].Item;
}
}
}

@ -4,8 +4,9 @@ using System.Linq;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ConsoleApp.Menu.Core;
using Model; using Model;
using Model.Managers;
namespace ConsoleApp.Menu namespace ConsoleApp.Menu
{ {
@ -14,17 +15,16 @@ namespace ConsoleApp.Menu
/// </summary> /// </summary>
internal class SearcherRecipe : Menu<Recipe> internal class SearcherRecipe : Menu<Recipe>
{ {
private readonly RecipeCollection _recipeCollectionOnSearch; protected MasterManager _masterMgr;
protected RecipeCollection _recipeCollectionOnSearch = new RecipeCollection("search");
public SearcherRecipe(RecipeCollection recipeCollection) : base("Search recipe") public SearcherRecipe(MasterManager masterManager) : base("Search recipe")
{ {
_recipeCollectionOnSearch = recipeCollection; _masterMgr = masterManager;
_allSelectors = ConvertRecipeCollectionInSelectors();
_selectList = _allSelectors;
} }
#region Methods #region Methods
private List<Selector<Recipe>> ConvertRecipeCollectionInSelectors() protected List<Selector<Recipe>> ConvertRecipeCollectionInSelectors()
{ {
List<Selector<Recipe>> newSelectors = new List<Selector<Recipe>>(); List<Selector<Recipe>> newSelectors = new List<Selector<Recipe>>();
foreach (Recipe recipe in _recipeCollectionOnSearch) foreach (Recipe recipe in _recipeCollectionOnSearch)
@ -34,10 +34,17 @@ namespace ConsoleApp.Menu
return newSelectors; return newSelectors;
} }
public override void Update()
{
_recipeCollectionOnSearch = _masterMgr.DataMgr.GetRecipes("all recipes");
_allSelectors = ConvertRecipeCollectionInSelectors();
base.Update();
}
public override IMenu? Return() public override IMenu? Return()
{ {
if (CurrentSelected == null) if (CurrentSelected == null)
throw new ArgumentNullException("CurrentSelected"); return this;
return new PlainText(CurrentSelected.ToString()); return new PlainText(CurrentSelected.ToString());
} }

@ -0,0 +1,31 @@
using ConsoleApp.Menu.Core;
using Model;
using Model.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu
{
internal class ShowUserInfos : PlainText
{
private MasterManager _masterMgr;
public ShowUserInfos(MasterManager masterManager)
: base("")
{
_masterMgr = masterManager;
}
public override void Display()
{
Console.WriteLine(
$"\nUser: {_masterMgr.CurrentConnectedUser}\n\n"
+ $"\tMail: {_masterMgr.CurrentConnectedUser?.Mail}\n"
+ $"\tName: {_masterMgr.CurrentConnectedUser?.Name}\n"
+ $"\tSurname: {_masterMgr.CurrentConnectedUser?.Surname}\n");
}
}
}

@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ConsoleApp.Menu.Core;
using Model.Managers;
namespace ConsoleApp namespace ConsoleApp
{ {
@ -18,33 +20,33 @@ namespace ConsoleApp
/// <summary> /// <summary>
/// The manager that contains usefull data taken from the model. /// The manager that contains usefull data taken from the model.
/// </summary> /// </summary>
public DataManager DataManager { get; private set; } public MasterManager MasterMgr { get; private set; }
/// <summary> /// <summary>
/// Each menu called are push in this stack. Then, to return back, we pop this stack to retrive the previous menu. /// Each menu called are push in this stack. Then, to return back, we pop this stack to retrive the previous menu.
/// </summary> /// </summary>
public Stack<Menu.IMenu> MenuCallStack { get; set; } public Stack<IMenu> MenuCallStack { get; set; }
#endregion #endregion
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Constructor of the MenuManager class. This constructor allows you to give the first menu of the call stack, wich is usefull for testing. /// Constructor of the MenuManager class. This constructor allows you to give the first menu of the call stack, wich is usefull for testing.
/// </summary> /// </summary>
/// <param name="dataManager">The data manager needed by the menus inside.</param> /// <param name="masterManager">The data manager needed by the menus inside.</param>
/// <param name="firstMenu">The starting menu, the first that will be push on the call stack.</param> /// <param name="firstMenu">The starting menu, the first that will be push on the call stack.</param>
public MenuManager(DataManager dataManager, Menu.IMenu firstMenu) public MenuManager(MasterManager masterManager, IMenu firstMenu)
{ {
DataManager = dataManager; MasterMgr = masterManager;
MenuCallStack = new Stack<Menu.IMenu>(); MenuCallStack = new Stack<IMenu>();
MenuCallStack.Push(firstMenu); MenuCallStack.Push(firstMenu);
} }
/// <summary> /// <summary>
/// Constructor of the MenuManager class. /// Constructor of the MenuManager class.
/// </summary> /// </summary>
/// <param name="dataManager">The data manager needed by the menus inside.</param> /// <param name="masterManager">The data manager needed by the menus inside.</param>
public MenuManager(DataManager dataManager) : this(dataManager, new MainMenu(dataManager)) public MenuManager(MasterManager masterManager) : this(masterManager, new MainMenu(masterManager))
{ } { }
#endregion #endregion
@ -55,7 +57,7 @@ namespace ConsoleApp
public void Loop() public void Loop()
{ {
ConsoleKeyInfo cki; ConsoleKeyInfo cki;
Menu.IMenu menuOnHead; IMenu menuOnHead;
do do
{ {
menuOnHead = MenuCallStack.Peek(); menuOnHead = MenuCallStack.Peek();
@ -72,8 +74,9 @@ namespace ConsoleApp
menuOnHead.SelectPrevious(); menuOnHead.SelectPrevious();
break; break;
case ConsoleKey.Enter: case ConsoleKey.Enter:
Menu.IMenu? retMenu = menuOnHead.Return(); IMenu? retMenu = menuOnHead.Return();
if (retMenu is null) MenuCallStack.Pop(); if (retMenu is null) MenuCallStack.Pop();
else if (ReferenceEquals(retMenu, menuOnHead)) break;
else MenuCallStack.Push(retMenu); else MenuCallStack.Push(retMenu);
break; break;
case ConsoleKey.LeftArrow: case ConsoleKey.LeftArrow:

@ -1,48 +1,31 @@
// See https://aka.ms/new-console-template for more information using ConsoleApp;
using ConsoleApp;
using ConsoleApp.Menu;
using DataPersistence;
using Model; using Model;
using System.Linq; using DataPersistence;
using System.Text; using Model.Managers;
Console.WriteLine("Hello, World!\n\n"); 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)
// TESTS: MasterManager masterMgr;
DataManager dataMgr = new DataManager(new Stubs()); IDataManager dataManager = (strategy == "xml") ?
//DataManager dataMgr = new DataManager(new DataContractXML()); new DataContractXML(path)
//DataManager dataMgr = new DataManager(new DataContractJSON()); : new DataContractJSON(path);
dataMgr.Serializer = new DataContractXML();
//dataMgr.Serializer = new DataContractJSON();
// /!\ here is an absolute path I put for testing purpose. It will only work on my computer so don't forget to change it whene you test.
//dataMgr.Export(rc[2], "C:\\Users\\alex6\\Downloads\\recipe2.json");
//dataMgr.Import<Recipe>("C:\\Users\\alex6\\Downloads\\recipe2.json");
PasswordManager passwordManager = new PasswordManager();
//RecipeCollection rc = new RecipeCollection("All recipes", dataMgr.Data[nameof(Recipe)].Cast<Recipe>().ToArray());
RecipeCollection rc = dataMgr.GetRecipes("All recipes");
//RecipeCollection rc = new RecipeCollection("All recipes", dataMgr.GetFromData<Recipe>().ToArray());
User user = dataMgr.GetUsers().Last();
//rc[0].AddReview(new Review(user, 1, "bonne recette !1"));
//rc[0].AddReview(new Review(user, 1, "bonne recette !2"));
//rc[0].AddReview(new Review(user, 4, "bonne recette !3"));
//rc[0].AddReview(new Review(user, 5, "bonne recette !4"));
//rc[0].AddReview(new Review(user, 3, "bonne recette !5"));
//rc[0].AddReview(new Review(user, 2, "bonne recette !6"));
//rc[0].AddReview(new Review(user, 2, "peut etre pas ducoup !"));
//rc[1].AddReview(new Review(user, 2, "Mais celle-ci oui !"));
dataMgr.Save(); if (!File.Exists(Path.Combine(path, $"data.{strategy}")))
{
masterMgr = new MasterManager(new Stubs());
masterMgr.DataMgr.Serializer = dataManager;
}
else
{
masterMgr = new MasterManager(dataManager);
}
MenuManager menuMgr = new MenuManager(dataMgr);
MenuManager menuMgr = new MenuManager(masterMgr);
menuMgr.Loop(); menuMgr.Loop();
Console.WriteLine(passwordManager.VerifyPassword(user.Password, "pamigos")); // Save data.
Console.ReadKey(); Console.Write("[ --SAVE-- ]:\t"); masterMgr.DataMgr.Save(); Console.WriteLine("Done.");

@ -48,7 +48,8 @@ namespace DataPersistence
typeof(Review), typeof(Review),
typeof(User), typeof(User),
typeof(Ingredient), typeof(Ingredient),
typeof(Quantity) typeof(Quantity),
typeof(PasswordSHA256)
}, },
PreserveObjectReferences = true PreserveObjectReferences = true
}; };

@ -14,8 +14,6 @@ namespace DataPersistence
{ {
public Dictionary<string, List<object>> Load() public Dictionary<string, List<object>> Load()
{ {
PasswordManager passwordManager = new PasswordManager();
Dictionary<string, List<object>> data = new Dictionary<string, List<object>> Dictionary<string, List<object>> data = new Dictionary<string, List<object>>
{ {
{ {
@ -24,7 +22,10 @@ namespace DataPersistence
new List<object>(new[] new List<object>(new[]
{ {
new Recipe( new Recipe(
title: "Cookies classiques", id: null, title: "Cookies classiques",
id: 50,
authorMail: "admin@mctg.fr",
picture : "room_service_icon.png",
ingredients: new List<Ingredient>(new[] ingredients: new List<Ingredient>(new[]
{ {
new Ingredient("Patates", new Quantity(23, Unit.unit)), new Ingredient("Patates", new Quantity(23, Unit.unit)),
@ -36,6 +37,7 @@ namespace DataPersistence
new PreparationStep(2, "Manger.") new PreparationStep(2, "Manger.")
}), }),
new Recipe( new Recipe(
authorMail: "admin@mctg.fr",
title: "Cookies au chocolat", id: null, title: "Cookies au chocolat", id: null,
preparationSteps: new[] preparationSteps: new[]
{ {
@ -45,6 +47,7 @@ namespace DataPersistence
}), }),
new Recipe( new Recipe(
title: "Gateau nature", id: null, title: "Gateau nature", id: null,
authorMail: "admin@mctg.fr",
preparationSteps: new[] preparationSteps: new[]
{ {
new PreparationStep(1, "Achetez les ingrédients."), new PreparationStep(1, "Achetez les ingrédients."),
@ -53,6 +56,7 @@ namespace DataPersistence
}), }),
new Recipe( new Recipe(
title: "Gateau au pommes", id: null, title: "Gateau au pommes", id: null,
authorMail: "admin@mctg.fr",
preparationSteps: new[] preparationSteps: new[]
{ {
new PreparationStep(1, "Achetez les légumes."), new PreparationStep(1, "Achetez les légumes."),
@ -62,6 +66,7 @@ namespace DataPersistence
}), }),
new Recipe( new Recipe(
title: "Gateau au chocolat", id: null, title: "Gateau au chocolat", id: null,
authorMail: "pedrosamigos@hotmail.com",
preparationSteps: new[] preparationSteps: new[]
{ {
new PreparationStep(1, "Ajouter les oeufs."), new PreparationStep(1, "Ajouter les oeufs."),
@ -71,7 +76,9 @@ namespace DataPersistence
new PreparationStep(5, "Faire cuire 45h au four traditionnel.") new PreparationStep(5, "Faire cuire 45h au four traditionnel.")
}), }),
new Recipe( new Recipe(
title: "Dinde au jambon", id: null, title: "Dinde au jambon",
id: null,
authorMail: "pedrosamigos@hotmail.com",
preparationSteps: new[] preparationSteps: new[]
{ {
new PreparationStep(1, "Faire une cuisson bien sec de la dinde à la poêle"), new PreparationStep(1, "Faire une cuisson bien sec de la dinde à la poêle"),
@ -82,6 +89,7 @@ namespace DataPersistence
}), }),
new Recipe( new Recipe(
title: "Poulet au curry", id: null, title: "Poulet au curry", id: null,
authorMail: "pedrosamigos@hotmail.com",
preparationSteps: new[] preparationSteps: new[]
{ {
new PreparationStep(1, "Trouvez des épices de curry."), new PreparationStep(1, "Trouvez des épices de curry."),
@ -94,6 +102,7 @@ namespace DataPersistence
}) })
#endregion #endregion
}, },
{ {
#region Data: User #region Data: User
nameof(User), nameof(User),
@ -103,12 +112,13 @@ namespace DataPersistence
name: "Admin", name: "Admin",
surname: "Admin", surname: "Admin",
mail: "admin@mctg.fr", mail: "admin@mctg.fr",
password: passwordManager.HashPassword("admin")), password: "admin"),
new User( new User(
name: "Pedros", name: "Pedros",
surname: "Amigos", surname: "Amigos",
mail: "pedrosamigos@hotmail.com", mail: "pedrosamigos@hotmail.com",
password: passwordManager.HashPassword("pamigos")) password: "pamigos")
}) })
#endregion #endregion
} }

@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Model.Managers
{
/// <summary>
/// The Main manager of the model.
/// </summary>
public class MasterManager
{
#region Attributes & Properties
/// <summary>
/// The currently connected user. 'null' if no user is connected.
/// </summary>
public User? CurrentConnectedUser { get; private set; }
/// <summary>
/// The collection of all recipes loaded.
/// </summary>
public RecipeCollection Recipes { get; private set; }
/// <summary>
/// The collection of all users loaded.
/// </summary>
public List<User> Users { get; private set; }
/// <summary>
/// The data manager for load, save, export and import data.
/// </summary>
public DataManager DataMgr { get; private set; }
#endregion
#region Constructors
/// <summary>
/// Constructor of the MasterManager.
/// </summary>
/// <param name="dataManager">The serializer for the data.</param>
public MasterManager(IDataManager dataManager)
{
DataMgr = new DataManager(dataManager);
CurrentConnectedUser = null;
Recipes = DataMgr.GetRecipes("all recipes");
Users = DataMgr.GetUsers();
}
#endregion
#region Methods
/// <summary>
/// Log in an user. Test if the log in information are correct then connect the user.
/// </summary>
/// <param name="mail">The user's mail</param>
/// <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)
throw new ArgumentNullException("There is no users registred.");
if (mail == "admin")
{
CurrentConnectedUser = Users.FirstOrDefault(u => u.Mail == "admin@mctg.fr");
return true;
}
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;
}
/// <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().FindAll(r => r.AuthorMail == CurrentConnectedUser?.Mail).ToArray());
}
#endregion
}

@ -16,6 +16,9 @@ namespace Model
#region Attributes #region Attributes
[DataMember(Name = "title")] [DataMember(Name = "title")]
private string _title = ""; private string _title = "";
[DataMember(Name = "image")]
private string _image = "";
#endregion #endregion
#region Properties #region Properties
@ -32,10 +35,10 @@ namespace Model
public List<Review> Reviews { get; private set; } public List<Review> Reviews { get; private set; }
/// <summary> /// <summary>
/// Author of the recipe. /// AuthorMail's mail of the recipe.
/// </summary> /// </summary>
[DataMember(Name = "author")] [DataMember(Name = "authorMail")]
public User? Author { get; private set; } public string? AuthorMail { get; private set; }
/// <summary> /// <summary>
/// The Title of the recipe. <br/> /// The Title of the recipe. <br/>
@ -54,11 +57,26 @@ namespace Model
} }
/// <summary> /// <summary>
/// The image of the recipe. <br/>
/// Set to "room_service_icon.png" when the value passed is null, empty or contain white space.
/// </summary>
public string? Image
{
get => _image;
set
{
if (!string.IsNullOrWhiteSpace(value))
_image = "room_service_icon.png";
_image = value;
}
}
/// The list of ingredients. /// The list of ingredients.
/// </summary> /// </summary>
[DataMember(Name = "ingredient")] [DataMember(Name = "ingredient")]
public List<Ingredient> Ingredients { get; set; } public List<Ingredient> Ingredients { get; set; }
/// <summary> /// <summary>
/// The steps of the preparation. See: <see cref="PreparationStep"/>. /// The steps of the preparation. See: <see cref="PreparationStep"/>.
/// </summary> /// </summary>
@ -72,18 +90,21 @@ namespace Model
/// </summary> /// </summary>
/// <param _name="title">The title of the recipe</param> /// <param _name="title">The title of the 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="picture"> The image that represent the recipe</param>
/// <param _name="reviews">Thr list of reviews.</param> /// <param _name="reviews">Thr list of reviews.</param>
/// <param _name="ingredients">Thr list of ingredients.</param> /// <param _name="ingredients">Thr list of ingredients.</param>
/// <param _name="preparationSteps">The steps of the preparation of the meal</param> /// <param _name="preparationSteps">The steps of the preparation of the meal</param>
public Recipe(string title, int? id, User? author, public Recipe(string title, int? id, string? authorMail, string? picture,
List<Review> reviews, List<Ingredient> ingredients, List<Review> reviews, List<Ingredient> ingredients,
params PreparationStep[] preparationSteps) params PreparationStep[] preparationSteps)
{ {
Title = title; Title = title;
Image = picture;
PreparationSteps = new List<PreparationStep>(preparationSteps); PreparationSteps = new List<PreparationStep>(preparationSteps);
Ingredients = ingredients; Ingredients = ingredients;
Reviews = reviews; Reviews = reviews;
Author = author; AuthorMail = authorMail;
if (id == null) if (id == null)
{ {
@ -95,34 +116,18 @@ namespace Model
else Id = (int)id; else Id = (int)id;
} }
/// <summary>
/// <inheritdoc cref="Recipe.Recipe(string, int?, List{Review}, PreparationStep[])"/>
/// </summary>
/// <param _name="title">The title of the recipe.</param>
public Recipe(string title)
: this(title, null, null, new List<Review>(), new List<Ingredient>())
{
}
/// <summary>
/// <inheritdoc cref="Recipe.Recipe(string, int?, List{Review}, PreparationStep[])"/>
/// </summary>
/// <param _name="title">The title of the recipe.</param>
/// <param _name="preparationSteps">The steps of the preparation of the meal.</param>
public Recipe(string title, params PreparationStep[] preparationSteps)
: this(title, null, null, new List<Review>(), new List<Ingredient>(), preparationSteps)
{
}
/// <summary> /// <summary>
/// <inheritdoc cref="Recipe.Recipe(string, int?, List{Review}, PreparationStep[])"/> /// <inheritdoc cref="Recipe.Recipe(string, int?, List{Review}, PreparationStep[])"/>
/// </summary> /// </summary>
/// <param _name="title">The title of the recipe.</param> /// <param _name="title">The title of the 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">Mail of the user that create the recipe</param>
/// <param _name="preparationSteps">The steps of the preparation of the meal.</param> /// <param _name="preparationSteps">The steps of the preparation of the meal.</param>
public Recipe(string title, int? id, params PreparationStep[] preparationSteps) public Recipe(string title, int? id, string? authorMail, params PreparationStep[] preparationSteps)
: this(title, id, null, new List<Review>(), new List<Ingredient>(), preparationSteps) : this(title, id, authorMail, null, new List<Review>(), new List<Ingredient>(), preparationSteps)
{ {
} }
/// <summary> /// <summary>
@ -130,13 +135,27 @@ namespace Model
/// </summary> /// </summary>
/// <param _name="title">The title of the recipe.</param> /// <param _name="title">The title of the 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="ingredients">Thr list of ingredients.</param> /// <param _name="authorMail">Mail of the user that create the recipe</param>
/// <param _name="picture">Mail of the user that create the recipe</param>
/// <param _name="ingredients">List of ingredients that compose the recipe. </param>
/// <param _name="preparationSteps">The steps of the preparation of the meal.</param> /// <param _name="preparationSteps">The steps of the preparation of the meal.</param>
public Recipe(string title, int? id, List<Ingredient> ingredients, public Recipe(string title, int? id, string? authorMail, string? picture, List<Ingredient> ingredients, params PreparationStep[] preparationSteps)
params PreparationStep[] preparationSteps) : this(title, id, authorMail, picture, new List<Review>(), ingredients, preparationSteps)
: this(title, id, null, new List<Review>(), ingredients, preparationSteps)
{ {
} }
///// <summary>
///// <inheritdoc cref="Recipe.Recipe(string, int?, List{Review}, PreparationStep[])"/>
///// </summary>
///// <param _name="title">The title of the recipe.</param>
///// <param _name="id">The id of the recipe. If not given, get a new id.</param>
///// <param _name="picture">Image that reppresent the recipe.</param>
///// <param _name="preparationSteps">The steps of the preparation of the meal.</param>
//public Recipe(string title, int? id, string picture, params PreparationStep[] preparationSteps)
// : this(title, id, null, picture, new List<Review>(), new List<Ingredient>(), preparationSteps)
//{
//}
#endregion #endregion
#region Methods #region Methods
@ -211,7 +230,7 @@ namespace Model
sb.AppendLine(review.ToString()); sb.AppendLine(review.ToString());
} }
sb.AppendLine(); sb.AppendLine();
sb.AppendLine($"Posted by: {Author?.ToString()}"); sb.AppendLine($"Posted by: {AuthorMail?.ToString()}");
return sb.ToString(); return sb.ToString();
} }
#endregion #endregion

@ -1,4 +1,5 @@
using System; using Model.Managers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
@ -9,21 +10,34 @@ using System.Xml.Linq;
namespace Model namespace Model
{ {
/// <summary>
/// Define a Review of a recipe.
/// </summary>
[DataContract(Name = "review")] [DataContract(Name = "review")]
public class Review : IEquatable<Review> public class Review : IEquatable<Review>
{ {
#region Attributes & Properties
[DataMember(Name = "stars")] [DataMember(Name = "stars")]
private int _stars; private int _stars;
[DataMember(Name = "content")] [DataMember(Name = "content")]
private string _content = ""; private string _content = "";
/// <summary>
/// The Id of the review.
/// </summary>
[DataMember(Name = "id")] [DataMember(Name = "id")]
public int Id { get; init; } public int Id { get; init; }
[DataMember(Name = "user")] /// <summary>
public User Author { get; private set; } /// The mail of the author of the review.
/// </summary>
[DataMember(Name = "authorMail")]
public string AuthorMail { get; private set; }
/// <summary>
/// The number of stars the review give.
/// </summary>
public int Stars public int Stars
{ {
get => _stars; get => _stars;
@ -34,6 +48,9 @@ namespace Model
} }
} }
/// <summary>
/// The comment in the review.
/// </summary>
public string Content public string Content
{ {
get => _content; get => _content;
@ -43,8 +60,17 @@ namespace Model
else _content = value; else _content = value;
} }
} }
#endregion
public Review(User author, int? id, int stars, string content) #region Constructors
/// <summary>
/// Constructor of a review.
/// </summary>
/// <param name="authorMail">The review's author's mail.</param>
/// <param name="id">The id of the review.</param>
/// <param name="stars">The mark to give for the recipe.</param>
/// <param name="content">A comment about the recipe.</param>
public Review(string authorMail, int? id, int stars, string content)
{ {
if (id == null) if (id == null)
{ {
@ -55,25 +81,32 @@ namespace Model
} }
else Id = (int)id; else Id = (int)id;
Author = author; AuthorMail = authorMail;
Stars = stars; Stars = stars;
Content = content; Content = content;
} }
public Review(User author, int stars, string content) /// <summary>
: this(author, null, stars, content) /// <inheritdoc/>
/// </summary>
public Review(string authorMail, int stars, string content)
: this(authorMail, null, stars, content)
{ {
} }
/// <summary>
/// <inheritdoc/>
/// </summary>
public Review(int stars, string content) public Review(int stars, string content)
: this(new User("admin", "admin", "admin@mctg.fr", new PasswordManager().HashPassword("admin")), : this("admin@mctg.fr", null, stars, content)
null, stars, content)
{ {
} }
#endregion
#region Methods
public override string ToString() public override string ToString()
{ {
return $"{Author.Name} {Author.Surname}: [ {Stars} stars ]\n{Content}"; return $"{AuthorMail}: [ {Stars} stars ]\n{Content}";
} }
public bool Equals(Review? other) public bool Equals(Review? other)
@ -95,5 +128,6 @@ namespace Model
{ {
return Id.GetHashCode(); return Id.GetHashCode();
} }
#endregion
} }
} }

@ -8,8 +8,8 @@ namespace Model
{ {
public interface IPasswordManager public interface IPasswordManager
{ {
public int HashPassword(string password); public string HashPassword(string password);
public bool VerifyPassword(int hashedPassword,string password); public bool VerifyPassword(string hashedPassword,string password);
} }
} }

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
public class PasswordManager : IPasswordManager
{
public int HashPassword(string password)
{
int hashedPassword = password.GetHashCode();
return hashedPassword;
}
public bool VerifyPassword(int hashedPassword, string passwordEntered )
{
int passwordEnteredHashed = passwordEntered.GetHashCode();
if ( passwordEnteredHashed == hashedPassword)
return true;
else return false;
}
}
}

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
[DataContract(Name = "passmgr")]
public class PasswordSHA256 : IPasswordManager
{
public string HashPassword(string password)
{
byte[] data;
using (SHA256 sha256Hash = SHA256.Create())
data = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(password));
var sb = new StringBuilder();
foreach (byte b in data) sb.Append(b.ToString("x2"));
return sb.ToString();
}
public bool VerifyPassword(string hashedPassword, string passwordEntered)
{
string hashedInput = HashPassword(passwordEntered);
StringComparer strcmp = StringComparer.OrdinalIgnoreCase;
return strcmp.Compare(hashedPassword, hashedInput) == 0;
}
}
}

@ -1,12 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Text;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.ComponentModel;
namespace Model namespace Model
{ {
@ -15,7 +10,7 @@ namespace Model
/// This user can login with an Id and a password /// This user can login with an Id and a password
/// </summary> /// </summary>
[DataContract(Name = "user")] [DataContract(Name = "user")]
public class User : IEquatable<User> public class User : IEquatable<User> , INotifyPropertyChanged
{ {
#region Private Attributes #region Private Attributes
@ -23,8 +18,10 @@ namespace Model
[DataMember] private string surname=""; [DataMember] private string surname="";
[DataMember] private string mail = ""; [DataMember] private string mail = "";
[DataMember] private string picture = ""; [DataMember] private string picture = "";
[DataMember] private int password ; [DataMember] private string password = "";
[DataMember] private List<Priority> priorities; [DataMember] private List<Priority> priorities;
public event PropertyChangedEventHandler? PropertyChanged;
#endregion #endregion
#region Properties #region Properties
@ -36,13 +33,11 @@ namespace Model
public string Name public string Name
{ {
get { return name; } get { return name; }
private set set
{ {
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Impossible d'avoir un champ Nom vide!");
}
name = value; name = value;
OnPropertyChanged();
} }
} }
@ -53,13 +48,11 @@ namespace Model
public string Surname public string Surname
{ {
get { return surname; } get { return surname; }
private set set
{
if (string.IsNullOrWhiteSpace(value))
{ {
throw new ArgumentException("Impossible d'avoir un champ Prénom vide!");
}
surname = value; surname = value;
OnPropertyChanged();
} }
} }
@ -81,7 +74,7 @@ namespace Model
} }
} }
public int Password public string Password
{ {
get => password; get => password;
set => password = value; set => password = value;
@ -129,23 +122,41 @@ namespace Model
throw new NotImplementedException(); throw new NotImplementedException();
} }
#endregion
protected void OnPropertyChanged ([CallerMemberName] string? propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{
return $"{Name} {Surname}";
}
[DataMember(Name = "passmgr")]
public IPasswordManager psswMgr { get; private set; }
#endregion
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Construtors of user. /// Construtors of user.
/// </summary> /// </summary>
/// <param _name="name">The _name of the user</param> /// <param name="name">The name of the user</param>
/// <param _name="surname">The surname of the user</param> /// <param name="surname">The surname of the user</param>
/// <param _name="mail">The user needs an email to login. </param> /// <param name="mail">The user needs an email to login.</param>
public User(string name, string surname, string mail, int password) /// <param name="password">The password of the new user.</param>
/// <param name="passwordManager">The password manager to manage the user password.</param>
public User(string name, string surname, string mail, string password, IPasswordManager passwordManager)
{ {
Name = name; Name = name;
Surname = surname; Surname = surname;
Mail = mail; Mail = mail;
Password = password; psswMgr = passwordManager;
Password = psswMgr.HashPassword(password);
priorities = new List<Priority> { priorities = new List<Priority> {
Priority.Gourmet, Priority.Gourmet,
Priority.Economic, Priority.Economic,
@ -156,10 +167,39 @@ namespace Model
} }
/// <summary>
/// <inheritdoc cref="User.User"/>
/// </summary>
public User(string name, string surname, string mail, string password)
: this(name, surname,mail, password, new PasswordSHA256())
{
}
#endregion /// <summary>
/// <inheritdoc cref="User.User"/>
/// </summary>
public User()
: 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
} }
} }

@ -3,8 +3,9 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using DataPersistence;
using Model; using Model;
using Model.Managers;
namespace Model_UnitTests namespace Model_UnitTests
{ {
@ -13,18 +14,12 @@ namespace Model_UnitTests
[Fact] [Fact]
public void TestResearchByName() public void TestResearchByName()
{ {
RecipeCollection recipes = new RecipeCollection( MasterManager masterManager = new MasterManager(new Stubs());
description: "test recipe", RecipeCollection recipes = masterManager.DataMgr.GetRecipes("test rc");
recipes: new[]
{
new Recipe(title: "Gateau à la crème"),
new Recipe(title: "Gateau au chocolat"),
new Recipe(title: "Gateau aux cerises")
});
Recipe? search_result = recipes.ResearchByName("chocolat").FirstOrDefault(); Recipe? search_result = recipes.ResearchByName("chocolat").FirstOrDefault();
Assert.NotNull(search_result); Assert.NotNull(search_result);
Assert.Equal("Gateau au chocolat", search_result.Title); Assert.Equal("Cookies au chocolat", search_result.Title);
} }
} }
} }

@ -7,7 +7,10 @@ namespace Model_UnitTests
[Fact] [Fact]
public void TestVoidConstructor() public void TestVoidConstructor()
{ {
Recipe r = new Recipe(""); // id is given to avoid tests errors with the static atrribute 'idCreator'. Recipe r = new Recipe(
title: "test recipe",
id: null,
authorMail: "test@test.fr");
Assert.NotNull(r.Title); Assert.NotNull(r.Title);
} }
} }

@ -12,8 +12,8 @@ namespace Model_UnitTests
[Fact] [Fact]
public void TestConstructUser() public void TestConstructUser()
{ {
PasswordManager passwordManager = new PasswordManager(); PasswordSHA256 passwordManager = new PasswordSHA256();
User user = new User("Bob", "Dylan", "bd@gmail.com", passwordManager.HashPassword("bobby")); User user = new User("Bob", "Dylan", "bd@gmail.com", "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);

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Views.AddRecipe"
Title="AddRecipe"
xmlns:local="clr-namespace:Views">
<VerticalStackLayout>
<local:MiniHeader
TitleMini="Ajouter une recette"
NeedReturn="True"
HeightRequest="100"/>
<Grid ColumnDefinitions="auto, *"
RowDefinitions="auto,auto,auto,auto,auto,auto, auto, auto, auto"
Margin="50,20,20,20">
<Label Text="Titre de la recette :"/>
<Entry Placeholder="Saisie du texte de la recette correspondante"
Grid.Row="1"
Margin="10"/>
<Label Text="Type de la recette" Grid.Row="2"/>
<CheckBox x:Name="CheckEntree" Grid.Row="3" Margin="10,0,20,0" />
<Label Text="Entrée" Grid.Row="3" Margin="40,20"/>
<CheckBox x:Name="CheckPlat" Grid.Row="3" Margin="90,0" />
<Label Text="Plat" Grid.Row="3" Margin="120,20"/>
<CheckBox x:Name="CheckDessert" Grid.Row="3" Margin="155,0" />
<Label Text="Dessert" Grid.Row="3" Margin="185,20"/>
<Label Text="Type de priorité" Grid.Row="4"/>
<Grid BackgroundColor="#D1E8E2"
MinimumHeightRequest="100"
MaximumWidthRequest="300"
Padding="20"
Grid.Row="5">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Text="Recettes économiques" Grid.Row="0" Padding="5,0,0,0"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="1" />
<Label Text="Recettes rapides" Grid.Row="2"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="3" />
<Label Text="Recettes simples" Grid.Row="4"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="5" />
<Label Text="Recettes légères" Grid.Row="6"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="7" />
<Label Text="Recettes gourmandes" Grid.Row="8"/>
</Grid>
<Label Text="Saisir les étapes de la recette " Grid.Row="6" Margin="0,15"/>
<Entry Placeholder="Etape de la recette" Grid.Row="7" Margin="12,0"/>
<HorizontalStackLayout Grid.Row="8" Margin="20">
<Button WidthRequest="100" Text="Précédent" TextColor="Black" Margin="20,0,20,0"/>
<Button WidthRequest="100" Text="Ajouter" TextColor="Black" Margin="20,0"/>
</HorizontalStackLayout>
<Label Text="Saisir les ingrédients de la recette" Grid.Row="6" Grid.Column="1" Margin="50,15"/>
<HorizontalStackLayout Grid.Row="7" Grid.Column="1">
<Entry Placeholder="Nom de l'ingrédient" Margin="12,0,50,0" WidthRequest="500"/>
<Picker Title="Unité">
</Picker>
</HorizontalStackLayout>
<HorizontalStackLayout Grid.Row="8" Grid.Column="1" Margin="20">
<Button WidthRequest="100" Text="Précédent" TextColor="Black" Margin="20,0,20,0"/>
<Button WidthRequest="100" Text="Ajouter" TextColor="Black" Margin="20,0"/>
</HorizontalStackLayout>
</Grid>
</VerticalStackLayout>
</ContentPage>

@ -0,0 +1,18 @@
using CommunityToolkit.Maui.Behaviors;
using DataPersistence;
using Model;
using Model.Managers;
using System.Diagnostics;
namespace Views
{
public partial class AddRecipe : ContentPage
{
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
public AddRecipe()
{
InitializeComponent();
}
}
}

@ -1,7 +1,7 @@
<?xml version = "1.0" encoding = "UTF-8" ?> <?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui" <Application 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:Vue" xmlns:local="clr-namespace:Views"
x:Class="Views.App"> x:Class="Views.App">
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>

@ -4,34 +4,51 @@ using Microsoft.UI.Windowing;
using Windows.Graphics; using Windows.Graphics;
#endif #endif
using DataPersistence;
using Model;
using System.Collections.ObjectModel;
using Model.Managers;
namespace Views namespace Views
{ {
public partial class App : Application public partial class App : Application
{ {
const int WindowWidth = 1200; //Point d'entrée de l'application
const int WindowHeight = 800; public MasterManager MasterMgr { get; private set; } = new MasterManager(new Stubs());
//L'utilisateur courant de l'application
public User CurrentUser { get; set; }
//collection de recette de l'application
public RecipeCollection AllRecipes { get; set; }
//const int WindowWidth = 1200;
//const int WindowHeight = 800;
public App() public App()
{ {
CurrentUser = MasterMgr.DataMgr.GetUsers().Last();
AllRecipes = MasterMgr.DataMgr.GetRecipes("All recipes");
InitializeComponent(); InitializeComponent();
Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) => // Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
{ // {
#if WINDOWS //#if WINDOWS
var mauiWindow = handler.VirtualView; // var mauiWindow = handler.VirtualView;
var nativeWindow = handler.PlatformView; // var nativeWindow = handler.PlatformView;
nativeWindow.Activate(); // nativeWindow.Activate();
IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow); // IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle); // WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId); // AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
appWindow.Resize(new SizeInt32(WindowWidth, WindowHeight)); // appWindow.Resize(new SizeInt32(WindowWidth, WindowHeight));
#endif //#endif
}); // });
/* - Comment(ctrl-k + ctrl-c)/Uncomment(ctrl-k + ctrl-u) to change page - */ /* - Comment(ctrl-k + ctrl-c)/Uncomment(ctrl-k + ctrl-u) to change page - */
UserAppTheme = AppTheme.Light; UserAppTheme = AppTheme.Light;
MainPage = new MyProfil(); MainPage = new Home();
//MainPage = new MyPosts(); //MainPage = new MyPosts();
} }
} }

@ -28,11 +28,19 @@
Style="{StaticResource button2}" Style="{StaticResource button2}"
IsVisible="{Binding IsNotConnected, Source={x:Reference fl}}" IsVisible="{Binding IsNotConnected, Source={x:Reference fl}}"
IsEnabled="{Binding IsNotConnected, Source={x:Reference fl}}"/> IsEnabled="{Binding IsNotConnected, Source={x:Reference fl}}"/>
<Label Text="Jean-Baptiste De La Fontaine" <StackLayout BindingContext="{Binding user}">
HorizontalOptions="Center" Margin="15" <Label Text="{Binding Name}"
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}}"/> IsVisible="{Binding IsNotConnected, Converter={toolkit:InvertedBoolConverter} ,Source={x:Reference fl}}"/>
<Label Text="{Binding Surname}"
HorizontalOptions="Center"
FontSize="20" FontAttributes="Bold" HorizontalTextAlignment="Center"
TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}"
IsVisible="{Binding IsNotConnected, Converter={toolkit:InvertedBoolConverter} ,Source={x:Reference fl}}"/>
</StackLayout>
</VerticalStackLayout> </VerticalStackLayout>

@ -1,10 +1,20 @@
using DataPersistence;
using Model;
using Model.Managers;
namespace Views; namespace Views;
public partial class ContainerFlyout : ContentView public partial class ContainerFlyout : ContentView
{ {
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
public User user => (App.Current as App).CurrentUser;
public ContainerFlyout() public ContainerFlyout()
{ {
InitializeComponent(); InitializeComponent();
BindingContext = this;
} }
// Bind MyFlyoutContent // Bind MyFlyoutContent

@ -3,6 +3,7 @@
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"
x:Class="Views.Home"> x:Class="Views.Home">
<local:ContainerBase <local:ContainerBase
@ -12,19 +13,29 @@
<local:ContainerBase.MyFlyoutContent> <local:ContainerBase.MyFlyoutContent>
<VerticalStackLayout Grid.Row="1"> <VerticalStackLayout Grid.Row="1">
<!-- Research --> <!-- Research -->
<Button Text="Recherche" ImageSource="search_icon.png" <Button
Text="Recherche"
ImageSource="search_icon.png"
MaximumHeightRequest="20" MaximumHeightRequest="20"
Style="{StaticResource button1}"/> Style="{StaticResource button1}"/>
<SearchBar Placeholder="Mots-clés (ex.: rapide, fromage)" FontAttributes="Italic" TextColor="Black" <SearchBar
Placeholder="Mots-clés (ex.: rapide, fromage)"
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"/>
<!-- Direct research --> <!-- Direct research -->
<Button Text="Entrées" ImageSource="flatware_icon.png" <Button
Text="Entrées"
ImageSource="flatware_icon.png"
Style="{StaticResource button1}"/> Style="{StaticResource button1}"/>
<Button Text="Plats" ImageSource="room_service_icon.png" <Button
Text="Plats"
ImageSource="room_service_icon.png"
Style="{StaticResource button1}"/> Style="{StaticResource button1}"/>
<Button Text="Desserts" ImageSource="coffee_icon.png" <Button
Text="Desserts"
ImageSource="coffee_icon.png"
Style="{StaticResource button1}"/> Style="{StaticResource button1}"/>
</VerticalStackLayout> </VerticalStackLayout>
</local:ContainerBase.MyFlyoutContent> </local:ContainerBase.MyFlyoutContent>
@ -32,9 +43,13 @@
<!-- Master --> <!-- Master -->
<local:ContainerBase.MyContent> <local:ContainerBase.MyContent>
<ScrollView> <ScrollView>
<StackLayout> <StackLayout BindingContext="{Binding AllRecipes}" MinimumWidthRequest="400">
<Label Text="Suggestions" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}" <!--Modification du prof apportée sur le stacklayout pour empecher l'affichage d'une seule case recipe-->
FontSize="24" Padding="15"/> <Label
Text="{Binding Description}"
TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}"
FontSize="24"
Padding="15"/>
<FlexLayout <FlexLayout
Margin="0, 15" Margin="0, 15"
@ -42,8 +57,35 @@
JustifyContent="Start" JustifyContent="Start"
AlignItems="Center" AlignItems="Center"
AlignContent="SpaceEvenly" AlignContent="SpaceEvenly"
HorizontalOptions="Center"> HorizontalOptions="Center"
BindableLayout.ItemsSource="{Binding}">
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="model:Recipe">
<Border Style="{StaticResource recipeCase}">
<Grid RowDefinitions="*, 40">
<!--<local:RecipeCase
CaseImageSource="room_service_icon.png"
Title="{Binding Title}"/>-->
<Image
Grid.Row="0" VerticalOptions="Fill"
Source="{Binding Image}"/>
<Label
Text="{Binding Title}" FontSize="18"
Grid.Row="1" HorizontalOptions="Center"/>
</Grid>
</Border>
</DataTemplate>
</BindableLayout.ItemTemplate>
<!--<local:RecipeCase CaseImageSource="room_service_icon.png"/>
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <local:RecipeCase CaseImageSource="room_service_icon.png"/>
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <local:RecipeCase CaseImageSource="room_service_icon.png"/>
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <local:RecipeCase CaseImageSource="room_service_icon.png"/>
@ -53,8 +95,7 @@
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <local:RecipeCase CaseImageSource="room_service_icon.png"/>
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <local:RecipeCase CaseImageSource="room_service_icon.png"/>
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <local:RecipeCase CaseImageSource="room_service_icon.png"/>
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <local:RecipeCase CaseImageSource="room_service_icon.png"/>-->
<local:RecipeCase CaseImageSource="room_service_icon.png"/>
</FlexLayout> </FlexLayout>
</StackLayout> </StackLayout>

@ -1,10 +1,22 @@
namespace Views using DataPersistence;
using Model;
using Model.Managers;
namespace Views
{ {
public partial class Home : ContentPage public partial class Home : ContentPage
{ {
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
public User user => (App.Current as App).CurrentUser;
public RecipeCollection AllRecipes => (App.Current as App).AllRecipes;
public Home() public Home()
{ {
//DataMgr = new DataManager(new Stubs());
//AllRecipes = new RecipeCollection("Toutes les recettes", DataMgr.Data[nameof(Recipe)].Cast<Recipe>().ToArray());
InitializeComponent(); InitializeComponent();
BindingContext = this;
} }
} }
} }

@ -14,8 +14,8 @@
<Grid RowDefinitions="250, *, *" VerticalOptions="Fill"> <Grid RowDefinitions="250, *, *" VerticalOptions="Fill">
<VerticalStackLayout Grid.Row="1"> <VerticalStackLayout Grid.Row="1">
<Button Text="Mes informations" ImageSource="person_default.png" Style="{StaticResource button1}" Grid.Row="1"/> <Button Text="Mes Recettes" ImageSource="person_default.png" Style="{StaticResource button1}" Grid.Row="1"/>
<Button Text="Modifier" ImageSource="settings_icon.png" Style="{StaticResource button1}" Grid.Row="2"/> <Button Text="Ajouter Recette" ImageSource="settings_icon.png" Style="{StaticResource button1}" Grid.Row="2"/>
</VerticalStackLayout> </VerticalStackLayout>
</Grid> </Grid>
@ -24,7 +24,8 @@
<local:ContainerBase.MyContent> <local:ContainerBase.MyContent>
<ScrollView> <ScrollView>
<StackLayout BindingContext="User"><!--Attention debut de binding--> <StackLayout >
<!--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"/>
@ -36,30 +37,22 @@
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}"/>
<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} "/>
<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"
<Label Text="Pseudo :" IsEnabled="False"
Padding="50,0,0,0" Text="{Binding CurrentUser.Mail}"/>
FontSize="18"/> <!--liste drag and drop-->
<Entry BackgroundColor="#D1E8E2"
Margin="50,10,0,50"/>
<Button BackgroundColor="#bdf5bd"
Text="Valider"
Margin="40,0,0,0"
TextColor="Black"
MaximumWidthRequest="100"/>
</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}}"
@ -91,20 +84,10 @@
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="7" /> <BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="7" />
<Label Text="Recettes gourmandes" Grid.Row="8"/> <Label Text="Recettes gourmandes" Grid.Row="8"/>
</Grid> </Grid>
</VerticalStackLayout> </VerticalStackLayout>
</HorizontalStackLayout> </HorizontalStackLayout>
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</local:ContainerBase.MyContent> </local:ContainerBase.MyContent>
</local:ContainerBase> </local:ContainerBase>
</ContentPage> </ContentPage>

@ -1,9 +1,20 @@
using CommunityToolkit.Maui.Behaviors;
using DataPersistence;
using Model;
using Model.Managers;
using System.Diagnostics;
namespace Views; namespace Views;
public partial class MyProfil : ContentPage public partial class MyProfil : ContentPage
{ {
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
public User user => (App.Current as App).CurrentUser;
public MyProfil() public MyProfil()
{ {
InitializeComponent(); InitializeComponent();
BindingContext = this;
} }
} }

@ -57,10 +57,14 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\DataPersistence\DataPersistence.csproj" />
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MauiXaml Update="AddRecipe.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="ContainerBase.xaml"> <MauiXaml Update="ContainerBase.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>

@ -9,4 +9,23 @@
# SAE 2.01 - Développement d'une application # SAE 2.01 - Développement d'une application
## Ma Cuisine Trop Géniale ! - Application MAUI ### Ma Cuisine Trop Géniale ! - Application MAUI
<br>
---
## Documentation
La conception et les diagrammes concernant l'architecture du projet sont disponible dans [le wiki](https://codefirst.iut.uca.fr/git/alexandre.agostinho/SAE-2.01/wiki/).
---
## Tests fonctionnels
Navigation dans les menus de l'application console :
- ` ^ ` *(fleche haute)* : selection précédante,
- ` v ` *(fleche basse)* : selection suivente,
- ` < ` *(fleche gauche)* : retour arrière,
- ` <enter> ` *(touche entrée)* : entrer dans la séléction / valider,
- ` r ` *(touche 'r')* : **activer le mode écriture**: rechercher dans les sélections / mettre du texte dans les zones de textes,
- ` <echap> ` *(touche echap)* : **désactiver le mode écriture** / **enregistrer le texte dans la zone de texte**.
⚠️ La navigation dans les menus de l'application console est assez spéciale. Elle est plutot complexe et surtout très mal optimisée (comme ce n'est que pour tester). Par exemple, pour entrer du texte dans un champ de texte : il faut activer le **mode écriture** avec la touche `r`, entrer son texte, **PUIS désactiver le mode écriture** avec la touche `<echap>`. Cette dernière étape permet d'enregistrer le texte dans le champ.
Loading…
Cancel
Save