diff --git a/.drone.yml b/.drone.yml index f538cac..01a268d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -100,7 +100,7 @@ steps: dockerfile: MCTG/Dockerfile context: MCTG/ registry: hub.codefirst.iut.uca.fr - repo: hub.codefirst.iut.uca.fr/alexandre.agostinho/cli-mctg + repo: hub.codefirst.iut.uca.fr/alexandre.agostinho/console-mctg username: from_secret: SECRET_REGISTRY_USERNAME password: @@ -111,7 +111,7 @@ steps: # image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest # environment: # IMAGENAME: hub.codefirst.iut.uca.fr/alexandre.agostinho/sae-2.01:latest - # CONTAINERNAME: cli-mctg + # CONTAINERNAME: console-mctg # COMMAND: create # OVERWRITE: true # depends_on: [ docker-build-and-push ] diff --git a/MCTG/ConsoleApp/Menu/ConnectionMenu.cs b/MCTG/ConsoleApp/Menu/ConnectionMenu.cs new file mode 100644 index 0000000..d4c9949 --- /dev/null +++ b/MCTG/ConsoleApp/Menu/ConnectionMenu.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp.Menu +{ + internal class ConnectionMenu : Entry + { + public ConnectionMenu() + : base("Connection", + new Entry.EntryStep("Username: ", typeof(string)), + new Entry.EntryStep("Password: ", typeof(string))) + { } + + public override IMenu? Return() + { + string username = _selectList[0].Item.Input; + string password = _selectList[1].Item.Input; + return new PlainText($"User: {username} connected with password: {password}"); + } + } +} diff --git a/MCTG/ConsoleApp/Menu/Entry.EntryStep.cs b/MCTG/ConsoleApp/Menu/Entry.EntryStep.cs new file mode 100644 index 0000000..b58a707 --- /dev/null +++ b/MCTG/ConsoleApp/Menu/Entry.EntryStep.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp.Menu +{ + internal abstract partial class Entry + { + /// + /// Define a step of the Entry menu, or in other word, an entry itself. + /// + public class EntryStep + { + #region Attributes & Properties + private readonly Type _entryType; + + /// + /// The entry description. This text is generally placed before the input field. + /// + public string Description { get; private set; } + + /// + /// Contain the input gave by the menu. + /// + public string Input { get; internal set; } + #endregion + + #region Constructors + /// + /// Constructor of the entry step. + /// + /// The text generally placed before the input in the menu. + /// The type of the returned input. + public EntryStep(string description, Type type) + { + Description = description; + Input = ""; + _entryType = type; + } + #endregion + + #region Methods + /// + /// Get the inputed string converted on this entry type. + /// + /// The converted string on the entry type. + /// Throw when the entry type converter does not exist here. + public object GetEntry() + { + try + { + if (_entryType == typeof(string)) + return Input; + if (_entryType == typeof(int)) + return Int32.Parse(Input); + if (_entryType == typeof(DateTime)) + return DateTime.Parse(Input); + } + catch (FormatException fe) + { + Console.Error.WriteLine(fe); + } + + throw new NotImplementedException("Error: parse of this type is not implemented."); + } + #endregion + } + } +} diff --git a/MCTG/ConsoleApp/Menu/Entry.cs b/MCTG/ConsoleApp/Menu/Entry.cs new file mode 100644 index 0000000..3a84fff --- /dev/null +++ b/MCTG/ConsoleApp/Menu/Entry.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp.Menu +{ + /// + /// Define an Entry menu. + ///
It allows you to navigate through the entries and completes them with a console input. + ///
+ internal abstract partial class Entry : Menu + { + #region Attributes & Properties + private List _steps; + #endregion + + #region Constructors + /// + /// Constructor of the entry menu, based on the Menu constructor. + /// + /// The title of this menu. + /// All the entries of this menu. + protected Entry(string title, params EntryStep[] entrySteps) : base(title) + { + _steps = entrySteps.ToList(); + _allSelectors = ConvertEntryStepsInSelector(); + _selectList = _allSelectors; + } + #endregion + + #region Methods + private List> ConvertEntryStepsInSelector() + { + List> newSelectors = new List>(); + foreach (EntryStep step in _steps) + { + newSelectors.Add(new Selector(step, step.Description)); + } + return newSelectors; + } + #endregion + + #region IMenu implementation + public override void WriteMenuMode(ConsoleKeyInfo cki) + { + if (!WriteMode && cki.Key == ConsoleKey.R) + { + EnableWriteMode(); + return; + } + + if (WriteMode) + { + if (cki.Key == ConsoleKey.Escape) + { + if (CurrentSelected is null) + throw new ArgumentNullException("CurrentSelected"); + + CurrentSelected.Input = InputStr.ToString(); + DisableWriteMode(); + InputStr.Clear(); + return; + } + + if (cki.Key == ConsoleKey.Backspace && InputStr.Length > 0) + { + InputStr.Remove(InputStr.Length - 1, 1); + return; + } + + InputStr.Append(cki.KeyChar); + } + } + + public override void Update() + { + if (_selectList.Count == 0) + { + CurrentSelected = default; + return; + } + CurrentSelected = _selectList[CurrentLine].Item; + } + + public override void Display() + { + _screenDisplay.Clear(); + Console.Clear(); + + _screenDisplay.AppendLine($"[ {Title} ]"); + _screenDisplay.AppendLine("-------------------------------------------"); + + for (int i = 0; i < _selectList.Count; i++) + { + if (CurrentLine == i) + _screenDisplay.Append($"> "); + else + _screenDisplay.Append($" "); + + _screenDisplay.Append($"{_selectList[i].Line} {_selectList[i].Item.Input}"); + + if (CurrentLine == i && WriteMode) + _screenDisplay.Append(InputStr); + + _screenDisplay.AppendLine(); + } + + if (_selectList.Count == 0) + _screenDisplay.AppendLine("Empty..."); + + _screenDisplay.AppendLine( + "\n\nHint:\n^:previous, v:next, <:ret, -enter-:return, r:write, -escape-:exit search mode"); + Console.WriteLine(_screenDisplay); + } + #endregion + } +} diff --git a/MCTG/ConsoleApp/Menu/IMenu.cs b/MCTG/ConsoleApp/Menu/IMenu.cs new file mode 100644 index 0000000..120a387 --- /dev/null +++ b/MCTG/ConsoleApp/Menu/IMenu.cs @@ -0,0 +1,72 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp.Menu +{ + /// + /// Define a console menu with element selection. + /// + internal interface IMenu + { + /// + /// True when enable, False otherwise. + /// + bool WriteMode { get; set; } + + /// + /// A string input. Used for search string or entry input. + /// + StringBuilder InputStr { get; set; } + + /// + /// Refresh the console with the updated display. This function dose not call Update(). + /// + void Display(); + + /// + /// Update the parameters of the menu. Generally called before Display() to refresh the informations. + /// + void Update(); + + /// + /// Select the next element in the selection list. + /// + void SelectNext(); + + /// + /// Select the previous element in the selection list. + /// + void SelectPrevious(); + + /// + /// Enable the write mode. + /// + void EnableWriteMode(); + + /// + /// Disable the write mode. + /// + void DisableWriteMode(); + + /// + /// Toogle the write mode. + /// + void ToggleWriteMode(); + + /// + /// Define the comportement of the write mode. For instence: in the standard menu, it is used for the research of a line. + /// + /// The key to deal with. + void WriteMenuMode(ConsoleKeyInfo cki); + + /// + /// Execute some actions and then return. + /// + /// 'null' when there is no menu after this selection. Otherwise the next menu. + IMenu? Return(); + } +} diff --git a/MCTG/ConsoleApp/Menu/IMenuDisplay.cs b/MCTG/ConsoleApp/Menu/IMenuDisplay.cs deleted file mode 100644 index 572082c..0000000 --- a/MCTG/ConsoleApp/Menu/IMenuDisplay.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ConsoleApp.Menu -{ - internal interface IMenuDisplay - { - /// - /// Update the menu display in the Console. - /// - void UpdateDisplay(); - - /// - /// Select the next line in the menu - /// - /// The current number of the new selected line - int SelectNextLine(); - - /// - /// Select the previous line in the menu - /// - /// The current number of the new selected line - int SelectPrevioustLine(); - } -} diff --git a/MCTG/ConsoleApp/Menu/MainMenu.cs b/MCTG/ConsoleApp/Menu/MainMenu.cs new file mode 100644 index 0000000..8dcbb8b --- /dev/null +++ b/MCTG/ConsoleApp/Menu/MainMenu.cs @@ -0,0 +1,24 @@ +using Model; +using DataPersistence; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp.Menu +{ + /// + /// Main menu of the console. Contain the first interaction menus. + /// + internal class MainMenu : Menu + { + public MainMenu(DataManager dataMgr) + : base("Main menu", + new Selector( + new SearcherRecipe(new RecipeCollection("search", dataMgr.Data[nameof(Recipe)].Cast().ToArray())), "Recipe search"), + new Selector( + new ConnectionMenu(), "Connection")) + { } + } +} diff --git a/MCTG/ConsoleApp/Menu/Menu.cs b/MCTG/ConsoleApp/Menu/Menu.cs new file mode 100644 index 0000000..68962db --- /dev/null +++ b/MCTG/ConsoleApp/Menu/Menu.cs @@ -0,0 +1,201 @@ +using System.Data; +using Model; +using System; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp.Menu +{ + /// + /// Define a selection menu. + ///
It allows you to navigate through the selections and search with a console input. + ///
+ /// The type (or the implementation) of the selection. + internal abstract class Menu : IMenu + where T : notnull + { + #region Attributes & Properties + protected StringBuilder _screenDisplay; + + protected List> _allSelectors = new List>(); + protected List> _selectList = new List>(); + + private int _currentLine; + + /// + /// Title of the menu. + /// + public string Title { get; private set; } + + /// + /// The current line of the selection list. + /// + public int CurrentLine + { + get + { + if (_currentLine >= _selectList.Count) _currentLine = _selectList.Count - 1; + return _currentLine; + } + protected set + { + _currentLine = value; + if (_currentLine <= 0) _currentLine = 0; + else if (_currentLine >= _selectList.Count) _currentLine = _selectList.Count-1; + } + } + + /// + /// The currently selected object. + /// + public T? CurrentSelected { get; protected set; } + #endregion + + #region Constructors + /// + /// Base constructor of the Menu class. + ///
This one is incomplete and need to be completed in the inherited class constructors. + ///
Basically, the '_allSelection' and '_selectList' attribute initialization are missing. + ///
+ /// The title of the Menu. + protected Menu(string title) + { + Title = title; + CurrentLine = 0; + WriteMode = false; + _screenDisplay = new StringBuilder(); + InputStr = new StringBuilder(); + } + + /// + /// Constructor of the Menu class. This constructor allows you to directly pass the selections. + /// + /// The title of the menu. + /// The selections of the menu. + protected Menu(string title, params Selector[] selections ) : this(title) + { + if (selections == null || selections.Length == 0) + { + Console.WriteLine("Empty menu..."); + return; + } + + _allSelectors = selections.ToList(); + _selectList = _allSelectors; + CurrentSelected = _allSelectors[0].Item; + } + #endregion + + #region IMenu implementation + public StringBuilder InputStr { get; set; } + public bool WriteMode { get; set; } + + public virtual IMenu? Return() + { + if (CurrentSelected is null) + throw new ArgumentNullException("CurrentSelected"); + + return (IMenu)CurrentSelected; + } + + protected virtual List> SearchInSelection() + { + if (_allSelectors is null) + throw new ArgumentNullException("_allSelectors"); + + return _allSelectors.FindAll(x => + x.Line.ToLower().Contains(InputStr.ToString().ToLower())); + } + + public virtual void WriteMenuMode(ConsoleKeyInfo cki) + { + if (!WriteMode && cki.Key == ConsoleKey.R) + { + EnableWriteMode(); + return; + } + + if (WriteMode) + { + if (cki.Key == ConsoleKey.Escape) + { + DisableWriteMode(); + InputStr.Clear(); + return; + } + + if (cki.Key == ConsoleKey.Backspace && InputStr.Length > 0) + { + InputStr.Remove(InputStr.Length - 1, 1); + return; + } + + InputStr.Append(cki.KeyChar); + } + } + + public virtual void Update() + { + _selectList = SearchInSelection(); + + if (_selectList.Count == 0) + { + CurrentSelected = default; + return; + } + CurrentSelected = _selectList[CurrentLine].Item; + } + + public virtual void Display() + { + _screenDisplay.Clear(); + Console.Clear(); + + _screenDisplay.AppendLine($"[ {Title} ]"); + _screenDisplay.AppendLine("-------------------------------------------"); + + if (WriteMode) + { + _screenDisplay.Append("Search: "); + _screenDisplay.AppendLine(InputStr.ToString()); + } + + for (int i = 0; i < _selectList.Count; i++) + { + if (CurrentLine == i) + _screenDisplay.Append($"> "); + else + _screenDisplay.Append($" "); + + _screenDisplay.AppendLine($"{_selectList[i].Line}"); + } + + if (_selectList.Count == 0) + _screenDisplay.AppendLine("Empty..."); + + _screenDisplay.AppendLine( + "\n\nHint:\n^:previous, v:next, <:ret, -enter-:select, r:search, -escape-:exit search mode"); + Console.WriteLine(_screenDisplay); + } + + public void SelectNext() => ++CurrentLine; + + public void SelectPrevious() => --CurrentLine; + + public void EnableWriteMode() => WriteMode = true; + + public void DisableWriteMode() => WriteMode = false; + + public void ToggleWriteMode() + { + if (WriteMode) + DisableWriteMode(); + else + EnableWriteMode(); + } + #endregion + } +} diff --git a/MCTG/ConsoleApp/Menu/PlainText.cs b/MCTG/ConsoleApp/Menu/PlainText.cs new file mode 100644 index 0000000..d5deee1 --- /dev/null +++ b/MCTG/ConsoleApp/Menu/PlainText.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp.Menu +{ + /// + /// Define a Plain text menu. + ///
This menu is a bit special. It display some text, and then, the only action that can be performed is the back return. Usefull for testing. + ///
+ internal class PlainText : IMenu + { + #region Constructors + /// + /// Constructor of the Plain text menu. + /// + /// The text buffer to display. + public PlainText(string text) + { + InputStr = new StringBuilder(text); + WriteMode = false; + } + #endregion + + #region IMenu implementation + public IMenu? Return() { return null; } + public void Display() + { + Console.Clear(); + Console.WriteLine(InputStr); + } + + public bool WriteMode { get; set; } + public StringBuilder InputStr { get; set; } + + public void DisableWriteMode() + { + // Plain text does not need to do anything for this. + } + public void EnableWriteMode() + { + // Plain text does not need to do anything for this. + } + public void SelectNext() + { + // Plain text does not need to do anything for this. + } + public void SelectPrevious() + { + // Plain text does not need to do anything for this. + } + public void ToggleWriteMode() + { + // Plain text does not need to do anything for this. + } + public void Update() + { + // Plain text does not need to do anything for this. + } + public void WriteMenuMode(ConsoleKeyInfo cki) + { + // Plain text does not need to do anything for this. + } + #endregion + } +} diff --git a/MCTG/ConsoleApp/Menu/SearcherRecipe.cs b/MCTG/ConsoleApp/Menu/SearcherRecipe.cs index 4e17512..b7dea49 100644 --- a/MCTG/ConsoleApp/Menu/SearcherRecipe.cs +++ b/MCTG/ConsoleApp/Menu/SearcherRecipe.cs @@ -1,125 +1,46 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Threading.Tasks; - -using Model; - -namespace ConsoleApp.Menu -{ - /// - /// An utility to find a recipe. - /// - public class SearcherRecipe : SelectMenu - { - #region Attribute - private RecipeCollection _recipeOnSearch; - #endregion - - #region Properties - /// - /// A collection of recipe where the title contain the search string - /// - public RecipeCollection SearchResult { get; private set; } - - /// - /// The search string - /// - public string ResearchStr { get; set; } - #endregion - - /// - /// Constructor of the SearcherRecipe utility. - /// - /// The collection of recipe where to search - public SearcherRecipe(RecipeCollection recipeOnSearch) - { - _recipeOnSearch = recipeOnSearch; - SearchResult = _recipeOnSearch; - ResearchStr = ""; - } - - #region Methodes - /// - /// Launch a search by name request in the collection of Recipe with with a string. - /// - /// The string for search - /// True if the result of the search gave at least 1 element. False otherwise. - public bool ComputeSearch(string researchStr = "") - { - ResearchStr = researchStr; - SearchResult = _recipeOnSearch.ResearchByName(ResearchStr.ToLower()); - _maxLines = SearchResult.Count - 1; - - return SearchResult.Count > 0; - } - - public override void UpdateDisplay() - { - StringBuilder sb = new StringBuilder(); - sb.AppendLine("---------------------------------------------------------"); - sb.AppendLine($" Research: {ResearchStr}"); - sb.AppendLine("---------------------------------------------------------"); - for (int i = 0; i < SearchResult.Count; i++) - { - if (i == CurrentLine) - { - CurrentSelected = SearchResult[i]; - sb.Append($">"); - } - sb.AppendLine($" [ {SearchResult[i].Id} ]:\t{SearchResult[i].Title} "); - } - Console.Clear(); - Console.WriteLine(sb); - } - - /// - /// Launch and pilot the search menu. - /// - /// The collection of recipe where to search - /// The recipe selected - public static Recipe? ResearchOn(RecipeCollection recipeOnSearch) - { - SearcherRecipe sr = new SearcherRecipe(recipeOnSearch); - StringBuilder sb = new StringBuilder(); - sr.ComputeSearch(); - sr.UpdateDisplay(); - - ConsoleKeyInfo cki; - - do - { - cki = Console.ReadKey(true); - - switch (cki.Key) - { - case ConsoleKey.UpArrow: - sr.SelectPrevioustLine(); - break; - case ConsoleKey.DownArrow: - sr.SelectNextLine(); - break; - case ConsoleKey.Backspace: - if (sb.Length > 0) - { - sb.Remove(sb.Length - 1, 1); - sr.ComputeSearch(sb.ToString()); - } - break; - default: - sb.Append(cki.KeyChar); - sr.ComputeSearch(sb.ToString()); - break; - } - - sr.UpdateDisplay(); - - } while (cki.Key != ConsoleKey.Enter); - - return sr.CurrentSelected; - } - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +using Model; + +namespace ConsoleApp.Menu +{ + /// + /// An utility to find a recipe. + /// + internal class SearcherRecipe : Menu + { + private readonly RecipeCollection _recipeCollectionOnSearch; + + public SearcherRecipe(RecipeCollection recipeCollection) : base("Search recipe") + { + _recipeCollectionOnSearch = recipeCollection; + _allSelectors = ConvertRecipeCollectionInSelectors(); + _selectList = _allSelectors; + } + + #region Methods + private List> ConvertRecipeCollectionInSelectors() + { + List> newSelectors = new List>(); + foreach (Recipe recipe in _recipeCollectionOnSearch) + { + newSelectors.Add(new Selector(recipe, $"[{recipe.Id}]: {recipe.Title}")); + } + return newSelectors; + } + + public override IMenu? Return() + { + if (CurrentSelected == null) + throw new ArgumentNullException("CurrentSelected"); + + return new PlainText(CurrentSelected.ToString()); + } + #endregion + } +} diff --git a/MCTG/ConsoleApp/Menu/SelectMenu.cs b/MCTG/ConsoleApp/Menu/SelectMenu.cs deleted file mode 100644 index 0e331c6..0000000 --- a/MCTG/ConsoleApp/Menu/SelectMenu.cs +++ /dev/null @@ -1,52 +0,0 @@ -using ConsoleApp; -using Model; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - - -namespace ConsoleApp.Menu -{ - /// - /// An abstract class that define the components of a selection-type menu. - /// - /// The return type of the currently selected item - public abstract class SelectMenu : IMenuDisplay - { - protected int _currentLine = 0; - protected int _maxLines = 0; - - /// - /// The currently selected item. - /// - public T? CurrentSelected { get; protected set; } - - /// - /// The current line selected in the menu. - /// - public int CurrentLine - { - get => _currentLine; - protected set - { - _currentLine = value; - if (_currentLine > _maxLines) - { - _currentLine = _maxLines; - } - if (_currentLine < 0) - { - _currentLine = 0; - } - return; - } - } - - public int SelectNextLine() { return ++CurrentLine; } - public int SelectPrevioustLine() { return --CurrentLine; } - - public abstract void UpdateDisplay(); - } -} diff --git a/MCTG/ConsoleApp/Menu/Selector.cs b/MCTG/ConsoleApp/Menu/Selector.cs new file mode 100644 index 0000000..f8f71e0 --- /dev/null +++ b/MCTG/ConsoleApp/Menu/Selector.cs @@ -0,0 +1,76 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection.Emit; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp.Menu +{ + /// + /// The selector of a menu. + /// + /// The type of the selector. + internal class Selector : IEquatable> + where T : notnull + { + #region Attributes & Properties + private string _line = ""; + + /// + /// The string that are displayed on the menu. + /// + public string Line { + get => _line; + private set + { + if (string.IsNullOrEmpty(value)) + _line = "no data"; + else + _line = value; + } + } + + /// + /// The item contained in the selector. + /// + public T Item { get; private set; } + #endregion + + #region Constructors + /// + /// The constructor of the selector. + /// + /// The item to place inside. + /// The string to display in the menu. + public Selector(T item, string line = "") + { + Line = line; + Item = item; + } + #endregion + + #region IEquatable implementation + public virtual bool Equals(Selector? other) + { + if (other == null) return false; + if (other == this) return true; + return other.Line.Equals(this.Line); + } + + public override bool Equals(object? obj) + { + var item = obj as Selector; + if (item == null) return false; + return Equals(obj); + } + + public override int GetHashCode() + { + return Line.GetHashCode(); + } + #endregion + } +} diff --git a/MCTG/ConsoleApp/MenuManager.cs b/MCTG/ConsoleApp/MenuManager.cs new file mode 100644 index 0000000..20cf567 --- /dev/null +++ b/MCTG/ConsoleApp/MenuManager.cs @@ -0,0 +1,90 @@ +using ConsoleApp.Menu; +using Model; +using DataPersistence; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp +{ + /// + /// Manage the menus of the console application. + /// + internal class MenuManager + { + #region Attributes & Properties + /// + /// The manager that contains usefull data taken from the model. + /// + public DataManager DataManager { get; private set; } + + /// + /// Each menu called are push in this stack. Then, to return back, we pop this stack to retrive the previous menu. + /// + public Stack MenuCallStack { get; set; } + #endregion + + #region Constructors + /// + /// Constructor of the MenuManager class. This constructor allows you to give the first menu of the call stack, wich is usefull for testing. + /// + /// The data manager needed by the menus inside. + /// The starting menu, the first that will be push on the call stack. + public MenuManager(DataManager dataManager, Menu.IMenu firstMenu) + { + DataManager = dataManager; + + MenuCallStack = new Stack(); + MenuCallStack.Push(firstMenu); + } + + /// + /// Constructor of the MenuManager class. + /// + /// The data manager needed by the menus inside. + public MenuManager(DataManager dataManager) : this(dataManager, new MainMenu(dataManager)) + { } + #endregion + + #region Methods + /// + /// Main loop. Loop while the menu call stack is not empty. + /// + public void Loop() + { + ConsoleKeyInfo cki; + Menu.IMenu menuOnHead; + do + { + menuOnHead = MenuCallStack.Peek(); + menuOnHead.Update(); + menuOnHead.Display(); + + cki = Console.ReadKey(true); + switch (cki.Key) + { + case ConsoleKey.DownArrow: + menuOnHead.SelectNext(); + break; + case ConsoleKey.UpArrow: + menuOnHead.SelectPrevious(); + break; + case ConsoleKey.Enter: + Menu.IMenu? retMenu = menuOnHead.Return(); + if (retMenu is null) MenuCallStack.Pop(); + else MenuCallStack.Push(retMenu); + break; + case ConsoleKey.LeftArrow: + MenuCallStack.Pop(); + break; + default: + menuOnHead.WriteMenuMode(cki); + break; + } + } while (MenuCallStack.Count > 0); + } + #endregion + } +} diff --git a/MCTG/ConsoleApp/Program.cs b/MCTG/ConsoleApp/Program.cs index 554006c..65c6564 100644 --- a/MCTG/ConsoleApp/Program.cs +++ b/MCTG/ConsoleApp/Program.cs @@ -11,12 +11,12 @@ Console.WriteLine("Hello, World!\n\n"); // TESTS: -//DataManager dataMgr = new DataManager(new Stubs()); +DataManager dataMgr = new DataManager(new Stubs()); //DataManager dataMgr = new DataManager(new DataContractXML(xmlFolderPath: "../../../../DataPersistence/data")); -DataManager dataMgr = new DataManager(new DataContractJSON(jsonFolderPath: "../../../../DataPersistence/data")); +//DataManager dataMgr = new DataManager(new DataContractJSON()); //dataMgr.Serializer = new DataContractXML(xmlFolderPath: "../../../../DataPersistence/data"); -//dataMgr.Serializer = new DataContractJSON(jsonFolderPath: "../../../../DataPersistence/data"); +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. @@ -25,10 +25,11 @@ DataManager dataMgr = new DataManager(new DataContractJSON(jsonFolderPath: "../. RecipeCollection rc = new RecipeCollection("All recipes", dataMgr.Data[nameof(Recipe)].Cast().ToArray()); -Recipe? ret = SearcherRecipe.ResearchOn(rc); -Console.WriteLine(ret); - dataMgr.Save(); +MenuManager menuMgr = new MenuManager(dataMgr); + +menuMgr.Loop(); + // press any key to quit -Console.ReadKey(); +//Console.ReadKey(); diff --git a/MCTG/Model/Manager/Manager.cs b/MCTG/Model/Manager/Manager.cs deleted file mode 100644 index 5c4a6a7..0000000 --- a/MCTG/Model/Manager/Manager.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Model -{ - /// - /// Manager of the model. Here is stoked all the recipes, the users, etc... - /// - public class Manager - { - /// - /// A collection of all the recipe loaded in the app. - /// - public RecipeCollection AllRecipes { get; protected set; } - - /// - /// The constructor of the manager. - /// - public Manager() - { - AllRecipes = new RecipeCollection(description: "All Recipes"); - } - - /// - /// The constructor of the manager. - /// - /// A list of loaded recipes - public Manager(RecipeCollection allRecipes) - { - AllRecipes = new RecipeCollection( - description: "All Recipes", - recipes: allRecipes.ToArray()); - } - } -} diff --git a/MCTG/Model/Recipes/RecipeCollection.cs b/MCTG/Model/Recipes/RecipeCollection.cs index d439c76..a1d8393 100644 --- a/MCTG/Model/Recipes/RecipeCollection.cs +++ b/MCTG/Model/Recipes/RecipeCollection.cs @@ -10,10 +10,9 @@ namespace Model /// Define a collection of . ///
This class implement and . /// - public class RecipeCollection : IList, IEquatable + public class RecipeCollection : List, IEquatable { #region Attributes - private readonly List _recipes; private string _description = ""; #endregion @@ -33,12 +32,6 @@ namespace Model _description = value; } } - - #region IList Prperties - public int Count => _recipes.Count; - public bool IsReadOnly => false; - public Recipe this[int index] { get => _recipes[index]; set => _recipes[index] = value; } - #endregion #endregion #region Constructors @@ -48,8 +41,8 @@ namespace Model /// A short description of what this list will contain /// Recipes to add in this new collection public RecipeCollection(string description, params Recipe[] recipes) + : base(recipes) { - _recipes = new List(recipes); Description = description; } #endregion @@ -63,7 +56,7 @@ namespace Model /// public Recipe? GetRecipeById(int id) { - Recipe? recipe = _recipes.Find(r => r.Id == id); + Recipe? recipe = this.Find(r => r.Id == id); if (recipe == null) throw new ArgumentException("No _recipes match the given id."); return recipe; } @@ -77,66 +70,14 @@ namespace Model { return new RecipeCollection( description: $"Results of the research: {str}", - recipes: _recipes.FindAll(x => x.Title.ToLower().Contains(str.ToLower())).ToArray()); - } - - #region IList Methods - public int IndexOf(Recipe item) - { - return _recipes.IndexOf(item); - } - - public void Insert(int index, Recipe item) - { - _recipes.Insert(index, item); - } - - public void RemoveAt(int index) - { - _recipes.RemoveAt(index); - } - - public void Add(Recipe item) - { - _recipes.Add(item); - } - - public void Clear() - { - _recipes.Clear(); + recipes: this.FindAll(x => x.Title.ToLower().Contains(str.ToLower())).ToArray()); } - public bool Contains(Recipe item) - { - return _recipes.Contains(item); - } - - public void CopyTo(Recipe[] array, int arrayIndex) - { - _recipes.CopyTo(array, arrayIndex); - } - - public bool Remove(Recipe item) - { - return _recipes.Remove(item); - } - - public IEnumerator GetEnumerator() - { - return _recipes.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _recipes.GetEnumerator(); - } - #endregion - public virtual bool Equals(RecipeCollection? other) { if (other == null) return false; if (other == this) return true; - return _description.Equals(other.Description) && _recipes.Equals(other._recipes); + return this.Description.Equals(other.Description); } public override bool Equals(object? obj) @@ -148,13 +89,13 @@ namespace Model public override int GetHashCode() { - return _recipes.GetHashCode(); + return Description.GetHashCode(); } public override string ToString() { StringBuilder sb = new StringBuilder($"[RecipeCollection] - {Description}:\n"); - foreach (Recipe r in _recipes) + foreach (Recipe r in this) { sb.AppendFormat("\t - {0}\n", r.ToString()); } diff --git a/MCTG/Tests/Model_UnitTests/Model_UnitTests.csproj b/MCTG/Tests/Model_UnitTests/Model_UnitTests.csproj index 318f712..2a658d9 100644 --- a/MCTG/Tests/Model_UnitTests/Model_UnitTests.csproj +++ b/MCTG/Tests/Model_UnitTests/Model_UnitTests.csproj @@ -21,5 +21,6 @@ + \ No newline at end of file diff --git a/MCTG/Tests/Model_UnitTests/RecipeCollection_UT.cs b/MCTG/Tests/Model_UnitTests/RecipeCollection_UT.cs index 36008b1..3f09b70 100644 --- a/MCTG/Tests/Model_UnitTests/RecipeCollection_UT.cs +++ b/MCTG/Tests/Model_UnitTests/RecipeCollection_UT.cs @@ -22,7 +22,10 @@ namespace Model_UnitTests new Recipe(title: "Gateau aux cerises", id: 3) }); - Assert.Equal(2, recipes.ResearchByName("chocolat").FirstOrDefault().Id); + Recipe? recipe = recipes.ResearchByName("chocolat").FirstOrDefault(); + + Assert.NotNull(recipe); + Assert.Equal(2, recipe.Id); } } } diff --git a/MCTG/Tests/Model_UnitTests/test_unit_user.cs b/MCTG/Tests/Model_UnitTests/test_unit_user.cs index 943afa0..1756e20 100644 --- a/MCTG/Tests/Model_UnitTests/test_unit_user.cs +++ b/MCTG/Tests/Model_UnitTests/test_unit_user.cs @@ -12,8 +12,8 @@ namespace Model_UnitTests [Fact] public void TestConstructUser() { - User user = new User("Bob","Dylan", "bd@gmail.com"); - //Assert. + User? user = new User("Bob","Dylan", "bd@gmail.com"); + Assert.NotNull(user); } } }