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,12 +5,11 @@
<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>
<ProjectReference Include="..\DataPersistence\DataPersistence.csproj" /> <ProjectReference Include="..\DataPersistence\DataPersistence.csproj" />
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -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;
}
}
}

@ -1,24 +1,50 @@
using System; using System;
using System.Collections.Generic; 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;
namespace ConsoleApp.Menu using Model.Managers;
{
internal class ConnectionMenu : Entry namespace ConsoleApp.Menu
{ {
public ConnectionMenu() internal class ConnectionMenu : Entry
: base("Connection", {
new Entry.EntryStep("Username: ", typeof(string)), private MasterManager _masterMgr;
new Entry.EntryStep("Password: ", typeof(string))) private bool _wrongInput = false;
{ }
public ConnectionMenu(MasterManager masterManager)
public override IMenu? Return() : base("Connection",
{ new Entry.EntryStep("Mail: ", typeof(string)),
string username = _selectList[0].Item.Input; new Entry.EntryStep("Password: ", typeof(string), true))
string password = _selectList[1].Item.Input; {
return new PlainText($"User: {username} connected with password: {password}"); _masterMgr = masterManager;
} }
}
} public override void Display()
{
base.Display();
if (_wrongInput)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Wrong input...");
Console.ResetColor();
}
}
public override IMenu? Return()
{
string mail = _selectList[0].Item.Input;
string password = _selectList[1].Item.Input;
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,119 +1,151 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.IO.Compression;
using System.Text; using System.Linq;
using System.Threading.Tasks; using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu using ConsoleApp.Menu.Core;
{
/// <summary> namespace ConsoleApp.Menu.Core
/// Define an Entry menu. {
/// <br/>It allows you to navigate through the entries and completes them with a console input. /// <summary>
/// </summary> /// Define an Entry menu.
internal abstract partial class Entry : Menu<Entry.EntryStep> /// <br/>It allows you to navigate through the entries and completes them with a console input.
{ /// </summary>
#region Attributes & Properties internal abstract partial class Entry : Menu<Entry.EntryStep>
private List<EntryStep> _steps; {
#endregion #region Attributes & Properties
private List<EntryStep> _steps;
#region Constructors #endregion
/// <summary>
/// Constructor of the entry menu, based on the Menu constructor. #region Constructors
/// </summary> /// <summary>
/// <param name="title">The title of this menu.</param> /// Constructor of the entry menu, based on the Menu constructor.
/// <param name="entrySteps">All the entries of this menu.</param> /// </summary>
protected Entry(string title, params EntryStep[] entrySteps) : base(title) /// <param name="title">The title of this menu.</param>
{ /// <param name="entrySteps">All the entries of this menu.</param>
_steps = entrySteps.ToList(); protected Entry(string title, params EntryStep[] entrySteps)
_allSelectors = ConvertEntryStepsInSelector(); : base(title)
_selectList = _allSelectors; {
} _steps = entrySteps.ToList();
#endregion _allSelectors = ConvertEntryStepsInSelector();
_selectList = _allSelectors;
#region Methods }
private List<Selector<EntryStep>> ConvertEntryStepsInSelector() #endregion
{
List<Selector<EntryStep>> newSelectors = new List<Selector<EntryStep>>(); #region Methods
foreach (EntryStep step in _steps) private List<Selector<EntryStep>> ConvertEntryStepsInSelector()
{ {
newSelectors.Add(new Selector<EntryStep>(step, step.Description)); List<Selector<EntryStep>> newSelectors = new List<Selector<EntryStep>>();
} foreach (EntryStep step in _steps)
return newSelectors; {
} newSelectors.Add(new Selector<EntryStep>(step, step.Description));
#endregion }
return newSelectors;
#region IMenu implementation }
public override void WriteMenuMode(ConsoleKeyInfo cki) #endregion
{
if (!WriteMode && cki.Key == ConsoleKey.R) #region IMenu implementation
{ public override void WriteMenuMode(ConsoleKeyInfo cki)
EnableWriteMode(); {
return; if (!WriteMode && cki.Key == ConsoleKey.R)
} {
EnableWriteMode();
if (WriteMode) if (CurrentSelected is null)
{ return;
if (cki.Key == ConsoleKey.Escape)
{ InputStr.Append(CurrentSelected.Input);
if (CurrentSelected is null) CurrentSelected.Input = "";
throw new ArgumentNullException("CurrentSelected"); return;
}
CurrentSelected.Input = InputStr.ToString();
DisableWriteMode(); if (WriteMode)
InputStr.Clear(); {
return; if (cki.Key == ConsoleKey.Escape)
} {
if (CurrentSelected is null)
if (cki.Key == ConsoleKey.Backspace && InputStr.Length > 0) throw new ArgumentNullException("CurrentSelected");
{
InputStr.Remove(InputStr.Length - 1, 1); CurrentSelected.Input = InputStr.ToString();
return; DisableWriteMode();
} InputStr.Clear();
return;
InputStr.Append(cki.KeyChar); }
}
} if (cki.Key == ConsoleKey.Backspace)
{
public override void Update() if (InputStr.Length > 0) InputStr.Remove(InputStr.Length - 1, 1);
{ return;
if (_selectList.Count == 0) }
{
CurrentSelected = default; InputStr.Append(cki.KeyChar);
return; }
} }
CurrentSelected = _selectList[CurrentLine].Item;
} public override void Update()
{
public override void Display() if (_selectList.Count == 0)
{ {
_screenDisplay.Clear(); CurrentSelected = default;
Console.Clear(); return;
}
_screenDisplay.AppendLine($"[ {Title} ]"); CurrentSelected = _selectList[CurrentLine].Item;
_screenDisplay.AppendLine("-------------------------------------------"); }
for (int i = 0; i < _selectList.Count; i++) public override void Display()
{ {
if (CurrentLine == i) StringBuilder displayItem = new StringBuilder();
_screenDisplay.Append($"> ");
else
_screenDisplay.Append($" "); _screenDisplay.Clear();
Console.Clear();
_screenDisplay.Append($"{_selectList[i].Line} {_selectList[i].Item.Input}");
_screenDisplay.AppendLine($"[ {Title} ]");
if (CurrentLine == i && WriteMode) _screenDisplay.AppendLine("-------------------------------------------");
_screenDisplay.Append(InputStr);
for (int i = 0; i < _selectList.Count; i++)
_screenDisplay.AppendLine(); {
}
if (_selectList[i].Item.Hidden)
if (_selectList.Count == 0) for (int _ = 0; _ < _selectList[i].Item.Input.Length; _++)
_screenDisplay.AppendLine("Empty..."); displayItem.Append('*');
else
_screenDisplay.AppendLine( displayItem.Append(_selectList[i].Item.Input);
"\n\nHint:\n^:previous, v:next, <:ret, -enter-:return, r:write, -escape-:exit search mode");
Console.WriteLine(_screenDisplay);
} if (CurrentLine == i)
#endregion {
} if (WriteMode)
} _screenDisplay.Append($"W ");
else
_screenDisplay.Append($"> ");
}
else
_screenDisplay.Append($" ");
_screenDisplay.Append($"{_selectList[i].Line} {displayItem}");
if (CurrentLine == i && WriteMode)
{
if (_selectList[i].Item.Hidden)
for (int _ = 0; _ < InputStr.Length; _++) _screenDisplay.Append('*');
else
_screenDisplay.Append(InputStr);
}
_screenDisplay.AppendLine();
displayItem.Clear();
}
if (_selectList.Count == 0)
_screenDisplay.AppendLine("Empty...");
_screenDisplay.AppendLine(
"\n\nHint:\n^:previous, v:next, <:back, -enter-:return, r:write, -escape-:exit search mode");
Console.WriteLine(_screenDisplay);
}
#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.
@ -44,7 +44,7 @@ namespace ConsoleApp.Menu
{ {
_currentLine = value; _currentLine = value;
if (_currentLine <= 0) _currentLine = 0; if (_currentLine <= 0) _currentLine = 0;
else if (_currentLine >= _selectList.Count) _currentLine = _selectList.Count-1; else if (_currentLine >= _selectList.Count) _currentLine = _selectList.Count - 1;
} }
} }
@ -75,7 +75,7 @@ namespace ConsoleApp.Menu
/// </summary> /// </summary>
/// <param name="title">The title of the menu.</param> /// <param name="title">The title of the menu.</param>
/// <param name="selections">The selections of the menu.</param> /// <param name="selections">The selections of the menu.</param>
protected Menu(string title, params Selector<T>[] selections ) : this(title) protected Menu(string title, params Selector<T>[] selections) : this(title)
{ {
if (selections == null || selections.Length == 0) if (selections == null || selections.Length == 0)
{ {
@ -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);
} }

@ -3,8 +3,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;
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);
@ -36,16 +36,16 @@ namespace ConsoleApp.Menu
public StringBuilder InputStr { get; set; } public StringBuilder InputStr { get; set; }
public void DisableWriteMode() public void DisableWriteMode()
{ {
// Plain text does not need to do anything for this. // Plain text does not need to do anything for this.
} }
public void EnableWriteMode() public void EnableWriteMode()
{ {
// Plain text does not need to do anything for this. // Plain text does not need to do anything for this.
} }
public void SelectNext() public void SelectNext()
{ {
// Plain text does not need to do anything for this. // Plain text does not need to do anything for this.
} }
public void SelectPrevious() public void SelectPrevious()
{ {

@ -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();
}
}
}

@ -1,24 +1,58 @@
using Model; using Model;
using DataPersistence; using DataPersistence;
using System; using System;
using System.Collections.Generic; 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;
namespace ConsoleApp.Menu using Model.Managers;
{
/// <summary> namespace ConsoleApp.Menu
/// Main menu of the console. Contain the first interaction menus. {
/// </summary> /// <summary>
internal class MainMenu : Menu<IMenu> /// Main menu of the console. Contain the first interaction menus.
{ /// </summary>
public MainMenu(DataManager dataMgr) internal class MainMenu : Menu<IMenu>
: base("Main menu", {
new Selector<IMenu>( private MasterManager _masterMgr;
new SearcherRecipe(new RecipeCollection("search", dataMgr.Data[nameof(Recipe)].Cast<Recipe>().ToArray())), "Recipe search"),
new Selector<IMenu>( public MainMenu(MasterManager masterManager)
new ConnectionMenu(), "Connection")) : base("Main menu")
{ } {
} _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 Model;
using ConsoleApp;
using ConsoleApp.Menu;
using DataPersistence; using DataPersistence;
using Model; using Model.Managers;
using System.Linq;
using System.Text;
Console.WriteLine("Hello, World!\n\n");
// TESTS:
DataManager dataMgr = new DataManager(new Stubs());
//DataManager dataMgr = new DataManager(new DataContractXML());
//DataManager dataMgr = new DataManager(new DataContractJSON());
dataMgr.Serializer = new DataContractXML(); Console.WriteLine("Hello, World!\n\n");
//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. string path = ""; // - path to the save file
//dataMgr.Export(rc[2], "C:\\Users\\alex6\\Downloads\\recipe2.json"); string strategy = "xml"; // - strategy is 'xml' or 'json' (/!\ this is case sensitive)
//dataMgr.Import<Recipe>("C:\\Users\\alex6\\Downloads\\recipe2.json");
PasswordManager passwordManager = new PasswordManager(); MasterManager masterMgr;
//RecipeCollection rc = new RecipeCollection("All recipes", dataMgr.Data[nameof(Recipe)].Cast<Recipe>().ToArray()); IDataManager dataManager = (strategy == "xml") ?
RecipeCollection rc = dataMgr.GetRecipes("All recipes"); new DataContractXML(path)
//RecipeCollection rc = new RecipeCollection("All recipes", dataMgr.GetFromData<Recipe>().ToArray()); : new DataContractJSON(path);
User user = dataMgr.GetUsers().Last(); if (!File.Exists(Path.Combine(path, $"data.{strategy}")))
{
masterMgr = new MasterManager(new Stubs());
masterMgr.DataMgr.Serializer = dataManager;
}
else
{
masterMgr = new MasterManager(dataManager);
}
//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(); MenuManager menuMgr = new MenuManager(masterMgr);
MenuManager menuMgr = new MenuManager(dataMgr);
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
}; };

@ -1,137 +1,147 @@
using Model; using Model;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace DataPersistence namespace DataPersistence
{ {
/// <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 : IDataManager
{ {
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>> {
{ #region Data: Recipes
{ nameof(Recipe),
#region Data: Recipes new List<object>(new[]
nameof(Recipe), {
new List<object>(new[] new Recipe(
{ title: "Cookies classiques",
new Recipe( id: 50,
title: "Cookies classiques", id: null, authorMail: "admin@mctg.fr",
ingredients: new List<Ingredient>(new[] picture : "room_service_icon.png",
ingredients: new List<Ingredient>(new[]
{ {
new Ingredient("Patates", new Quantity(23, Unit.unit)), new Ingredient("Patates", new Quantity(23, Unit.unit)),
new Ingredient("Farine", new Quantity(23, Unit.G)) new Ingredient("Farine", new Quantity(23, Unit.G))
}), }),
preparationSteps: new[] preparationSteps: new[]
{ {
new PreparationStep(1, "Faire cuire."), new PreparationStep(1, "Faire cuire."),
new PreparationStep(2, "Manger.") new PreparationStep(2, "Manger.")
}), }),
new Recipe( new Recipe(
title: "Cookies au chocolat", id: null, authorMail: "admin@mctg.fr",
preparationSteps: new[] title: "Cookies au chocolat", id: null,
{ preparationSteps: new[]
new PreparationStep(1, "Moulinez la pâte."), {
new PreparationStep(2, "Faire cuire pendant une bonne heure."), new PreparationStep(1, "Moulinez la pâte."),
new PreparationStep(3, "Sortir du four et mettre dans un plat.") new PreparationStep(2, "Faire cuire pendant une bonne heure."),
}), new PreparationStep(3, "Sortir du four et mettre dans un plat.")
new Recipe( }),
title: "Gateau nature", id: null, new Recipe(
preparationSteps: new[] title: "Gateau nature", id: null,
{ authorMail: "admin@mctg.fr",
new PreparationStep(1, "Achetez les ingrédients."), preparationSteps: new[]
new PreparationStep(2, "Préparez le matériel. Ustensiles et tout."), {
new PreparationStep(3, "Pleurez.") new PreparationStep(1, "Achetez les ingrédients."),
}), new PreparationStep(2, "Préparez le matériel. Ustensiles et tout."),
new Recipe( new PreparationStep(3, "Pleurez.")
title: "Gateau au pommes", id: null, }),
preparationSteps: new[] new Recipe(
{ title: "Gateau au pommes", id: null,
new PreparationStep(1, "Achetez les légumes."), authorMail: "admin@mctg.fr",
new PreparationStep(2, "Préparez le plat. Ustensiles et préchauffez le four."), preparationSteps: new[]
new PreparationStep(3, "Coupez les pommes en morceaux et disposez-les sur le plat."), {
new PreparationStep(4, "Mettez enfin le plat au four, puis une fois cuit, dégustez !") new PreparationStep(1, "Achetez les légumes."),
}), new PreparationStep(2, "Préparez le plat. Ustensiles et préchauffez le four."),
new Recipe( new PreparationStep(3, "Coupez les pommes en morceaux et disposez-les sur le plat."),
title: "Gateau au chocolat", id: null, new PreparationStep(4, "Mettez enfin le plat au four, puis une fois cuit, dégustez !")
preparationSteps: new[] }),
{ new Recipe(
new PreparationStep(1, "Ajouter les oeufs."), title: "Gateau au chocolat", id: null,
new PreparationStep(2, "Ajouter la farine."), authorMail: "pedrosamigos@hotmail.com",
new PreparationStep(3, "Ajouter 100g de chocolat fondu."), preparationSteps: new[]
new PreparationStep(4, "Mélanger le tout."), {
new PreparationStep(5, "Faire cuire 45h au four traditionnel.") new PreparationStep(1, "Ajouter les oeufs."),
}), new PreparationStep(2, "Ajouter la farine."),
new Recipe( new PreparationStep(3, "Ajouter 100g de chocolat fondu."),
title: "Dinde au jambon", id: null, new PreparationStep(4, "Mélanger le tout."),
preparationSteps: new[] new PreparationStep(5, "Faire cuire 45h au four traditionnel.")
{ }),
new PreparationStep(1, "Faire une cuisson bien sec de la dinde à la poêle"), new Recipe(
new PreparationStep(2, "Mettre la dinde au frigo."), title: "Dinde au jambon",
new PreparationStep(3, "Mettre le jambon dans le micro-onde."), id: null,
new PreparationStep(4, "Faire chauffer 3min."), authorMail: "pedrosamigos@hotmail.com",
new PreparationStep(5, "Présentez sur un plat la dinde et le jambon : Miam !") preparationSteps: new[]
}), {
new Recipe( new PreparationStep(1, "Faire une cuisson bien sec de la dinde à la poêle"),
title: "Poulet au curry", id: null, new PreparationStep(2, "Mettre la dinde au frigo."),
preparationSteps: new[] new PreparationStep(3, "Mettre le jambon dans le micro-onde."),
{ new PreparationStep(4, "Faire chauffer 3min."),
new PreparationStep(1, "Trouvez des épices de curry."), new PreparationStep(5, "Présentez sur un plat la dinde et le jambon : Miam !")
new PreparationStep(2, "Trouvez maintenant du poulet."), }),
new PreparationStep(3, "Coupez la tête du poulet et posez-la dans un plat."), new Recipe(
new PreparationStep(4, "Parsemez d'épices curry la tête de la poule."), title: "Poulet au curry", id: null,
new PreparationStep(5, "Mettre le tout au four traditionnel 30min."), authorMail: "pedrosamigos@hotmail.com",
new PreparationStep(6, "Dégustez en famille !") preparationSteps: new[]
}) {
}) new PreparationStep(1, "Trouvez des épices de curry."),
#endregion new PreparationStep(2, "Trouvez maintenant du poulet."),
}, new PreparationStep(3, "Coupez la tête du poulet et posez-la dans un plat."),
new PreparationStep(4, "Parsemez d'épices curry la tête de la poule."),
new PreparationStep(5, "Mettre le tout au four traditionnel 30min."),
new PreparationStep(6, "Dégustez en famille !")
})
})
#endregion
},
{ {
#region Data: User #region Data: User
nameof(User), nameof(User),
new List<object>(new[] new List<object>(new[]
{ {
new User( new User(
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
} }
}; };
return data; return data;
} }
#region Not supported methods #region Not supported methods
public void Save(Dictionary<string, List<object>> elements) public void Save(Dictionary<string, List<object>> elements)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
public void Export<T>(T obj, string pathToExport) where T : class public void Export<T>(T obj, string pathToExport) where T : class
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
public KeyValuePair<string, T> Import<T>(string pathToImport) where T : class public KeyValuePair<string, T> Import<T>(string pathToImport) where T : class
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
#endregion #endregion
} }
} }

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

@ -1,38 +1,55 @@
#if WINDOWS #if WINDOWS
using Microsoft.UI; using Microsoft.UI;
using Microsoft.UI.Windowing; using Microsoft.UI.Windowing;
using Windows.Graphics; using Windows.Graphics;
#endif #endif
namespace Views using DataPersistence;
{ using Model;
public partial class App : Application using System.Collections.ObjectModel;
{ using Model.Managers;
const int WindowWidth = 1200;
const int WindowHeight = 800; namespace Views
{
public App() public partial class App : Application
{ {
InitializeComponent(); //Point d'entrée de l'application
public MasterManager MasterMgr { get; private set; } = new MasterManager(new Stubs());
Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
{ //L'utilisateur courant de l'application
#if WINDOWS public User CurrentUser { get; set; }
var mauiWindow = handler.VirtualView;
var nativeWindow = handler.PlatformView; //collection de recette de l'application
nativeWindow.Activate(); public RecipeCollection AllRecipes { get; set; }
IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle); //const int WindowWidth = 1200;
AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId); //const int WindowHeight = 800;
appWindow.Resize(new SizeInt32(WindowWidth, WindowHeight));
#endif public App()
}); {
CurrentUser = MasterMgr.DataMgr.GetUsers().Last();
AllRecipes = MasterMgr.DataMgr.GetRecipes("All recipes");
/* - Comment(ctrl-k + ctrl-c)/Uncomment(ctrl-k + ctrl-u) to change page - */
UserAppTheme = AppTheme.Light; InitializeComponent();
MainPage = new MyProfil();
//MainPage = new MyPosts(); // Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
} // {
} //#if WINDOWS
} // var mauiWindow = handler.VirtualView;
// var nativeWindow = handler.PlatformView;
// nativeWindow.Activate();
// IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
// WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
// AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
// appWindow.Resize(new SizeInt32(WindowWidth, WindowHeight));
//#endif
// });
/* - Comment(ctrl-k + ctrl-c)/Uncomment(ctrl-k + ctrl-u) to change page - */
UserAppTheme = AppTheme.Light;
MainPage = new Home();
//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,39 +1,49 @@
namespace Views; using DataPersistence;
using Model;
public partial class ContainerFlyout : ContentView using Model.Managers;
{
public ContainerFlyout() namespace Views;
{
InitializeComponent(); public partial class ContainerFlyout : ContentView
} {
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
// Bind MyFlyoutContent public User user => (App.Current as App).CurrentUser;
public static readonly BindableProperty MyFlyoutContentProperty =
BindableProperty.Create("MyFlyoutContent", typeof(View), typeof(ContainerFlyout), new Grid()); public ContainerFlyout()
{
public View MyFlyoutContent InitializeComponent();
{ BindingContext = this;
get => (View)GetValue(MyFlyoutContentProperty);
set => SetValue(MyFlyoutContentProperty, value);
} }
// Bind IsNotConnected // Bind MyFlyoutContent
public static readonly BindableProperty IsNotConnectedProperty = public static readonly BindableProperty MyFlyoutContentProperty =
BindableProperty.Create("IsNotConnected", typeof(bool), typeof(Button), true); BindableProperty.Create("MyFlyoutContent", typeof(View), typeof(ContainerFlyout), new Grid());
public bool IsNotConnected public View MyFlyoutContent
{ {
get => (bool)GetValue(IsNotConnectedProperty); get => (View)GetValue(MyFlyoutContentProperty);
set => SetValue(IsNotConnectedProperty, value); set => SetValue(MyFlyoutContentProperty, value);
} }
// bind NeedReturn // Bind IsNotConnected
public static readonly BindableProperty NeedReturnProperty = public static readonly BindableProperty IsNotConnectedProperty =
BindableProperty.Create("NeedReturn", typeof(bool), typeof(Border), false); BindableProperty.Create("IsNotConnected", typeof(bool), typeof(Button), true);
public bool NeedReturn public bool IsNotConnected
{ {
get => (bool)GetValue(NeedReturnProperty); get => (bool)GetValue(IsNotConnectedProperty);
set => SetValue(NeedReturnProperty, value); 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);
}
}

@ -1,66 +1,107 @@
<?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"
x:Class="Views.Home"> xmlns:model="clr-namespace:Model;assembly=Model"
x:Class="Views.Home">
<local:ContainerBase
IsNotConnected="True"> <local:ContainerBase
IsNotConnected="True">
<!-- Flyout -->
<local:ContainerBase.MyFlyoutContent> <!-- Flyout -->
<VerticalStackLayout Grid.Row="1"> <local:ContainerBase.MyFlyoutContent>
<!-- Research --> <VerticalStackLayout Grid.Row="1">
<Button Text="Recherche" ImageSource="search_icon.png" <!-- Research -->
MaximumHeightRequest="20" <Button
Style="{StaticResource button1}"/> Text="Recherche"
<SearchBar Placeholder="Mots-clés (ex.: rapide, fromage)" FontAttributes="Italic" TextColor="Black" ImageSource="search_icon.png"
BackgroundColor="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray300}}" MaximumHeightRequest="20"
Margin="15, 10, 15, 40"/> Style="{StaticResource button1}"/>
<SearchBar
<!-- Direct research --> Placeholder="Mots-clés (ex.: rapide, fromage)"
<Button Text="Entrées" ImageSource="flatware_icon.png" FontAttributes="Italic" TextColor="Black"
Style="{StaticResource button1}"/> BackgroundColor="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray300}}"
<Button Text="Plats" ImageSource="room_service_icon.png" Margin="15, 10, 15, 40"/>
Style="{StaticResource button1}"/>
<Button Text="Desserts" ImageSource="coffee_icon.png" <!-- Direct research -->
Style="{StaticResource button1}"/> <Button
</VerticalStackLayout> Text="Entrées"
</local:ContainerBase.MyFlyoutContent> ImageSource="flatware_icon.png"
Style="{StaticResource button1}"/>
<!-- Master --> <Button
<local:ContainerBase.MyContent> Text="Plats"
<ScrollView> ImageSource="room_service_icon.png"
<StackLayout> Style="{StaticResource button1}"/>
<Label Text="Suggestions" TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}" <Button
FontSize="24" Padding="15"/> Text="Desserts"
ImageSource="coffee_icon.png"
<FlexLayout Style="{StaticResource button1}"/>
Margin="0, 15" </VerticalStackLayout>
Wrap="Wrap" </local:ContainerBase.MyFlyoutContent>
JustifyContent="Start"
AlignItems="Center" <!-- Master -->
AlignContent="SpaceEvenly" <local:ContainerBase.MyContent>
HorizontalOptions="Center"> <ScrollView>
<StackLayout BindingContext="{Binding AllRecipes}" MinimumWidthRequest="400">
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <!--Modification du prof apportée sur le stacklayout pour empecher l'affichage d'une seule case recipe-->
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <Label
<local:RecipeCase CaseImageSource="room_service_icon.png"/> Text="{Binding Description}"
<local:RecipeCase CaseImageSource="room_service_icon.png"/> TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}"
<local:RecipeCase CaseImageSource="room_service_icon.png"/> FontSize="24"
<local:RecipeCase CaseImageSource="room_service_icon.png"/> Padding="15"/>
<local:RecipeCase CaseImageSource="room_service_icon.png"/>
<local:RecipeCase CaseImageSource="room_service_icon.png"/> <FlexLayout
<local:RecipeCase CaseImageSource="room_service_icon.png"/> Margin="0, 15"
<local:RecipeCase CaseImageSource="room_service_icon.png"/> Wrap="Wrap"
<local:RecipeCase CaseImageSource="room_service_icon.png"/> JustifyContent="Start"
AlignItems="Center"
</FlexLayout> AlignContent="SpaceEvenly"
</StackLayout> HorizontalOptions="Center"
</ScrollView> BindableLayout.ItemsSource="{Binding}">
</local:ContainerBase.MyContent>
<BindableLayout.ItemTemplate>
</local:ContainerBase> <DataTemplate x:DataType="model:Recipe">
<Border Style="{StaticResource recipeCase}">
</ContentPage> <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"/>
<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>
</StackLayout>
</ScrollView>
</local:ContainerBase.MyContent>
</local:ContainerBase>
</ContentPage>

@ -1,10 +1,22 @@
namespace Views using DataPersistence;
{ using Model;
public partial class Home : ContentPage using Model.Managers;
{
public Home() namespace Views
{ {
InitializeComponent(); 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()
{
//DataMgr = new DataManager(new Stubs());
//AllRecipes = new RecipeCollection("Toutes les recettes", DataMgr.Data[nameof(Recipe)].Cast<Recipe>().ToArray());
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}}"
@ -67,44 +60,34 @@
<Grid BackgroundColor="#D1E8E2" <Grid BackgroundColor="#D1E8E2"
MinimumHeightRequest="300" MinimumHeightRequest="300"
Padding="20"> Padding="20">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Text="Recettes économiques" Grid.Row="0" Padding="5,0,0,0"/> <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" /> <BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="1" />
<Label Text="Recettes rapides" Grid.Row="2"/> <Label Text="Recettes rapides" Grid.Row="2"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="3" /> <BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="3" />
<Label Text="Recettes simples" Grid.Row="4"/> <Label Text="Recettes simples" Grid.Row="4"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="5" /> <BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="5" />
<Label Text="Recettes légères" Grid.Row="6"/> <Label Text="Recettes légères" Grid.Row="6"/>
<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 @@
namespace Views; using CommunityToolkit.Maui.Behaviors;
using DataPersistence;
public partial class MyProfil : ContentPage using Model;
{ using Model.Managers;
public MyProfil() using System.Diagnostics;
{
InitializeComponent(); namespace Views;
}
public partial class MyProfil : ContentPage
{
public MasterManager MasterMgr => (App.Current as App).MasterMgr;
public User user => (App.Current as App).CurrentUser;
public MyProfil()
{
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