diff --git a/Rendu/SAE2.01 - Description de l'architecture de l'application.pdf b/Rendu/SAE2.01 - Description de l'architecture de l'application.pdf index cd0786f..8bfe471 100644 Binary files a/Rendu/SAE2.01 - Description de l'architecture de l'application.pdf and b/Rendu/SAE2.01 - Description de l'architecture de l'application.pdf differ diff --git a/Sources/Persistance/Persistance.cs b/Sources/Persistance/Persistance.cs index 9f6b0d8..80609bc 100644 --- a/Sources/Persistance/Persistance.cs +++ b/Sources/Persistance/Persistance.cs @@ -12,9 +12,15 @@ namespace StimPersistance [ExcludeFromCodeCoverage] public class Persistance : IPersistance { - public Persistance(string chemin) + private const string gameFileName = "games.xml"; + private const string userFileName = "users.xml"; + private readonly string fullGamePath; + private readonly string fullUserPath; + + public Persistance(string path) { - Directory.SetCurrentDirectory(chemin); + fullGamePath = Path.Combine(path, gameFileName); + fullUserPath = Path.Combine(path, userFileName); } public void SaveGame(List games) @@ -22,7 +28,7 @@ namespace StimPersistance XmlWriterSettings settings = new() { Indent = true }; DataContractSerializer serializer = new(typeof(List)); - using (TextWriter tw = File.CreateText("games.xml")) + using (TextWriter tw = File.CreateText(fullGamePath)) using (XmlWriter writer = XmlWriter.Create(tw, settings)) serializer.WriteObject(writer, games); } @@ -31,26 +37,26 @@ namespace StimPersistance XmlWriterSettings settings = new() { Indent = true }; DataContractSerializer serializer = new(typeof(HashSet)); - using (TextWriter tw = File.CreateText("users.xml")) + using (TextWriter tw = File.CreateText(fullUserPath)) using (XmlWriter writer = XmlWriter.Create(tw, settings)) serializer.WriteObject(writer, users); } public List LoadGame() { - if (File.Exists("games.xml")) + if (File.Exists(fullGamePath)) { DataContractSerializer serializer = new(typeof(List)); - using (Stream stream = File.OpenRead("games.xml")) return serializer.ReadObject(stream) as List ?? new(); + using (Stream stream = File.OpenRead(fullGamePath)) return serializer.ReadObject(stream) as List ?? new(); } return new(); } public HashSet LoadUser() { - if (File.Exists("users.xml")) + if (File.Exists(fullUserPath)) { DataContractSerializer serializer = new(typeof(HashSet)); - using (Stream stream = File.OpenRead("users.xml")) return serializer.ReadObject(stream) as HashSet ?? new(); + using (Stream stream = File.OpenRead(fullUserPath)) return serializer.ReadObject(stream) as HashSet ?? new(); } return new(); } diff --git a/Sources/Stim.Model/Game.cs b/Sources/Stim.Model/Game.cs index 2b7a874..df29884 100644 --- a/Sources/Stim.Model/Game.cs +++ b/Sources/Stim.Model/Game.cs @@ -15,15 +15,12 @@ namespace Model get => name; private set { - if (string.IsNullOrWhiteSpace(value)) name="Default"; - else - { - name = value; - NotifyPropertyChanged(); - } + if (string.IsNullOrWhiteSpace(value)) name = "Default"; + else name = value; + NotifyPropertyChanged(); } } - private string name; + private string name = default!; [DataMember] public string Description @@ -31,15 +28,12 @@ namespace Model get => description; private set { - if (string.IsNullOrWhiteSpace(value)) return; - else - { - description = value; - NotifyPropertyChanged(); - } + if (string.IsNullOrWhiteSpace(value)) description = "Defaut"; + else description = value; + NotifyPropertyChanged(); } } - private string description; + private string description = default!; [DataMember] public int Year @@ -47,15 +41,12 @@ namespace Model get => year; private set { - if (value < 1957 || value > 2023) return; - else - { - year = value; - NotifyPropertyChanged(); - } + if (value < 1957 || value > 2023) year = 2023; + else year = value; + NotifyPropertyChanged(); } } - private int year; + private int year = default!; [DataMember] public string Cover @@ -63,15 +54,12 @@ namespace Model get => cover; private set { - if (string.IsNullOrWhiteSpace(value)) cover="no_cover.png"; - else - { - cover = value; - NotifyPropertyChanged(); - } + if (string.IsNullOrWhiteSpace(value)) cover = "no_cover.png"; + else cover = value; + NotifyPropertyChanged(); } } - private string cover; + private string cover = default!; [DataMember] public ObservableCollection Tags @@ -79,12 +67,9 @@ namespace Model get => tags; private set { - if (value == null || value.Count > 3) return; - else - { - tags = value; - NotifyPropertyChanged(); - } + if (value == null || value.Count > 3) tags = new ObservableCollection(); + else tags = value; + NotifyPropertyChanged(); } } private ObservableCollection tags; @@ -93,27 +78,19 @@ namespace Model public ReadOnlyCollection Reviews { get; private set; } private readonly List reviews; - public double Average => AverageCalc(); - public double AverageCalc() - { - if (Reviews.Count > 0) return Math.Round((double)Reviews.Select(review => review.Rate).Average(), 1); - else return 0; - } + public double Average => Reviews.Any() ? Math.Round(Reviews.Select(review => review.Rate).Average(), 1) : 0; [DataMember] public string Lien { get => lien; private set { - if (string.IsNullOrWhiteSpace(value)) return; - else - { - lien = value; - NotifyPropertyChanged(); - } + if (string.IsNullOrWhiteSpace(value)) lien = "Pas de lien"; + else lien = value; + NotifyPropertyChanged(); } } - private string lien; + private string lien = default!; public Game(string name, string description, int year, List c_tags, string cover, string c_lien) { @@ -135,12 +112,7 @@ namespace Model public event PropertyChangedEventHandler? PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); public override int GetHashCode() { diff --git a/Sources/Stim.Model/Manager.cs b/Sources/Stim.Model/Manager.cs index 87db3e3..8ef7a73 100644 --- a/Sources/Stim.Model/Manager.cs +++ b/Sources/Stim.Model/Manager.cs @@ -1,13 +1,14 @@ using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Model { public class Manager { - private readonly IPersistance mgrpersistance; - public IReadOnlyList GameList => gameList.AsReadOnly(); - private List gameList; + public readonly IPersistance mgrpersistance; + public ReadOnlyCollection GameList { get; private set; } + private readonly List gameList; public Game? SelectedGame { get; set; } public User? CurrentUser { get; set; } public HashSet Users { get; private set; } @@ -16,42 +17,44 @@ namespace Model { mgrpersistance = persistance; gameList = persistance.LoadGame(); + GameList = new ReadOnlyCollection(gameList); Users = persistance.LoadUser(); } public IEnumerable FilterGames(string? filterName, string? filterTag1, string? filterTag2) { IEnumerable retList; - retList = GameList; + retList = gameList; if (filterName != null) retList = retList - .Where(game => game.Name.IndexOf(filterName, StringComparison.OrdinalIgnoreCase) >= 0 + .Where(game => game.Name.Contains(filterName, StringComparison.OrdinalIgnoreCase) ); if (filterTag1 != null) retList = retList - .Where(game => game.Tags != null && game.Tags.Any(tag => tag != null && tag.IndexOf(filterTag1, StringComparison.OrdinalIgnoreCase) >= 0) + .Where(game => game.Tags != null && game.Tags.Any(tag => tag != null && tag.Contains(filterTag1, StringComparison.OrdinalIgnoreCase)) ); if (filterTag2 != null) retList = retList - .Where(game => game.Tags != null && game.Tags.Any(tag => tag != null && tag.IndexOf(filterTag2, StringComparison.OrdinalIgnoreCase) >= 0) + .Where(game => game.Tags != null && game.Tags.Any(tag => tag != null && tag.Contains(filterTag2, StringComparison.OrdinalIgnoreCase)) ); return retList; } public void AddGametoGamesList(Game game) { - gameList.Add(game); + if (!gameList.Contains(game)) gameList.Add(game); mgrpersistance.SaveGame(gameList); } public void AddUsertoUserList(User user) { - Users.Add(user); + if (!Users.Contains(user)) Users.Add(user); mgrpersistance.SaveUser(Users); } public void RemoveGameFromGamesList(Game game) { + SelectedGame = null; gameList.Remove(game); mgrpersistance.SaveGame(gameList); } - + [ExcludeFromCodeCoverage] public void SaveGames() { mgrpersistance.SaveGame(gameList); @@ -64,6 +67,7 @@ namespace Model } return null; } + [ExcludeFromCodeCoverage] public void SaveUser() { mgrpersistance.SaveUser(Users); diff --git a/Sources/Stim.Model/Review.cs b/Sources/Stim.Model/Review.cs index 7137bec..894244b 100644 --- a/Sources/Stim.Model/Review.cs +++ b/Sources/Stim.Model/Review.cs @@ -1,21 +1,24 @@ -using System.Runtime.Serialization; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; namespace Model { [DataContract] - public class Review + public class Review :INotifyPropertyChanged { [DataMember] - public float Rate + public double Rate { get => rate; private set { - if (value < 0 || value > 5) return; - rate = value; + if (value < 0 || value > 5) rate = 0; + else rate = value; + NotifyPropertyChanged(); } } - private float rate; + private double rate; [DataMember] public string? Text @@ -23,16 +26,21 @@ namespace Model get => text; private set { - if (string.IsNullOrWhiteSpace(value)) return; - text = value; + if (string.IsNullOrWhiteSpace(value)) text = "Default"; + else text = value; + NotifyPropertyChanged(); } } private string? text; + public event PropertyChangedEventHandler? PropertyChanged; + private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + [DataMember] public string AuthorName { get; set; } - public Review(string username, float rate, string text) + public Review(string username, double rate, string text) { AuthorName = username; Rate = rate; @@ -48,7 +56,7 @@ namespace Model { if (!string.IsNullOrWhiteSpace(text)) Text = text+" (Modifié)"; } - public void EditRate(float newval) + public void EditRate(double newval) { if (newval >= 0 && newval <= 5) Rate= newval; } diff --git a/Sources/Stim.Model/User.cs b/Sources/Stim.Model/User.cs index 553e3f8..7bd43f6 100644 --- a/Sources/Stim.Model/User.cs +++ b/Sources/Stim.Model/User.cs @@ -11,42 +11,48 @@ namespace Model public sealed class User : INotifyPropertyChanged , IEquatable { [DataMember] - public string Username + public string UserImage + { + get => userImage; + private set + { + if (!string.IsNullOrWhiteSpace(value)) userImage = value; + else userImage = "no_cover.png"; + NotifyPropertyChanged(); + } + } + private string userImage = default!; + [DataMember] + public string? Username { get => username; set { if (string.IsNullOrWhiteSpace(value)) username = "Default"; - else - { - username = value; - NotifyPropertyChanged(); - } + else username = value; + NotifyPropertyChanged(); } } - private string username; + private string username=default!; [DataMember] public string Biographie { - get => biographie ?? "Pas de biographie"; + get => biographie; set { if (string.IsNullOrWhiteSpace(value)) biographie = "Pas de biographie"; - else - { - biographie = value; - NotifyPropertyChanged(); - } + else biographie = value; + NotifyPropertyChanged(); } } - private string biographie; + private string biographie = default!; [DataMember] public string Email { get => email; set { - Regex rg_email = new Regex("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"); + Regex rg_email = new Regex("^([a-zA-Z0-9_-]+[.])*[a-zA-Z0-9_-]+@([a-zA-Z0-9_-]+[.])+[a-zA-Z0-9_-]{2,4}$"); if (!(string.IsNullOrWhiteSpace(value)) && rg_email.IsMatch(value)) { email = value; @@ -55,7 +61,7 @@ namespace Model else email = "Default"; } } - private string email; + private string email = default!; [DataMember] public string Password { @@ -71,17 +77,12 @@ namespace Model } } } - private string password; + private string password = default!; public event PropertyChangedEventHandler? PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); [DataMember] public ObservableCollection Followed_Games @@ -89,17 +90,6 @@ namespace Model get; private init; } - [DataMember] - public string? UserImage - { - get => userImage; - private set - { - if (!string.IsNullOrWhiteSpace(value)) userImage = value; - else userImage = "no_cover.png"; - } - } - private string? userImage; public User(string userImage,string username, string biographie, string email, string password) { @@ -111,7 +101,7 @@ namespace Model else Biographie = biographie; if (email == null) Email = "Default"; else Email = email; - if (password == null) throw new ArgumentNullException("password"); + if (password == null) throw new ArgumentNullException(nameof(password)); else Password = password; Followed_Games = new ObservableCollection(); } @@ -120,6 +110,15 @@ namespace Model if (string.IsNullOrWhiteSpace(Username)) return false; return other != null && Username.Equals(other.Username); } + + public override bool Equals(object? obj) + { + if (obj == null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return this.Equals((User)obj); + } + public override int GetHashCode() { if (Username!=null) return Username.GetHashCode(); @@ -152,14 +151,6 @@ namespace Model Followed_Games.Remove(game); } - public override bool Equals(object? obj) - { - if (obj == null) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return this.Equals((User)obj); - } - public override string ToString() { StringBuilder builder = new(); diff --git a/Sources/Stim/AddGamePage.xaml b/Sources/Stim/AddGamePage.xaml index 102f203..385823a 100644 --- a/Sources/Stim/AddGamePage.xaml +++ b/Sources/Stim/AddGamePage.xaml @@ -5,6 +5,7 @@ x:Class="Stim.AddGamePage" Title="Ajouter un jeu" Background="{StaticResource Secondary}"> + @@ -23,9 +24,9 @@ - + - + - - + + + + diff --git a/Sources/Stim/ProfilPage.xaml.cs b/Sources/Stim/ProfilPage.xaml.cs index 20f6dff..1b26846 100644 --- a/Sources/Stim/ProfilPage.xaml.cs +++ b/Sources/Stim/ProfilPage.xaml.cs @@ -1,5 +1,6 @@ using CommunityToolkit.Maui.Views; using Model; +using System.Text.RegularExpressions; namespace Stim; @@ -22,4 +23,29 @@ public partial class ProfilPage : ContentPage if (string.IsNullOrWhiteSpace(newName as string)) await this.ShowPopupAsync(new MessagePopup("Nom d'utilisateur invalide")); else ((App)App.Current).Manager.CurrentUser.Username = (newName as string); } + public async void PopUpUsername(object sender, EventArgs e) + { + var newName = await this.ShowPopupAsync(new EntryPopup("Username")); + if (string.IsNullOrWhiteSpace(newName as string)) await this.ShowPopupAsync(new MessagePopup("Nom d'utilisateur invalide")); + else ((App)App.Current).Manager.CurrentUser.Username = (newName as string); + } + public async void PopUpBio(object sender, EventArgs e) + { + var newBio = await this.ShowPopupAsync(new EntryPopup("Biographie")); + ((App)App.Current).Manager.CurrentUser.Biographie = (newBio as string); + } + public async void PopUpPswd(object sender, EventArgs e) + { + Regex rg = new Regex("^(?=.*[A-Za-z])(?=.*[0-9@$!%*#?&])[A-Za-z-0-9@$!%*#?&]{8,}$"); + var newPswd = await this.ShowPopupAsync(new EntryPopup("Password")); + if (string.IsNullOrWhiteSpace(newPswd as string) || rg.IsMatch(newPswd as string)) await this.ShowPopupAsync(new MessagePopup("Nom d'utilisateur invalide")); + else ((App)App.Current).Manager.CurrentUser.Password = (newPswd as string); + } + public async void PopUpEmail(object sender, EventArgs e) + { + Regex rg = new Regex("^([a-zA-Z0-9_-]+[.])*[a-zA-Z0-9_-]+@([a-zA-Z0-9_-]+[.])+[a-zA-Z0-9_-]{2,4}$"); + var newMail = await this.ShowPopupAsync(new EntryPopup("Email")); + if (string.IsNullOrWhiteSpace(newMail as string) || rg.IsMatch(newMail as string)) await this.ShowPopupAsync(new MessagePopup("Email Invalide")); + else ((App)App.Current).Manager.CurrentUser.Email = (newMail as string); + } } \ No newline at end of file diff --git a/Sources/Stim/Resources/Images/remove_black.png b/Sources/Stim/Resources/Images/remove_black.png new file mode 100644 index 0000000..e2ad22f Binary files /dev/null and b/Sources/Stim/Resources/Images/remove_black.png differ diff --git a/Sources/Stim/Resources/Images/remove_red.png b/Sources/Stim/Resources/Images/remove_red.png new file mode 100644 index 0000000..dfc2dd8 Binary files /dev/null and b/Sources/Stim/Resources/Images/remove_red.png differ diff --git a/Sources/Stim/Resources/Images/remove_white.png b/Sources/Stim/Resources/Images/remove_white.png new file mode 100644 index 0000000..8dfb79d Binary files /dev/null and b/Sources/Stim/Resources/Images/remove_white.png differ diff --git a/Sources/Stim/Resources/Styles/Styles.xaml b/Sources/Stim/Resources/Styles/Styles.xaml index 785c236..e49b846 100644 --- a/Sources/Stim/Resources/Styles/Styles.xaml +++ b/Sources/Stim/Resources/Styles/Styles.xaml @@ -384,5 +384,65 @@ + + + + + + + + + + + + + + + + + + diff --git a/Sources/Stim/ReviewPopUp.xaml b/Sources/Stim/ReviewPopUp.xaml new file mode 100644 index 0000000..ec8a6e5 --- /dev/null +++ b/Sources/Stim/ReviewPopUp.xaml @@ -0,0 +1,16 @@ + + + + +