diff --git a/.DS_Store b/.DS_Store
index 5d1ff1d..2c8816e 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/sources/DtoAbstractLayer/DtoAbstractLayer.csproj b/sources/DtoAbstractLayer/DtoAbstractLayer.csproj
new file mode 100644
index 0000000..496da7a
--- /dev/null
+++ b/sources/DtoAbstractLayer/DtoAbstractLayer.csproj
@@ -0,0 +1,12 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
diff --git a/sources/DtoAbstractLayer/IDtoManager.cs b/sources/DtoAbstractLayer/IDtoManager.cs
new file mode 100644
index 0000000..4edf2da
--- /dev/null
+++ b/sources/DtoAbstractLayer/IDtoManager.cs
@@ -0,0 +1,97 @@
+using LibraryDTO;
+
+namespace DtoAbstractLayer;
+
+///
+/// abstract layer for requests on Books Library
+///
+public interface IDtoManager
+{
+ ///
+ /// get a book by specifying its id
+ ///
+ /// id of the Book to get
+ /// a Book with this id (or null if id is unknown)
+ Task GetBookById(string id);
+
+ ///
+ /// get a book by specifying its isbn
+ ///
+ /// isbn of the Book to get
+ /// a Book with this isbn (or null if isbn is unknown)
+ Task GetBookByISBN(string isbn);
+
+ ///
+ /// get books containing a substring in their titles
+ ///
+ /// the substring to look for in book titles
+ /// index of the page of resulting books
+ /// number of resulting books per page
+ /// sort criterium (not mandatory):
+ ///
+ ///
```title```: sort books by titles in alphabetical order,
+ ///
```title_reverse```: sort books by titles in reverse alphabetical order,
+ ///
```new```: sort books by publishing dates, beginning with the most recents,
+ ///
```old```: sort books by publishing dates, beginning with the oldest
+ ///
+ ///
+ /// max count books
+ Task>> GetBooksByTitle(string title, int index, int count, string sort = "");
+
+ ///
+ /// get books of a particular author by giving the author id
+ ///
+ /// the id of the author
+ /// index of the page of resulting books
+ /// number of resulting books per page
+ /// sort criterium (not mandatory):
+ ///
+ ///
```title```: sort books by titles in alphabetical order,
+ ///
```title_reverse```: sort books by titles in reverse alphabetical order,
+ ///
```new```: sort books by publishing dates, beginning with the most recents,
+ ///
```old```: sort books by publishing dates, beginning with the oldest
+ ///
+ ///
+ /// max count books
+ Task>> GetBooksByAuthorId(string authorId, int index, int count, string sort = "");
+
+ ///
+ /// get books of authors whose name (or alternate names) contains a particular substring
+ ///
+ /// name to look for in author names or alternate names
+ /// index of the page of resulting books
+ /// number of resulting books per page
+ /// sort criterium (not mandatory):
+ ///
+ ///
```title```: sort books by titles in alphabetical order,
+ ///
```title_reverse```: sort books by titles in reverse alphabetical order,
+ ///
```new```: sort books by publishing dates, beginning with the most recents,
+ ///
```old```: sort books by publishing dates, beginning with the oldest
+ ///
+ ///
+ /// max count books
+ Task>> GetBooksByAuthor(string author, int index, int count, string sort = "");
+
+ ///
+ /// get an author by specifying its id
+ ///
+ /// id of the Author to get
+ /// an author with this id (or null if id is unknown)
+ Task GetAuthorById(string id);
+
+ ///
+ /// get authors containing a substring in their names (or alternate names)
+ ///
+ /// the substring to look for in author names (or alternate names)
+ /// index of the page of resulting authors
+ /// number of resulting authors per page
+ /// sort criterium (not mandatory):
+ ///
+ ///
```name```: sort authors by names in alphabetical order,
+ ///
```name_reverse```: sort authors by names in reverse alphabetical order,
+ ///
+ ///
+ /// max count authors
+ Task>> GetAuthorsByName(string substring, int index, int count, string sort = "");
+}
+
diff --git a/sources/ExtensionsAndMappers/Class1.cs b/sources/ExtensionsAndMappers/Class1.cs
new file mode 100644
index 0000000..ed6e84a
--- /dev/null
+++ b/sources/ExtensionsAndMappers/Class1.cs
@@ -0,0 +1,7 @@
+namespace ExtensionsAndMappers;
+
+public class Class1
+{
+
+}
+
diff --git a/sources/ExtensionsAndMappers/ExtensionsAndMappers.csproj b/sources/ExtensionsAndMappers/ExtensionsAndMappers.csproj
new file mode 100644
index 0000000..4658cbf
--- /dev/null
+++ b/sources/ExtensionsAndMappers/ExtensionsAndMappers.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/sources/JsonReader/AuthorJsonReader.cs b/sources/JsonReader/AuthorJsonReader.cs
new file mode 100644
index 0000000..0ae07db
--- /dev/null
+++ b/sources/JsonReader/AuthorJsonReader.cs
@@ -0,0 +1,80 @@
+using System;
+using LibraryDTO;
+using Newtonsoft.Json.Linq;
+using System.Globalization;
+
+namespace JsonReader
+{
+ public static class AuthorJsonReader
+ {
+ public static AuthorDTO ReadAuthor(string json)
+ {
+ JObject o = JObject.Parse(json);
+ string bioTokenAsString = null;
+ if(o.TryGetValue("bio", out JToken? bioToken))
+ {
+ if(bioToken.Type == JTokenType.String)
+ {
+ bioTokenAsString = (string)bioToken;
+ }
+ else
+ {
+ var bioTokenValue = o["bio"]?["value"];
+ bioTokenAsString = (string)bioTokenValue;
+ }
+ }
+
+ AuthorDTO author = new AuthorDTO
+ {
+ Id = (string)o["key"],
+ Name = (string)o["name"],
+ Bio = bioTokenAsString,
+ BirthDate = o.TryGetValue("birth_date", out JToken? bd) ? ReadDate((string)o["birth_date"]) : null,
+ DeathDate = o.TryGetValue("death_date", out JToken? dd) ? ReadDate((string)o["death_date"]) : null,
+ Links = o.TryGetValue("links", out JToken? links) ? links.Select(l => new LinkDTO { Title = (string)l["title"], Url = (string)l["url"] }).ToList() : new List(),
+ AlternateNames = o.TryGetValue("alternate_names", out JToken? altNames) ? altNames.Select(alt => (string)alt).ToList() : new List()
+ };
+ return author;
+ }
+
+ public static DateTime? ReadDate(string dateInJson)
+ {
+ if(dateInJson == null) return null;
+
+ List> pubDateFormat =new List>()
+ {
+ Tuple.Create("d MMMM yyyy", CultureInfo.GetCultureInfo("fr-FR")),
+ Tuple.Create("d MMMM yyyy", CultureInfo.InvariantCulture),
+ Tuple.Create("MMM dd, yyyy", CultureInfo.InvariantCulture)
+ };
+
+ DateTime? publishDate = null;
+ foreach(var format in pubDateFormat)
+ {
+ if(DateTime.TryParseExact(dateInJson, format.Item1, format.Item2, DateTimeStyles.None, out DateTime readDate))
+ {
+ publishDate = readDate;
+ break;
+ }
+ }
+ if(!publishDate.HasValue && int.TryParse(dateInJson, out int year))
+ {
+ publishDate = new DateTime(year, 12, 31);
+ }
+ return publishDate;
+ }
+
+ public static Tuple> GetAuthorsByName(string json)
+ {
+ JObject o = JObject.Parse(json);
+ long numFound = (long)o["numFound"];
+ var authors = o["docs"].Select(doc => new AuthorDTO
+ {
+ Id = $"/authors/{(string)doc["key"]}",
+ Name = (string)doc["name"],
+ });
+ return Tuple.Create(numFound, authors);
+ }
+ }
+}
+
diff --git a/sources/JsonReader/BookJsonReader.cs b/sources/JsonReader/BookJsonReader.cs
new file mode 100644
index 0000000..ab2a87e
--- /dev/null
+++ b/sources/JsonReader/BookJsonReader.cs
@@ -0,0 +1,97 @@
+using System.Globalization;
+using LibraryDTO;
+using Newtonsoft.Json.Linq;
+
+namespace JsonReader;
+
+public static class BookJsonReader
+{
+ static Dictionary languages = new Dictionary()
+ {
+ [@"/languages/fre"] = Languages.French,
+ [@"/languages/eng"] = Languages.English,
+ ["fre"] = Languages.French,
+ ["eng"] = Languages.English,
+ [""] = Languages.Unknown
+ };
+
+ public static BookDTO ReadBook(string json)
+ {
+ JObject o = JObject.Parse(json);
+ var l = o["languages"]?.FirstOrDefault("");
+ Languages lang = l != null ? languages[(string)l["key"]] : Languages.Unknown;
+ //List> pubDateFormat =new List>()
+ //{
+ // Tuple.Create("d MMMM yyyy", CultureInfo.GetCultureInfo("fr-FR")),
+ // Tuple.Create("MMM dd, yyyy", CultureInfo.InvariantCulture)
+ //};
+
+ //DateTime? publishDate = null;
+ //foreach(var format in pubDateFormat)
+ //{
+ // if(DateTime.TryParseExact((string)o["publish_date"], format.Item1, format.Item2, DateTimeStyles.None, out DateTime readDate))
+ // {
+ // publishDate = readDate;
+ // break;
+ // }
+ //}
+ //if(!publishDate.HasValue)
+ //{
+ // publishDate = new DateTime((int)o["publish_date"], 12, 31);
+ //}
+ DateTime? publishDate = AuthorJsonReader.ReadDate((string)o["publish_date"]);
+
+ BookDTO book = new BookDTO
+ {
+ Id = (string)o["key"],
+ Title = (string)o["title"],
+ Publishers = o["publishers"].Select(p => (string)p).ToList(),
+ PublishDate = publishDate.GetValueOrDefault(DateTime.Now),
+ ISBN13 = (string)o["isbn_13"][0],
+ NbPages = o["number_of_pages"] != null ? (int)o["number_of_pages"] : -1,
+ Language = lang,
+ Format = o.TryGetValue("physical_format", out JToken? f) ? (string)f : null,
+ Works = o["works"].Select(w => new WorkDTO { Id = (string)w["key"] }).ToList(),
+ Contributors = o.TryGetValue("contributors", out JToken? contr) ? contr.Select(c => new ContributorDTO { Name = (string)c["name"], Role = (string)c["role"] }).ToList() : new List(),
+ Authors = o["authors"]?.Select(a => new AuthorDTO { Id = (string)a["key"] }).ToList()
+ };
+ if(book.Authors == null)
+ {
+ book.Authors = new List();
+ }
+ return book;
+ }
+
+ public static Tuple> GetBooksByAuthor(string json)
+ {
+ JObject o = JObject.Parse(json);
+ long numFound = (long)o["numFound"];
+ var books = o["docs"].Select(doc => new BookDTO
+ {
+ Id = (string)(doc["seed"].First()),
+ Title = (string)doc["title"],
+ ISBN13 = (string)(doc["isbn"].First()),
+ Authors = doc["seed"].Where(s => ((string)s).StartsWith("/authors/"))
+ .Select(s => new AuthorDTO { Id = (string)s }).ToList(),
+ Language = languages.GetValueOrDefault((string)(doc["language"].First()))
+ });
+ return Tuple.Create(numFound, books);
+ }
+
+ public static Tuple> GetBooksByTitle(string json)
+ {
+ JObject o = JObject.Parse(json);
+ long numFound = (long)o["numFound"];
+ var books = o["docs"].Select(doc => new BookDTO
+ {
+ Id = (string)(doc["seed"].First()),
+ Title = (string)doc["title"],
+ ISBN13 = (string)(doc["isbn"].First()),
+ Authors = doc["seed"].Where(s => ((string)s).StartsWith("/authors/"))
+ .Select(s => new AuthorDTO { Id = (string)s }).ToList(),
+ Language = languages.GetValueOrDefault((string)(doc["language"].First()))
+ });
+ return Tuple.Create(numFound, books);
+ }
+}
+
diff --git a/sources/JsonReader/JsonReader.csproj b/sources/JsonReader/JsonReader.csproj
new file mode 100644
index 0000000..8e77096
--- /dev/null
+++ b/sources/JsonReader/JsonReader.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
diff --git a/sources/JsonReader/WorkJsonReader.cs b/sources/JsonReader/WorkJsonReader.cs
new file mode 100644
index 0000000..387dbbd
--- /dev/null
+++ b/sources/JsonReader/WorkJsonReader.cs
@@ -0,0 +1,55 @@
+using System;
+using LibraryDTO;
+using Newtonsoft.Json.Linq;
+using System.Globalization;
+
+namespace JsonReader
+{
+ public static class WorkJsonReader
+ {
+ public static WorkDTO ReadWork(string json, string ratingsJson)
+ {
+ JObject o = JObject.Parse(json);
+ JObject r = JObject.Parse(ratingsJson);
+ var ratingsDto = new RatingsDTO();
+ if(r["summary"]["average"].Type != JTokenType.Float)
+ {
+ ratingsDto.Average = -1;
+ ratingsDto.Count = 0;
+ }
+ else
+ {
+ ratingsDto.Average = (float)r["summary"]["average"];
+ ratingsDto.Count = (int)r["summary"]["count"];
+ }
+
+ string description = null;
+ if(o.TryGetValue("description", out JToken? descr))
+ {
+ if(descr.Type == JTokenType.String)
+ {
+ description = (string)descr;
+ }
+ else
+ {
+ if (descr["value"].Type == JTokenType.String)
+ {
+ description = (string)descr["value"];
+ }
+ }
+ }
+
+ WorkDTO work = new WorkDTO
+ {
+ Id = (string)o["key"],
+ Title = (string)o["title"],
+ Authors = o.TryGetValue("authors", out JToken? authors) ? authors.Select(a => new AuthorDTO { Id = (string)a["author"]["key"] }).ToList() : new List(),
+ Description = description,
+ Subjects = o.TryGetValue("subjects", out JToken? subjects) ? subjects.Select(s => (string)s).ToList() : new List(),
+ Ratings = ratingsDto
+ };
+ return work;
+ }
+ }
+}
+
diff --git a/sources/LibraryDTO/AuthorDTO.cs b/sources/LibraryDTO/AuthorDTO.cs
new file mode 100644
index 0000000..22376e7
--- /dev/null
+++ b/sources/LibraryDTO/AuthorDTO.cs
@@ -0,0 +1,18 @@
+using System;
+namespace LibraryDTO
+{
+ public class AuthorDTO
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+ public string ImageSmall => $"https://covers.openlibrary.org/a/olid/{Id.Substring(Id.LastIndexOf("/"))}-S.jpg";
+ public string ImageMedium => $"https://covers.openlibrary.org/a/olid/{Id.Substring(Id.LastIndexOf("/"))}-M.jpg";
+ public string ImageLarge => $"https://covers.openlibrary.org/a/olid/{Id.Substring(Id.LastIndexOf("/"))}-L.jpg";
+ public string Bio { get; set; }
+ public List AlternateNames { get; set; } = new List();
+ public List Links { get; set; }
+ public DateTime? BirthDate { get; set; }
+ public DateTime? DeathDate { get; set; }
+ }
+}
+
diff --git a/sources/LibraryDTO/BookDTO.cs b/sources/LibraryDTO/BookDTO.cs
new file mode 100644
index 0000000..a260ae0
--- /dev/null
+++ b/sources/LibraryDTO/BookDTO.cs
@@ -0,0 +1,23 @@
+using System;
+namespace LibraryDTO
+{
+ public class BookDTO
+ {
+ public string Id { get; set; }
+ public string Title { get; set; }
+ public List Publishers { get; set; } = new List();
+ public DateTime PublishDate { get; set; }
+ public string ISBN13 { get; set; }
+ public List Series { get; set; } = new List();
+ public int NbPages { get; set; }
+ public string Format { get; set; }
+ public Languages Language { get; set; }
+ public List Contributors { get; set; }
+ public string ImageSmall => $"https://covers.openlibrary.org/b/isbn/{ISBN13}-S.jpg";
+ public string ImageMedium => $"https://covers.openlibrary.org/b/isbn/{ISBN13}-M.jpg";
+ public string ImageLarge => $"https://covers.openlibrary.org/b/isbn/{ISBN13}-L.jpg";
+ public List Works { get; set; } = new List();
+ public List Authors { get; set; } = new List();
+ }
+}
+
diff --git a/sources/LibraryDTO/ContributorDTO.cs b/sources/LibraryDTO/ContributorDTO.cs
new file mode 100644
index 0000000..beab5d1
--- /dev/null
+++ b/sources/LibraryDTO/ContributorDTO.cs
@@ -0,0 +1,10 @@
+using System;
+namespace LibraryDTO
+{
+ public class ContributorDTO
+ {
+ public string Name { get; set; }
+ public string Role { get; set; }
+ }
+}
+
diff --git a/sources/LibraryDTO/Languages.cs b/sources/LibraryDTO/Languages.cs
new file mode 100644
index 0000000..fcf51b5
--- /dev/null
+++ b/sources/LibraryDTO/Languages.cs
@@ -0,0 +1,11 @@
+using System;
+namespace LibraryDTO
+{
+ public enum Languages
+ {
+ Unknown,
+ French,
+ English
+ }
+}
+
diff --git a/sources/LibraryDTO/LibraryDTO.csproj b/sources/LibraryDTO/LibraryDTO.csproj
new file mode 100644
index 0000000..ef76c53
--- /dev/null
+++ b/sources/LibraryDTO/LibraryDTO.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+ 4
+ bin\Debug\net7.0\LibraryDTO.xml
+
+
+ true
+ 4
+ bin\Release\net7.0\LibraryDTO.xml
+
+
diff --git a/sources/LibraryDTO/LinkDTO.cs b/sources/LibraryDTO/LinkDTO.cs
new file mode 100644
index 0000000..336909c
--- /dev/null
+++ b/sources/LibraryDTO/LinkDTO.cs
@@ -0,0 +1,10 @@
+using System;
+namespace LibraryDTO
+{
+ public class LinkDTO
+ {
+ public string Title { get; set; }
+ public string Url { get; set; }
+ }
+}
+
diff --git a/sources/LibraryDTO/RatingsDTO.cs b/sources/LibraryDTO/RatingsDTO.cs
new file mode 100644
index 0000000..f15e5eb
--- /dev/null
+++ b/sources/LibraryDTO/RatingsDTO.cs
@@ -0,0 +1,10 @@
+using System;
+namespace LibraryDTO
+{
+ public class RatingsDTO
+ {
+ public float Average { get; set; }
+ public int Count { get; set; }
+ }
+}
+
diff --git a/sources/LibraryDTO/WorkDTO.cs b/sources/LibraryDTO/WorkDTO.cs
new file mode 100644
index 0000000..2c41813
--- /dev/null
+++ b/sources/LibraryDTO/WorkDTO.cs
@@ -0,0 +1,14 @@
+using System;
+namespace LibraryDTO
+{
+ public class WorkDTO
+ {
+ public string Id { get; set; }
+ public string Description { get; set; }
+ public string Title { get; set; }
+ public List Subjects { get; set; } = new List();
+ public List Authors { get; set; } = new List();
+ public RatingsDTO Ratings { get; set; }
+ }
+}
+
diff --git a/sources/Model/Author.cs b/sources/Model/Author.cs
new file mode 100644
index 0000000..9992f2f
--- /dev/null
+++ b/sources/Model/Author.cs
@@ -0,0 +1,32 @@
+using System;
+namespace Model
+{
+ public class Author : IEquatable
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+ public string ImageSmall => $"https://covers.openlibrary.org/a/olid/{Id.Substring(Id.LastIndexOf("/"))}-S.jpg";
+ public string ImageMedium => $"https://covers.openlibrary.org/a/olid/{Id.Substring(Id.LastIndexOf("/"))}-M.jpg";
+ public string ImageLarge => $"https://covers.openlibrary.org/a/olid/{Id.Substring(Id.LastIndexOf("/"))}-L.jpg";
+ public string Bio { get; set; }
+ public List AlternateNames { get; set; } = new List();
+ public List Links { get; set; }
+ public DateTime? BirthDate { get; set; }
+ public DateTime? DeathDate { get; set; }
+
+ public bool Equals(Author? other)
+ => Id == other.Id;
+
+ public override bool Equals(object? obj)
+ {
+ if(ReferenceEquals(obj, null)) return false;
+ if(ReferenceEquals(this, obj)) return true;
+ if(GetType() != obj.GetType()) return false;
+ return Equals(obj as Author);
+ }
+
+ public override int GetHashCode()
+ => Id.GetHashCode();
+ }
+}
+
diff --git a/sources/Model/Book.cs b/sources/Model/Book.cs
new file mode 100644
index 0000000..092b1b8
--- /dev/null
+++ b/sources/Model/Book.cs
@@ -0,0 +1,41 @@
+using static Model.Book;
+
+namespace Model;
+
+public class Book : IEquatable
+{
+ public string Id { get; set; }
+ public string Title { get; set; }
+ public List Publishers { get; set; } = new List();
+ public DateTime PublishDate { get; set; }
+ public string ISBN13 { get; set; }
+ public List Series { get; set; } = new List();
+ public int NbPages { get; set; }
+ public string Format { get; set; }
+ public Languages Language { get; set; }
+ public List Contributors { get; set; }
+ public string ImageSmall => $"https://covers.openlibrary.org/b/isbn/{ISBN13}-S.jpg";
+ public string ImageMedium => $"https://covers.openlibrary.org/b/isbn/{ISBN13}-M.jpg";
+ public string ImageLarge => $"https://covers.openlibrary.org/b/isbn/{ISBN13}-L.jpg";
+ public List Works { get; set; } = new List();
+ public List Authors { get; set; } = new List();
+ public Status Status { get; set; }
+ public List UserTags { get; set; } = new List();
+ public float? UserRating { get; set; }
+ public string UserNote { get; set; }
+
+ public bool Equals(Book? other)
+ => Id == other.Id;
+
+ public override bool Equals(object? obj)
+ {
+ if(ReferenceEquals(obj, null)) return false;
+ if(ReferenceEquals(this, obj)) return true;
+ if(GetType() != obj.GetType()) return false;
+ return Equals(obj as Book);
+ }
+
+ public override int GetHashCode()
+ => Id.GetHashCode();
+}
+
diff --git a/sources/Model/Borrowing.cs b/sources/Model/Borrowing.cs
new file mode 100644
index 0000000..7110c3b
--- /dev/null
+++ b/sources/Model/Borrowing.cs
@@ -0,0 +1,29 @@
+using System;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace Model
+{
+ public class Borrowing : IEquatable //emprunt
+ {
+ public string Id { get; set; }
+ public Book Book { get; set; }
+ public Contact Owner { get; set; }
+ public DateTime BorrowedAt { get; set; }
+ public DateTime? ReturnedAt { get; set; }
+
+ public bool Equals(Borrowing? other)
+ => Id == other.Id;
+
+ public override bool Equals(object? obj)
+ {
+ if(ReferenceEquals(obj, null)) return false;
+ if(ReferenceEquals(this, obj)) return true;
+ if(GetType() != obj.GetType()) return false;
+ return Equals(obj as Borrowing);
+ }
+
+ public override int GetHashCode()
+ => Id.GetHashCode();
+ }
+}
+
diff --git a/sources/Model/Contact.cs b/sources/Model/Contact.cs
new file mode 100644
index 0000000..9066aa6
--- /dev/null
+++ b/sources/Model/Contact.cs
@@ -0,0 +1,25 @@
+using System;
+namespace Model
+{
+ public class Contact : IEquatable
+ {
+ public string Id { get; set; }
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+
+ public bool Equals(Contact? other)
+ => Id == other.Id;
+
+ public override bool Equals(object? obj)
+ {
+ if(ReferenceEquals(obj, null)) return false;
+ if(ReferenceEquals(this, obj)) return true;
+ if(GetType() != obj.GetType()) return false;
+ return Equals(obj as Contact);
+ }
+
+ public override int GetHashCode()
+ => Id.GetHashCode();
+ }
+}
+
diff --git a/sources/Model/Contributor.cs b/sources/Model/Contributor.cs
new file mode 100644
index 0000000..d1b5c12
--- /dev/null
+++ b/sources/Model/Contributor.cs
@@ -0,0 +1,10 @@
+using System;
+namespace Model
+{
+ public class Contributor
+ {
+ public string Name { get; set; }
+ public string Role { get; set; }
+ }
+}
+
diff --git a/sources/Model/ILibraryManager.cs b/sources/Model/ILibraryManager.cs
new file mode 100644
index 0000000..8edc427
--- /dev/null
+++ b/sources/Model/ILibraryManager.cs
@@ -0,0 +1,15 @@
+using System;
+namespace Model
+{
+ public interface ILibraryManager
+ {
+ Task GetBookById(string id);
+ Task GetBookByISBN(string isbn);
+ Task>> GetBooksByTitle(string title, int index, int count, string sort = "");
+ Task>> GetBooksByAuthorId(string authorId, int index, int count, string sort = "");
+ Task>> GetBooksByAuthor(string author, int index, int count, string sort = "");
+ Task GetAuthorById(string id);
+ Task>> GetAuthorsByName(string substring, int index, int count, string sort = "");
+ }
+}
+
diff --git a/sources/Model/IUserLibraryManager.cs b/sources/Model/IUserLibraryManager.cs
new file mode 100644
index 0000000..3e05af1
--- /dev/null
+++ b/sources/Model/IUserLibraryManager.cs
@@ -0,0 +1,40 @@
+using System;
+namespace Model
+{
+ public interface IUserLibraryManager : ILibraryManager
+ {
+ Task>> GetBooksFromCollection(int index, int count, string sort = "");
+
+ Task AddBook(Book book);
+ Task AddBook(string id);
+ Task AddBookByIsbn(string isbn);
+ Task RemoveBook(Book book);
+ Task RemoveBook(string id);
+ Task RemoveBookByIsbn(string isbn);
+
+ Task AddToFavorites(Book book);
+ Task AddToFavorites(string bookId);
+ Task RemoveFromFavorites(Book book);
+ Task RemoveFromFavorites(string bookId);
+
+ Task UpdateBook(Book updatedBook);
+
+ Task AddContact(Contact contact);
+ Task RemoveContact(Contact contact);
+
+ Task LendBook(Book book, Contact contact, DateTime? loanDate);
+ Task GetBackBook(Book book, DateTime? returnedDate);
+ Task BorrowBook(Book book, Contact owner, DateTime? borrowedDate);
+ Task GiveBackBook(Book book, DateTime? returnedDate);
+
+ Task>> GetCurrentLoans(int index, int count);
+ Task>> GetPastLoans(int index, int count);
+
+ Task>> GetCurrentBorrowings(int index, int count);
+ Task>> GetPastBorrowings(int index, int count);
+
+ Task>> GetContacts(int index, int count);
+
+ }
+}
+
diff --git a/sources/Model/Languages.cs b/sources/Model/Languages.cs
new file mode 100644
index 0000000..d5c2014
--- /dev/null
+++ b/sources/Model/Languages.cs
@@ -0,0 +1,11 @@
+using System;
+namespace Model
+{
+ public enum Languages
+ {
+ Unknown,
+ French,
+ English
+ }
+}
+
diff --git a/sources/Model/Link.cs b/sources/Model/Link.cs
new file mode 100644
index 0000000..04afed9
--- /dev/null
+++ b/sources/Model/Link.cs
@@ -0,0 +1,10 @@
+using System;
+namespace Model
+{
+ public class Link
+ {
+ public string Title { get; set; }
+ public string Url { get; set; }
+ }
+}
+
diff --git a/sources/Model/Loan.cs b/sources/Model/Loan.cs
new file mode 100644
index 0000000..f6c2168
--- /dev/null
+++ b/sources/Model/Loan.cs
@@ -0,0 +1,27 @@
+using System;
+namespace Model
+{
+ public class Loan : IEquatable //prêt
+ {
+ public string Id { get; set; }
+ public Book Book { get; set; }
+ public Contact Loaner { get; set; }
+ public DateTime LoanedAt { get; set; }
+ public DateTime? ReturnedAt { get; set; }
+
+ public bool Equals(Loan? other)
+ => Id == other.Id;
+
+ public override bool Equals(object? obj)
+ {
+ if(ReferenceEquals(obj, null)) return false;
+ if(ReferenceEquals(this, obj)) return true;
+ if(GetType() != obj.GetType()) return false;
+ return Equals(obj as Loan);
+ }
+
+ public override int GetHashCode()
+ => Id.GetHashCode();
+ }
+}
+
diff --git a/sources/Model/Manager.cs b/sources/Model/Manager.cs
new file mode 100644
index 0000000..32bedf6
--- /dev/null
+++ b/sources/Model/Manager.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Reflection;
+
+namespace Model
+{
+ public class Manager
+ {
+ private ILibraryManager LibraryManager { get; set; }
+ private IUserLibraryManager UserLibraryManager { get; set; }
+
+ public ReadOnlyCollection Books { get; private set; }
+ private List books = new();
+
+ public Manager(ILibraryManager libMgr, IUserLibraryManager userLibMgr)
+ {
+ LibraryManager = libMgr;
+ UserLibraryManager = userLibMgr;
+ Books = new ReadOnlyCollection(books);
+ }
+
+ public async Task GetBookById(string id)
+ => await LibraryManager.GetBookById(id);
+
+ public async Task GetBookByISBN(string isbn)
+ => await LibraryManager.GetBookByISBN(isbn);
+
+ public async Task<(long count, IEnumerable books)> GetBooksByTitle(string title, int index, int count, string sort = "")
+ {
+ var result = await LibraryManager.GetBooksByTitle(title, index, count, sort);
+ return (result.Item1, result.Item2);
+ }
+
+ public async Task<(long count, IEnumerable books)> GetBooksByAuthorId(string authorId, int index, int count, string sort = "")
+ {
+ var result = await LibraryManager.GetBooksByAuthorId(authorId, index, count, sort);
+ return (result.Item1, result.Item2);
+ }
+
+ public async Task<(long count, IEnumerable books)> GetBooksByAuthor(string author, int index, int count, string sort = "")
+ {
+ var result = await LibraryManager.GetBooksByAuthor(author, index, count, sort);
+ return (result.Item1, result.Item2);
+ }
+
+ public async Task GetAuthorById(string id)
+ => await LibraryManager.GetAuthorById(id);
+
+ public async Task<(long count, IEnumerable authors)> GetAuthorsByName(string substring, int index, int count, string sort = "")
+ {
+ var result = await LibraryManager.GetAuthorsByName(substring, index, count, sort);
+ return (result.Item1, result.Item2);
+ }
+
+ public Task AddBookToCollection(string id)
+ {
+ return UserLibraryManager.AddBook(id);
+ }
+
+ public async Task GetBookByIdFromCollection(string id)
+ => await UserLibraryManager.GetBookById(id);
+
+
+ public Task UpdateBook(Book book)
+ {
+ return UserLibraryManager.UpdateBook(book);
+ }
+
+ public Task<(long count, IEnumerable books)> GetBooksFromCollection(int index, int count, string sort = "")
+ {
+ var result = UserLibraryManager.GetBooksFromCollection(index, count, sort).Result;
+ return Task.FromResult((result.Item1, result.Item2));
+ }
+
+ public Task<(long count, IEnumerable contacts)> GetContacts(int index, int count)
+ {
+ var result = UserLibraryManager.GetContacts(index, count).Result;
+ return Task.FromResult((result.Item1, result.Item2));
+ }
+
+ public Task<(long count, IEnumerable loans)> GetCurrentLoans(int index, int count)
+ {
+ var result = UserLibraryManager.GetCurrentLoans(index, count).Result;
+ return Task.FromResult((result.Item1, result.Item2));
+ }
+
+ public Task<(long count, IEnumerable loans)> GetPastLoans(int index, int count)
+ {
+ var result = UserLibraryManager.GetPastLoans(index, count).Result;
+ return Task.FromResult((result.Item1, result.Item2));
+ }
+
+ public Task<(long count, IEnumerable borrowings)> GetCurrentBorrowings(int index, int count)
+ {
+ var result = UserLibraryManager.GetCurrentBorrowings(index, count).Result;
+ return Task.FromResult((result.Item1, result.Item2));
+ }
+
+ public Task<(long count, IEnumerable borrowings)> GetPastBorrowings(int index, int count)
+ {
+ var result = UserLibraryManager.GetPastBorrowings(index, count).Result;
+ return Task.FromResult((result.Item1, result.Item2));
+ }
+ }
+}
+
diff --git a/sources/Model/Model.csproj b/sources/Model/Model.csproj
new file mode 100644
index 0000000..4658cbf
--- /dev/null
+++ b/sources/Model/Model.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/sources/Model/Ratings.cs b/sources/Model/Ratings.cs
new file mode 100644
index 0000000..9579f4c
--- /dev/null
+++ b/sources/Model/Ratings.cs
@@ -0,0 +1,10 @@
+using System;
+namespace Model
+{
+ public class Ratings
+ {
+ public float Average { get; set; }
+ public int Count { get; set; }
+ }
+}
+
diff --git a/sources/Model/Status.cs b/sources/Model/Status.cs
new file mode 100644
index 0000000..3ec0a44
--- /dev/null
+++ b/sources/Model/Status.cs
@@ -0,0 +1,13 @@
+using System;
+namespace Model
+{
+ public enum Status
+ {
+ Unknown,
+ Finished,
+ Reading,
+ NotRead,
+ ToBeRead
+ }
+}
+
diff --git a/sources/Model/Work.cs b/sources/Model/Work.cs
new file mode 100644
index 0000000..e9705bd
--- /dev/null
+++ b/sources/Model/Work.cs
@@ -0,0 +1,28 @@
+using System;
+namespace Model
+{
+ public class Work : IEquatable
+ {
+ public string Id { get; set; }
+ public string Description { get; set; }
+ public string Title { get; set; }
+ public List Subjects { get; set; } = new List();
+ public List Authors { get; set; } = new List();
+ public Ratings Ratings { get; set; }
+
+ public bool Equals(Work? other)
+ => Id == other.Id;
+
+ public override bool Equals(object? obj)
+ {
+ if(ReferenceEquals(obj, null)) return false;
+ if(ReferenceEquals(this, obj)) return true;
+ if(GetType() != obj.GetType()) return false;
+ return Equals(obj as Work);
+ }
+
+ public override int GetHashCode()
+ => Id.GetHashCode();
+ }
+}
+
diff --git a/sources/PocketBook/Applicative_VM/NavigatorVM.cs b/sources/PocketBook/Applicative_VM/NavigatorVM.cs
index 2489665..f67eec9 100644
--- a/sources/PocketBook/Applicative_VM/NavigatorVM.cs
+++ b/sources/PocketBook/Applicative_VM/NavigatorVM.cs
@@ -1,6 +1,7 @@
using System;
using System.Windows.Input;
using System.Threading.Tasks;
+using System.Reflection;
namespace PocketBook.Applicative_VM
{
@@ -9,42 +10,18 @@ namespace PocketBook.Applicative_VM
public ICommand Navigateto { get; private set; }
public NavigatorVM()
{
- Navigateto = new Command(async (parameter) =>
+ Navigateto = new Command(async (name) =>
{
- if (!string.IsNullOrEmpty(parameter))
+
+ Type pageType = Assembly.GetExecutingAssembly().GetTypes()
+ .Where(t => typeof(Page).IsAssignableFrom(t) && t.Name == name as String)
+ .FirstOrDefault();
+
+ if (pageType != null)
{
- switch (parameter)
- {
- case "TousPage":
- await App.Current.MainPage.Navigation.PushAsync(new TousPage());
- break;
- case "SharePage":
- await App.Current.MainPage.Navigation.PushAsync(new SharePage());
- break;
- case "Auteur":
- await App.Current.MainPage.Navigation.PushAsync(new Auteur());
- break;
- case "BookDetail":
- await App.Current.MainPage.Navigation.PushAsync(new BookDetail());
- break;
- case "DatePublic":
- await App.Current.MainPage.Navigation.PushAsync(new DatePublic());
- break;
- case "LaterPage":
- await App.Current.MainPage.Navigation.PushAsync(new LaterPage());
- break;
- case "MarkPage":
- await App.Current.MainPage.Navigation.PushAsync(new MarkPage());
- break;
- case "StatutPage":
- await App.Current.MainPage.Navigation.PushAsync(new StatutPage());
- break;
- case "LikePage":
- await App.Current.MainPage.Navigation.PushAsync(new LikePage());
- break;
- }
+ Page page = (Page)Activator.CreateInstance(pageType,this);
+ await App.Current.MainPage.Navigation.PushAsync(page);
}
- else await App.Current.MainPage.Navigation.PopToRootAsync();
});
}
}
diff --git a/sources/PocketBook/Applicative_VM/ScanMenuVM.cs b/sources/PocketBook/Applicative_VM/ScanMenuVM.cs
new file mode 100644
index 0000000..1385472
--- /dev/null
+++ b/sources/PocketBook/Applicative_VM/ScanMenuVM.cs
@@ -0,0 +1,43 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Windows.Input;
+
+namespace PocketBook.Applicative_VM
+{
+ public class ScanMenuVM : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public ICommand ShowScanMenu { get; private set; }
+
+ private bool scanMenuIsVisible;
+
+ public bool ScanMenuIsVisible
+ {
+ get { return scanMenuIsVisible; }
+ set
+ {
+ if (scanMenuIsVisible != value)
+ {
+ scanMenuIsVisible = value;
+ OnPropertyChanged(nameof(ScanMenuIsVisible));
+ }
+ }
+ }
+
+ public ScanMenuVM()
+ {
+ ShowScanMenu = new Command(() =>
+ {
+ ScanMenuIsVisible = !ScanMenuIsVisible;
+ });
+ }
+
+ protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+}
diff --git a/sources/PocketBook/MauiProgram.cs b/sources/PocketBook/MauiProgram.cs
index 43fdb1d..d8ede8c 100644
--- a/sources/PocketBook/MauiProgram.cs
+++ b/sources/PocketBook/MauiProgram.cs
@@ -40,7 +40,17 @@ public static class MauiProgram
});
builder.Services
.AddSingleton()
+ .AddSingleton()
.AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
;
#if DEBUG
builder.Logging.AddDebug();
diff --git a/sources/PocketBook/Pages/Auteur.xaml b/sources/PocketBook/Pages/Auteur.xaml
index 602985b..9ec3630 100644
--- a/sources/PocketBook/Pages/Auteur.xaml
+++ b/sources/PocketBook/Pages/Auteur.xaml
@@ -10,9 +10,6 @@
-
-
-
diff --git a/sources/PocketBook/Pages/Auteur.xaml.cs b/sources/PocketBook/Pages/Auteur.xaml.cs
index f1f5f82..7dda99e 100644
--- a/sources/PocketBook/Pages/Auteur.xaml.cs
+++ b/sources/PocketBook/Pages/Auteur.xaml.cs
@@ -1,14 +1,15 @@
+using PocketBook.Applicative_VM;
+
namespace PocketBook;
public partial class Auteur : ContentPage
{
- public Auteur()
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+
+ public Auteur(NavigatorVM navigator)
{
+ NavigateCommandBooks = navigator;
InitializeComponent();
}
- private async void RetourMainMenu(object sender, EventArgs e)
- {
- await Navigation.PopToRootAsync();
- }
}
\ No newline at end of file
diff --git a/sources/PocketBook/Pages/BookDetail.xaml.cs b/sources/PocketBook/Pages/BookDetail.xaml.cs
index 18d411a..27145bc 100644
--- a/sources/PocketBook/Pages/BookDetail.xaml.cs
+++ b/sources/PocketBook/Pages/BookDetail.xaml.cs
@@ -1,22 +1,23 @@
+using PocketBook.Applicative_VM;
+
namespace PocketBook;
public partial class BookDetail : ContentPage
{
- public BookDetail()
- {
- InitializeComponent();
- titreBook.Text = "La horde du contrevent";
- bookAuteur.Text = "Alain Damasio";
- bookEdition.Text = "Fayard (2019)";
- bookNbPages.Text = "700";
- bookISBN.Text = "9854645645456";
- bookLangue.Text = "français";
- bookStatus.Text = "Non lu";
- bookAdd.Text = "15 août 2013";
- }
- private async void RetourMainMenu(object sender, EventArgs e)
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+
+ public BookDetail(NavigatorVM navigator)
{
- await Navigation.PopAsync();
+ NavigateCommandBooks = navigator;
+ InitializeComponent();
+ titreBook.Text = "La horde du contrevent";
+ bookAuteur.Text = "Alain Damasio";
+ bookEdition.Text = "Fayard (2019)";
+ bookNbPages.Text = "700";
+ bookISBN.Text = "9854645645456";
+ bookLangue.Text = "français";
+ bookStatus.Text = "Non lu";
+ bookAdd.Text = "15 août 2013";
}
}
\ No newline at end of file
diff --git a/sources/PocketBook/Pages/Composants/ContentView/ContentViewBook.xaml b/sources/PocketBook/Pages/Composants/ContentView/ContentViewBook.xaml
index 24f8a6a..1966585 100644
--- a/sources/PocketBook/Pages/Composants/ContentView/ContentViewBook.xaml
+++ b/sources/PocketBook/Pages/Composants/ContentView/ContentViewBook.xaml
@@ -2,15 +2,18 @@
+ xmlns:local="clr-namespace:PocketBook"
+ x:Name="root">
+
+
+
-
+
-
-
-
+
+
+
diff --git a/sources/PocketBook/Pages/Composants/ContentView/ContentViewBook.xaml.cs b/sources/PocketBook/Pages/Composants/ContentView/ContentViewBook.xaml.cs
index 543f4ff..44a5f69 100644
--- a/sources/PocketBook/Pages/Composants/ContentView/ContentViewBook.xaml.cs
+++ b/sources/PocketBook/Pages/Composants/ContentView/ContentViewBook.xaml.cs
@@ -1,3 +1,5 @@
+using System.Windows.Input;
+
namespace PocketBook;
public partial class ContentViewBook : ContentView
{
@@ -14,6 +16,24 @@ public partial class ContentViewBook : ContentView
public static readonly BindableProperty BookImageProperty =
BindableProperty.Create(nameof(BookImage), typeof(string), typeof(ContentViewBook), string.Empty);
+ public static readonly BindableProperty CommandProperty =
+ BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(ContentViewBook));
+
+ public static readonly BindableProperty CommandParameterProperty =
+ BindableProperty.Create(nameof(CommandParameter), typeof(string), typeof(ContentViewBook));
+
+ public ICommand Command
+ {
+ get { return (ICommand)GetValue(CommandProperty); }
+ set { SetValue(CommandProperty, value); }
+ }
+
+ public string CommandParameter
+ {
+ get { return (string)GetValue(CommandParameterProperty); }
+ set { SetValue(CommandParameterProperty, value); }
+ }
+
public string BookName
{
get { return (string)GetValue(BookNameProperty); }
@@ -38,9 +58,5 @@ public partial class ContentViewBook : ContentView
public ContentViewBook()
{
InitializeComponent();
- bookName.SetBinding(Label.TextProperty, new Binding(nameof(BookName), source: this));
- autorName.SetBinding(Label.TextProperty, new Binding(nameof(AutorName), source: this));
- bookStatus.SetBinding(Label.TextProperty, new Binding(nameof(BookStatus), source: this));
- bookImage.SetBinding(Image.SourceProperty, new Binding(nameof(BookImage), source: this));
}
}
\ No newline at end of file
diff --git a/sources/PocketBook/Pages/Composants/ContentView/ScanMenuView.xaml b/sources/PocketBook/Pages/Composants/ContentView/ScanMenuView.xaml
index 0c82394..d212e1d 100644
--- a/sources/PocketBook/Pages/Composants/ContentView/ScanMenuView.xaml
+++ b/sources/PocketBook/Pages/Composants/ContentView/ScanMenuView.xaml
@@ -2,8 +2,11 @@
+
+
diff --git a/sources/PocketBook/Pages/Composants/ContentView/ScanMenuView.xaml.cs b/sources/PocketBook/Pages/Composants/ContentView/ScanMenuView.xaml.cs
index c43fc79..7e43184 100644
--- a/sources/PocketBook/Pages/Composants/ContentView/ScanMenuView.xaml.cs
+++ b/sources/PocketBook/Pages/Composants/ContentView/ScanMenuView.xaml.cs
@@ -2,7 +2,7 @@
public partial class ScanMenuView : ContentView
{
- public ScanMenuView()
+ public ScanMenuView()
{
InitializeComponent();
}
diff --git a/sources/PocketBook/Pages/DatePublic.xaml b/sources/PocketBook/Pages/DatePublic.xaml
index 8ff23ae..847aa47 100644
--- a/sources/PocketBook/Pages/DatePublic.xaml
+++ b/sources/PocketBook/Pages/DatePublic.xaml
@@ -8,9 +8,6 @@
-
-
-
diff --git a/sources/PocketBook/Pages/DatePublic.xaml.cs b/sources/PocketBook/Pages/DatePublic.xaml.cs
index 4fa6d98..e2e392f 100644
--- a/sources/PocketBook/Pages/DatePublic.xaml.cs
+++ b/sources/PocketBook/Pages/DatePublic.xaml.cs
@@ -1,14 +1,15 @@
-namespace PocketBook;
+using PocketBook.Applicative_VM;
+
+namespace PocketBook;
public partial class DatePublic : ContentPage
{
- public DatePublic()
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+
+ public DatePublic(NavigatorVM navigator)
{
+ NavigateCommandBooks = navigator;
InitializeComponent();
}
- private async void RetourMainMenu(object sender, EventArgs e)
- {
- await Navigation.PopToRootAsync();
- }
}
diff --git a/sources/PocketBook/Pages/LaterPage.xaml b/sources/PocketBook/Pages/LaterPage.xaml
index a6c0088..19e671a 100644
--- a/sources/PocketBook/Pages/LaterPage.xaml
+++ b/sources/PocketBook/Pages/LaterPage.xaml
@@ -1,4 +1,4 @@
-
+
-
-
-
diff --git a/sources/PocketBook/Pages/LaterPage.xaml.cs b/sources/PocketBook/Pages/LaterPage.xaml.cs
index 5c70346..715f1cb 100644
--- a/sources/PocketBook/Pages/LaterPage.xaml.cs
+++ b/sources/PocketBook/Pages/LaterPage.xaml.cs
@@ -1,17 +1,15 @@
using CommunityToolkit.Maui.Views;
+using PocketBook.Applicative_VM;
namespace PocketBook;
public partial class LaterPage : ContentPage
{
- public LaterPage()
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+
+ public LaterPage(NavigatorVM navigator)
{
+ NavigateCommandBooks = navigator;
InitializeComponent();
}
-
-
- private async void RetourMainMenu(object sender, EventArgs e)
- {
- await Navigation.PopToRootAsync();
- }
}
\ No newline at end of file
diff --git a/sources/PocketBook/Pages/LikePage.xaml b/sources/PocketBook/Pages/LikePage.xaml
index 1cb06c0..1297fdf 100644
--- a/sources/PocketBook/Pages/LikePage.xaml
+++ b/sources/PocketBook/Pages/LikePage.xaml
@@ -10,9 +10,6 @@
-
-
-
diff --git a/sources/PocketBook/Pages/LikePage.xaml.cs b/sources/PocketBook/Pages/LikePage.xaml.cs
index cd373ff..7e0b995 100644
--- a/sources/PocketBook/Pages/LikePage.xaml.cs
+++ b/sources/PocketBook/Pages/LikePage.xaml.cs
@@ -1,18 +1,16 @@
using CommunityToolkit.Maui.Views;
+using PocketBook.Applicative_VM;
namespace PocketBook;
public partial class LikePage : ContentPage
{
- public LikePage()
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+
+ public LikePage(NavigatorVM navigator)
{
+ NavigateCommandBooks = navigator;
InitializeComponent();
}
-
- private async void RetourMainMenu(object sender, EventArgs e)
- {
- await Navigation.PopToRootAsync();
- }
-
}
\ No newline at end of file
diff --git a/sources/PocketBook/Pages/MarkPage.xaml b/sources/PocketBook/Pages/MarkPage.xaml
index 8828a5a..bf9254f 100644
--- a/sources/PocketBook/Pages/MarkPage.xaml
+++ b/sources/PocketBook/Pages/MarkPage.xaml
@@ -1,4 +1,4 @@
-
+
-
-
-
diff --git a/sources/PocketBook/Pages/MarkPage.xaml.cs b/sources/PocketBook/Pages/MarkPage.xaml.cs
index 403c6aa..d0f5fcb 100644
--- a/sources/PocketBook/Pages/MarkPage.xaml.cs
+++ b/sources/PocketBook/Pages/MarkPage.xaml.cs
@@ -1,17 +1,15 @@
using CommunityToolkit.Maui.Views;
+using PocketBook.Applicative_VM;
namespace PocketBook;
public partial class MarkPage : ContentPage
{
- public MarkPage()
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+
+ public MarkPage(NavigatorVM navigator)
{
+ NavigateCommandBooks = navigator;
InitializeComponent();
}
-
-
- private async void RetourMainMenu(object sender, EventArgs e)
- {
- await Navigation.PopToRootAsync();
- }
}
\ No newline at end of file
diff --git a/sources/PocketBook/Pages/SharePage.xaml.cs b/sources/PocketBook/Pages/SharePage.xaml.cs
index 485e847..bb99348 100644
--- a/sources/PocketBook/Pages/SharePage.xaml.cs
+++ b/sources/PocketBook/Pages/SharePage.xaml.cs
@@ -1,16 +1,15 @@
using CommunityToolkit.Maui.Views;
+using PocketBook.Applicative_VM;
namespace PocketBook;
public partial class SharePage : ContentPage
{
- public SharePage()
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+
+ public SharePage(NavigatorVM navigator)
{
+ NavigateCommandBooks = navigator;
InitializeComponent();
}
-
- private async void RetourMainMenu(object sender, EventArgs e)
- {
- await Navigation.PopToRootAsync();
- }
}
\ No newline at end of file
diff --git a/sources/PocketBook/Pages/StatutPage.xaml b/sources/PocketBook/Pages/StatutPage.xaml
index 817ce41..78ddd4d 100644
--- a/sources/PocketBook/Pages/StatutPage.xaml
+++ b/sources/PocketBook/Pages/StatutPage.xaml
@@ -10,9 +10,6 @@
-
-
-
diff --git a/sources/PocketBook/Pages/StatutPage.xaml.cs b/sources/PocketBook/Pages/StatutPage.xaml.cs
index 34e85a4..40c3a10 100644
--- a/sources/PocketBook/Pages/StatutPage.xaml.cs
+++ b/sources/PocketBook/Pages/StatutPage.xaml.cs
@@ -1,17 +1,15 @@
using CommunityToolkit.Maui.Views;
+using PocketBook.Applicative_VM;
namespace PocketBook;
public partial class StatutPage : ContentPage
{
- public StatutPage()
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+
+ public StatutPage(NavigatorVM navigator)
{
+ NavigateCommandBooks = navigator;
InitializeComponent();
}
-
-
- private async void RetourMainMenu(object sender, EventArgs e)
- {
- await Navigation.PopToRootAsync();
- }
}
\ No newline at end of file
diff --git a/sources/PocketBook/Pages/TousPage.xaml b/sources/PocketBook/Pages/TousPage.xaml
index 06f66db..ec79037 100644
--- a/sources/PocketBook/Pages/TousPage.xaml
+++ b/sources/PocketBook/Pages/TousPage.xaml
@@ -7,73 +7,42 @@
Title="Tous"
Shell.ForegroundColor="{StaticResource Primary}">
-
+ Order="Primary" IconImageSource="plus.png" Command="{Binding ScanMenuVM.ShowScanMenu}"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sources/PocketBook/Pages/TousPage.xaml.cs b/sources/PocketBook/Pages/TousPage.xaml.cs
index 54369ac..073331d 100644
--- a/sources/PocketBook/Pages/TousPage.xaml.cs
+++ b/sources/PocketBook/Pages/TousPage.xaml.cs
@@ -1,18 +1,19 @@
using CommunityToolkit.Maui.Core;
using CommunityToolkit.Maui.Views;
+using PocketBook.Applicative_VM;
namespace PocketBook;
public partial class TousPage : ContentPage
{
+ public NavigatorVM NavigateCommandBooks { get; private set; }
+ public ScanMenuVM ScanMenuVM { get; private set; }
- public TousPage()
+ public TousPage(NavigatorVM navigation)
{
+ ScanMenuVM = new ScanMenuVM();
+ NavigateCommandBooks = navigation;
InitializeComponent();
- }
-
- public async void OnBookSelected(object sender, EventArgs e)
- {
- await Navigation.PushAsync(new BookDetail());
+ BindingContext = this;
}
}
\ No newline at end of file
diff --git a/sources/Stub/EnumsMapper.cs b/sources/Stub/EnumsMapper.cs
new file mode 100644
index 0000000..95edef2
--- /dev/null
+++ b/sources/Stub/EnumsMapper.cs
@@ -0,0 +1,49 @@
+using System;
+using Utils;
+
+namespace Stub
+{
+ static class EnumsMapper
+ {
+ public static EnumsMapper BiddingsMapper { get; }
+ = new EnumsMapper(
+ Tuple.Create(Model.Languages.Unknown, LibraryDTO.Languages.Unknown),
+ Tuple.Create(Model.Languages.French, LibraryDTO.Languages.French),
+ Tuple.Create(Model.Languages.English, LibraryDTO.Languages.English)
+ );
+
+ public static TModel ToModel(this TDTO dto) where TModel : Enum
+ where TDTO : Enum
+ {
+ foreach(var prop in typeof(EnumsMapper).GetProperties())
+ {
+ if(prop.PropertyType.Equals(typeof(EnumsMapper)))
+ {
+ return (prop.GetValue(null) as EnumsMapper).GetModel(dto);
+ }
+ }
+ return default(TModel);
+ }
+
+ public static Model.Languages ToModel(this LibraryDTO.Languages dto)
+ => ToModel(dto);
+
+ public static TDTO ToDTO(this TModel model) where TModel : Enum
+ where TDTO : Enum
+ {
+ foreach(var prop in typeof(EnumsMapper).GetProperties())
+ {
+ if(prop.PropertyType.Equals(typeof(EnumsMapper)))
+ {
+ return (prop.GetValue(null) as EnumsMapper).GetEntity(model);
+ }
+ }
+ return default(TDTO);
+ }
+
+ public static LibraryDTO.Languages ToDTO(this Model.Languages model)
+ => ToDTO(model);
+ }
+
+}
+
diff --git a/sources/Stub/Extensions.cs b/sources/Stub/Extensions.cs
new file mode 100644
index 0000000..a4abb02
--- /dev/null
+++ b/sources/Stub/Extensions.cs
@@ -0,0 +1,93 @@
+using System;
+using LibraryDTO;
+using Model;
+using static Stub.Mapper;
+
+namespace Stub
+{
+ public static class Extensions
+ {
+ public static Ratings ToPoco(this RatingsDTO dto)
+ => new Ratings() { Average = dto.Average, Count = dto.Count };
+ public static IEnumerable ToPocos(this IEnumerable dtos)
+ => dtos.Select(dto => dto.ToPoco());
+
+ public static Contributor ToPoco(this ContributorDTO dto)
+ => new Contributor { Name = dto.Name, Role = dto.Role };
+ public static IEnumerable ToPocos(this IEnumerable dtos)
+ => dtos.Select(dto => dto.ToPoco());
+
+ public static Link ToPoco(this LinkDTO dto)
+ => new Link { Title = dto.Title, Url = dto.Url };
+ public static IEnumerable ToPocos(this IEnumerable dtos)
+ => dtos.Select(dto => dto.ToPoco());
+
+ public static Author ToPoco(this AuthorDTO dto)
+ {
+ var result = AuthorsMapper.GetT(dto);
+ if(result == null)
+ {
+ result = new Author
+ {
+ AlternateNames = dto.AlternateNames,
+ Bio = dto.Bio,
+ BirthDate = dto.BirthDate,
+ DeathDate = dto.DeathDate,
+ Id = dto.Id,
+ Links = dto.Links.ToPocos().ToList(),
+ Name = dto.Name
+ };
+ }
+ return result;
+ }
+ public static IEnumerable ToPocos(this IEnumerable dtos)
+ => dtos.Select(dto => dto.ToPoco());
+
+ public static Work ToPoco(this WorkDTO dto)
+ {
+ var result = WorksMapper.GetT(dto);
+ if(result == null)
+ {
+ result = new Work
+ {
+ Authors = dto.Authors.ToPocos().ToList(),
+ Description = dto.Description,
+ Id = dto.Id,
+ Ratings = dto.Ratings.ToPoco(),
+ Subjects = dto.Subjects,
+ Title = dto.Title
+ };
+ }
+ return result;
+ }
+ public static IEnumerable ToPocos(this IEnumerable dtos)
+ => dtos.Select(dto => dto.ToPoco());
+
+ public static Book ToPoco(this BookDTO dto)
+ {
+ var result = BooksMapper.GetT(dto);
+ if(result == null)
+ {
+ result = new Book
+ {
+ Authors = dto.Authors.ToPocos().ToList(),
+ Contributors = dto.Contributors.ToPocos().ToList(),
+ Format = dto.Format,
+ Id = dto.Id,
+ ISBN13 = dto.ISBN13,
+ Language = dto.Language.ToModel(),
+ NbPages = dto.NbPages,
+ PublishDate = dto.PublishDate,
+ Publishers = dto.Publishers,
+ Series = dto.Series,
+ Title = dto.Title,
+ Works = dto.Works.ToPocos().ToList()
+ };
+ }
+ return result;
+ }
+ public static IEnumerable ToPocos(this IEnumerable dtos)
+ => dtos.Select(dto => dto.ToPoco());
+ }
+}
+
diff --git a/sources/Stub/LibraryStub.cs b/sources/Stub/LibraryStub.cs
new file mode 100644
index 0000000..ee8a432
--- /dev/null
+++ b/sources/Stub/LibraryStub.cs
@@ -0,0 +1,49 @@
+using Model;
+using Stub;
+
+namespace StubLib;
+
+public class LibraryStub : ILibraryManager
+{
+ private StubbedDTO.Stub StubDTO { get; set; } = new StubbedDTO.Stub();
+
+ public async Task GetAuthorById(string id)
+ {
+ return (await StubDTO.GetAuthorById(id)).ToPoco();
+ }
+
+ public async Task>> GetAuthorsByName(string substring, int index, int count, string sort = "")
+ {
+ var result = await StubDTO.GetAuthorsByName(substring, index, count, sort);
+ return Tuple.Create(result.Item1, result.Item2.ToPocos());
+ }
+
+ public async Task GetBookById(string id)
+ {
+ return (await StubDTO.GetBookById(id)).ToPoco();
+ }
+
+ public async Task GetBookByISBN(string isbn)
+ {
+ return (await StubDTO.GetBookByISBN(isbn)).ToPoco();
+ }
+
+ public async Task>> GetBooksByAuthor(string author, int index, int count, string sort = "")
+ {
+ var result = await StubDTO.GetBooksByAuthor(author, index, count, sort);
+ return Tuple.Create(result.Item1, result.Item2.ToPocos());
+ }
+
+ public async Task>> GetBooksByAuthorId(string authorId, int index, int count, string sort = "")
+ {
+ var result = await StubDTO.GetBooksByAuthor(authorId, index, count, sort);
+ return Tuple.Create(result.Item1, result.Item2.ToPocos());
+ }
+
+ public async Task>> GetBooksByTitle(string title, int index, int count, string sort = "")
+ {
+ var result = await StubDTO.GetBooksByTitle(title, index, count, sort);
+ return Tuple.Create(result.Item1, result.Item2.ToPocos());
+ }
+}
+
diff --git a/sources/Stub/Mapper.cs b/sources/Stub/Mapper.cs
new file mode 100644
index 0000000..1b2fc16
--- /dev/null
+++ b/sources/Stub/Mapper.cs
@@ -0,0 +1,25 @@
+using System;
+using static System.Collections.Specialized.BitVector32;
+using System.Numerics;
+using Utils;
+using Model;
+using LibraryDTO;
+
+namespace Stub
+{
+ static class Mapper
+ {
+ internal static Mapper AuthorsMapper { get; } = new Mapper();
+ internal static Mapper WorksMapper { get; } = new Mapper();
+ internal static Mapper BooksMapper { get; } = new Mapper();
+
+ internal static void Reset()
+ {
+ AuthorsMapper.Reset();
+ WorksMapper.Reset();
+ BooksMapper.Reset();
+ }
+ }
+
+}
+
diff --git a/sources/Stub/Stub.csproj b/sources/Stub/Stub.csproj
new file mode 100644
index 0000000..f70ca4b
--- /dev/null
+++ b/sources/Stub/Stub.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/sources/Stub/UserLibraryStub.cs b/sources/Stub/UserLibraryStub.cs
new file mode 100644
index 0000000..7ea3f98
--- /dev/null
+++ b/sources/Stub/UserLibraryStub.cs
@@ -0,0 +1,421 @@
+using System;
+using System.Collections.ObjectModel;
+using Model;
+using System.Linq;
+using LibraryDTO;
+using System.Xml.Linq;
+
+namespace StubLib
+{
+ public class UserLibraryStub : IUserLibraryManager
+ {
+ public ReadOnlyCollection Favorites { get; private set; }
+ private List favorites = new List();
+
+ public ReadOnlyCollection Books { get; private set; }
+ private List books = new List();
+
+ public ReadOnlyCollection Contacts { get; private set; }
+ private List contacts = new List();
+
+ public ReadOnlyCollection Loans { get; private set; }
+ private List loans = new List();
+
+ public ReadOnlyCollection Borrowings { get; private set; }
+ private List borrowings = new List();
+
+ public ILibraryManager LibraryMgr { get; private set; }
+
+ public UserLibraryStub(ILibraryManager libraryMgr)
+ {
+ LibraryMgr = libraryMgr;
+ Favorites = new ReadOnlyCollection(favorites);
+ Books = new ReadOnlyCollection(books);
+ Borrowings = new ReadOnlyCollection(borrowings);
+ Loans = new ReadOnlyCollection(loans);
+ Contacts = new ReadOnlyCollection(contacts);
+
+ contacts.AddRange(new Contact[]
+ {
+ new Contact { Id = "/contacts/01", FirstName = "Audrey", LastName = "Pouclet" },
+ new Contact { Id = "/contacts/02", FirstName = "Malika", LastName = "More" },
+ new Contact { Id = "/contacts/03", FirstName = "Antoine" },
+ });
+ books.AddRange(new Book[]
+ {
+ LibraryMgr.GetBookById("/books/OL25910297M").Result,
+ LibraryMgr.GetBookById("/books/OL26210208M").Result,
+ LibraryMgr.GetBookById("/books/OL27258011M").Result,
+ LibraryMgr.GetBookById("/books/OL28294024M").Result,
+ LibraryMgr.GetBookById("/books/OL28639494M").Result,
+ LibraryMgr.GetBookById("/books/OL35699439M").Result,
+ LibraryMgr.GetBookById("/books/OL37758347M").Result,
+ LibraryMgr.GetBookById("/books/OL38218739M").Result,
+ LibraryMgr.GetBookById("/books/OL38586212M").Result,
+ LibraryMgr.GetBookById("/books/OL8839071M").Result,
+ LibraryMgr.GetBookById("/books/OL8198056M").Result,
+ });
+ books[0].Status = Status.Finished;
+ books[0].UserNote = "Super bouquin de SF !";
+ books[0].UserRating = 4.5f;
+ loans.Add(new Loan { Id = "/loans/01", Book = books[0], Loaner = contacts[0], LoanedAt = new DateTime(2022, 7, 12), ReturnedAt = new DateTime(2023, 9, 1) });
+ books[1].Status = Status.ToBeRead;
+ books[2].Status = Status.Finished;
+ books[2].UserNote = "Des nouvelles de SF. Super auteur à découvrir !";
+ books[2].UserRating = 4.8f;
+ books[3].Status = Status.Finished;
+ books[3].UserRating = 4.0f;
+ loans.Add(new Loan { Id = "/loans/02", Book = books[3], Loaner = contacts[2], LoanedAt = new DateTime(2020, 12, 23), ReturnedAt = new DateTime(2021, 8, 13) } );
+ books[4].Status = Status.Finished;
+ books[4].UserNote = "Déjà moins connu que le premier, et pourtant...";
+ books[4].UserRating = 4.2f;
+ books[5].Status = Status.Finished;
+ books[5].UserNote = "Coup de coeur. Poétique, anarchique, philosophique... + SF. Du Deleuze et du Foucault chez Damasio";
+ books[5].UserRating = 4.9f;
+ books[6].Status = Status.NotRead;
+ books[7].Status = Status.Finished;
+ books[7].UserRating = 4.9f;
+ books[7].UserNote = "Chef d'oeuvre";
+ books[8].Status = Status.Finished;
+ books[8].UserRating = 4.2f;
+ books[8].UserNote = "Des nouvelles très réussies dont Rapport Minoritaire";
+ books[9].Status = Status.ToBeRead;
+ books[9].Status = Status.Reading;
+
+ borrowings.Add(new Borrowing
+ {
+ Id = "/borrowing/01", Owner = contacts[0],
+ Book = LibraryMgr.GetBookById("/books/OL27328194M").Result,
+ BorrowedAt = new DateTime(2023, 9, 7)
+ });
+ borrowings.Add(new Borrowing
+ {
+ Id = "/borrowing/02", Owner = contacts[1],
+ Book = LibraryMgr.GetBookById("/books/OL27989051M").Result,
+ BorrowedAt = new DateTime(2022, 7, 7),
+ ReturnedAt = new DateTime(2023, 3, 1)
+ });
+ borrowings.Add(new Borrowing
+ {
+ Id = "/borrowing/03", Owner = contacts[1],
+ Book = LibraryMgr.GetBookById("/books/OL35698073M").Result,
+ BorrowedAt = new DateTime(2022, 7, 7),
+ ReturnedAt = new DateTime(2022, 9, 1)
+ });
+ borrowings.Add(new Borrowing
+ {
+ Id = "/borrowing/04", Owner = contacts[1],
+ Book = LibraryMgr.GetBookById("/books/OL35698083M").Result,
+ BorrowedAt = new DateTime(2022, 7, 7),
+ ReturnedAt = new DateTime(2023, 8, 30)
+ });
+ }
+
+ public Task AddBook(Book book)
+ {
+ if(Books.Contains(book))
+ {
+ return Task.FromResult(null);
+ }
+ books.Add(book);
+ return Task.FromResult(book);
+ }
+
+ public async Task AddBook(string id)
+ {
+ if(Books.SingleOrDefault(b => b.Id == id) != null)
+ {
+ return null;
+ }
+ var book = await LibraryMgr.GetBookById(id);
+ books.Add(book);
+ return book;
+ }
+
+ public async Task AddBookByIsbn(string isbn)
+ {
+ if(Books.SingleOrDefault(b => b.ISBN13 == isbn) != null)
+ {
+ return null;
+ }
+ var book = await LibraryMgr.GetBookByISBN(isbn);
+ books.Add(book);
+ return book;
+ }
+
+ public Task RemoveBook(Book book)
+ {
+ return Task.FromResult(books.Remove(book));
+ }
+
+ public Task RemoveBook(string id)
+ {
+ return Task.FromResult(books.RemoveAll(b => b.Id == id) >= 0);
+ }
+
+ public Task RemoveBookByIsbn(string isbn)
+ {
+ return Task.FromResult(books.RemoveAll(b => b.ISBN13 == isbn) >= 0);
+ }
+
+ public Task AddToFavorites(Book book)
+ {
+ if(Favorites.Contains(book))
+ {
+ return Task.FromResult(false);
+ }
+ var bookToAdd = Books.SingleOrDefault(b => b.Id == book.Id);
+ if(bookToAdd == null)
+ {
+ return Task.FromResult(false);
+ }
+ favorites.Add(bookToAdd);
+ return Task.FromResult(true);
+ }
+
+ public Task AddToFavorites(string bookId)
+ {
+ if(Favorites.SingleOrDefault(b => b.Id == bookId) != null)
+ {
+ return Task.FromResult(false);
+ }
+ var book = Books.SingleOrDefault(b => b.Id == bookId);
+ if(book == null)
+ {
+ return Task.FromResult(false);
+ }
+ favorites.Add(book);
+ return Task.FromResult(true);
+ }
+
+ public Task RemoveFromFavorites(Book book)
+ {
+ return Task.FromResult(favorites.Remove(book));
+ }
+
+ public Task RemoveFromFavorites(string bookId)
+ {
+ return Task.FromResult(favorites.RemoveAll(b => b.Id == bookId) >= 0);
+ }
+
+ public Task AddContact(Contact contact)
+ {
+ if(Contacts.Contains(contact))
+ {
+ return Task.FromResult(null);
+ }
+ contacts.Add(contact);
+ return Task.FromResult(contact);
+ }
+
+ public Task RemoveContact(Contact contact)
+ {
+ return Task.FromResult(contacts.Remove(contact));
+ }
+
+ public Task LendBook(Book book, Contact contact, DateTime? loanDate = null)
+ {
+ if(!Books.Contains(book))
+ return Task.FromResult(false);
+ if(!Contacts.Contains(contact))
+ AddContact(contact);
+ Loan loan = new Loan { Book = book, Loaner = contact, LoanedAt = loanDate.GetValueOrDefault(DateTime.Now) };
+ if(Loans.Contains(loan))
+ return Task.FromResult(false);
+ loans.Add(loan);
+ return Task.FromResult(true);
+ }
+
+ public Task GetBackBook(Book book, DateTime? returnedDate = null)
+ {
+ if(!Books.Contains(book))
+ return Task.FromResult(false);
+ var loan = loans.SingleOrDefault(l => l.Book == book);
+ if(loan == null)
+ return Task.FromResult(false);
+ loan.ReturnedAt = returnedDate.GetValueOrDefault(DateTime.Now);
+ return Task.FromResult(true);
+ }
+
+ public Task BorrowBook(Book book, Contact owner, DateTime? borrowedDate = null)
+ {
+ if(!Books.Contains(book))
+ return Task.FromResult(false);
+ if(!Contacts.Contains(owner))
+ AddContact(owner);
+ Borrowing borrow = new Borrowing { Book = book, Owner = owner, BorrowedAt = borrowedDate.GetValueOrDefault(DateTime.Now) };
+ if(Borrowings.Contains(borrow))
+ return Task.FromResult(false);
+ borrowings.Add(borrow);
+ return Task.FromResult(true);
+ }
+
+ public Task GiveBackBook(Book book, DateTime? returnedDate = null)
+ {
+ if(!Books.Contains(book))
+ return Task.FromResult(false);
+ var borrow = borrowings.SingleOrDefault(b => b.Book == book);
+ if(borrow == null)
+ return Task.FromResult(false);
+ borrow.ReturnedAt = returnedDate.GetValueOrDefault(DateTime.Now);
+ return Task.FromResult(true);
+ }
+
+ public Task GetBookById(string id)
+ {
+ return Task.FromResult(Books.SingleOrDefault(b => b.Id == id));
+ }
+
+ public Task GetBookByISBN(string isbn)
+ {
+ return Task.FromResult(Books.SingleOrDefault(b => b.ISBN13 == isbn));
+ }
+
+ public Task>> GetBooksByTitle(string title, int index, int count, string sort = "")
+ {
+ var foundBooks = Books.Where(b => b.Title.Contains(title, StringComparison.InvariantCultureIgnoreCase));
+ return OrderBooks(foundBooks, index, count, sort);
+ }
+
+ public Task>> GetBooksByAuthorId(string authorId, int index, int count, string sort = "")
+ {
+ var foundBooks = Books.Where(b => b.Authors.Exists(a => a.Id.Contains(authorId))
+ || b.Works.Exists(w => w.Authors.Exists(a => a.Id.Contains(authorId))));
+ return OrderBooks(books, index, count, sort);
+ }
+
+ public Task>> GetBooksByAuthor(string author, int index, int count, string sort = "")
+ {
+ var foundBooks = Books.Where(b => ContainsAuthorName(b, author));
+ return OrderBooks(books, index, count, sort);
+ }
+
+ public IEnumerable Authors
+ {
+ get
+ {
+ var bookAuthors = Books.SelectMany(b => b.Authors);
+ var workAuthors = Books.SelectMany(b => b.Works).SelectMany(w => w.Authors);
+ return bookAuthors.Union(workAuthors).Distinct();
+ }
+ }
+
+ public Task GetAuthorById(string id)
+ {
+ return Task.FromResult(Authors.SingleOrDefault(a => a.Id == id));
+ }
+
+ private Task>> OrderAuthors(IEnumerable authors, int index, int count, string sort = "")
+ {
+ switch(sort)
+ {
+ case "name":
+ authors = authors.OrderBy(a => a.Name);
+ break;
+ case "name_reverse":
+ authors = authors.OrderByDescending(a => a.Name);
+ break;
+ }
+ return Task.FromResult(Tuple.Create((long)authors.Count(), authors.Skip(index*count).Take(count)));
+ }
+
+ public Task>> GetAuthorsByName(string substring, int index, int count, string sort = "")
+ {
+ var foundAuthors = Authors.Where(a => a.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase)
+ || a.AlternateNames.Exists(alt => alt.Contains(substring, StringComparison.InvariantCultureIgnoreCase)));
+ return OrderAuthors(foundAuthors, index, count, sort);
+ }
+
+ public Task UpdateBook(Book updatedBook)
+ {
+ if(!books.Contains(updatedBook))
+ {
+ return Task.FromResult(null);
+ }
+ books.Remove(updatedBook);
+ books.Add(updatedBook);
+ return Task.FromResult(updatedBook);
+ }
+
+ private Task>> OrderBooks(IEnumerable books, int index, int count, string sort = "")
+ {
+ switch(sort)
+ {
+ case "title":
+ books = books.OrderBy(b => b.Title);
+ break;
+ case "title_reverse":
+ books = books.OrderByDescending(b => b.Title);
+ break;
+ case "new":
+ books = books.OrderByDescending(b => b.PublishDate);
+ break;
+ case "old":
+ books = books.OrderBy(b => b.PublishDate);
+ break;
+
+ }
+ return Task.FromResult(Tuple.Create(books.LongCount(), books.Skip(index*count).Take(count)));
+ }
+
+ private bool ContainsAuthorName(Book book, string name)
+ {
+ IEnumerable authors = new List();
+
+ if(book.Authors != null && book.Authors.Count > 0)
+ {
+ authors = authors.Union(book.Authors);
+ }
+ if(book.Works != null)
+ {
+ var worksAuthors = book.Works.SelectMany(w => w.Authors).ToList();
+ if(worksAuthors.Count > 0)
+ authors = authors.Union(worksAuthors);
+ }
+ foreach(var author in authors)
+ {
+ if(author.Name.Contains(name, StringComparison.OrdinalIgnoreCase)
+ || author.AlternateNames.Exists(alt => alt.Contains(name, StringComparison.OrdinalIgnoreCase)))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Task>> GetBooksFromCollection(int index, int count, string sort = "")
+ {
+ return OrderBooks(Books, index, count, sort);
+ }
+
+ public Task>> GetCurrentLoans(int index, int count)
+ {
+ var currentLoans = Loans.Where(l => !l.ReturnedAt.HasValue);
+ return Task.FromResult(Tuple.Create(currentLoans.LongCount(), currentLoans.Skip(index*count).Take(count)));
+ }
+
+ public Task>> GetPastLoans(int index, int count)
+ {
+ var currentLoans = Loans.Where(l => l.ReturnedAt.HasValue);
+ return Task.FromResult(Tuple.Create(currentLoans.LongCount(), currentLoans.Skip(index*count).Take(count)));
+ }
+
+ public Task>> GetCurrentBorrowings(int index, int count)
+ {
+ var currentBorrowings = Borrowings.Where(l => !l.ReturnedAt.HasValue);
+ return Task.FromResult(Tuple.Create(currentBorrowings.LongCount(), currentBorrowings.Skip(index*count).Take(count)));
+ }
+
+ public Task>> GetPastBorrowings(int index, int count)
+ {
+ var currentBorrowings = Borrowings.Where(l => l.ReturnedAt.HasValue);
+ return Task.FromResult(Tuple.Create(currentBorrowings.LongCount(), currentBorrowings.Skip(index*count).Take(count)));
+ }
+
+ public Task>> GetContacts(int index, int count)
+ {
+ return Task.FromResult(Tuple.Create(Contacts.LongCount(), Contacts.Skip(index*count).Take(count)));
+ }
+ }
+}
+
diff --git a/sources/StubbedDTO/Stub.cs b/sources/StubbedDTO/Stub.cs
new file mode 100644
index 0000000..e8fc5b8
--- /dev/null
+++ b/sources/StubbedDTO/Stub.cs
@@ -0,0 +1,208 @@
+using System.Data.SqlTypes;
+using System.Reflection;
+using DtoAbstractLayer;
+using JsonReader;
+using LibraryDTO;
+using static System.Reflection.Metadata.BlobBuilder;
+
+namespace StubbedDTO;
+
+public class Stub : IDtoManager
+{
+ public static List Authors { get; set; } = new List();
+
+ public static List Books { get; set; } = new List();
+
+ public static List Works { get; set; } = new List();
+
+ public static Assembly Assembly => typeof(Stub).Assembly;
+
+ static Stub()
+ {
+ foreach(var resource in Assembly.GetManifestResourceNames().Where(n => n.Contains("authors")))
+ {
+ using(Stream stream = Assembly.GetManifestResourceStream(resource))
+ using(StreamReader reader = new StreamReader(stream))
+ {
+ Authors.Add(AuthorJsonReader.ReadAuthor(reader.ReadToEnd()));
+ }
+ }
+
+ foreach(var resource in Assembly.GetManifestResourceNames().Where(n => n.Contains("works")))
+ {
+ var ratingsResource = resource.Insert(resource.LastIndexOf('.'), ".ratings").Replace("works", "ratings");
+
+ using(Stream stream = Assembly.GetManifestResourceStream(resource))
+ using(StreamReader reader = new StreamReader(stream))
+ using(Stream streamRatings = Assembly.GetManifestResourceStream(ratingsResource))
+ using(StreamReader readerRatings = new StreamReader(streamRatings))
+ {
+ var work = WorkJsonReader.ReadWork(reader.ReadToEnd(), readerRatings.ReadToEnd());
+ if(work.Authors != null)
+ foreach(var author in work.Authors.ToList())
+ {
+ var newAuthor = Authors.SingleOrDefault(a => a.Id == author.Id);
+ work.Authors.Remove(author);
+ work.Authors.Add(newAuthor);
+ }
+ Works.Add(work);
+ }
+ }
+
+ foreach(var resource in Assembly.GetManifestResourceNames().Where(n => n.Contains("books")))
+ {
+ using(Stream stream = Assembly.GetManifestResourceStream(resource))
+ using(StreamReader reader = new StreamReader(stream))
+ {
+ var book = BookJsonReader.ReadBook(reader.ReadToEnd());
+ foreach(var author in book.Authors.ToList())
+ {
+ var newAuthor = Authors.SingleOrDefault(a => a.Id == author.Id);
+ book.Authors.Remove(author);
+ book.Authors.Add(newAuthor);
+ }
+ foreach(var work in book.Works.ToList())
+ {
+ var newWork = Works.SingleOrDefault(w => w.Id == work.Id);
+ book.Works.Remove(work);
+ book.Works.Add(newWork);
+ }
+ Books.Add(book);
+ }
+ }
+ }
+
+ public Task GetAuthorById(string id)
+ {
+ var author = Stub.Authors.SingleOrDefault(a => a.Id.Contains(id));
+ return Task.FromResult(author);
+ }
+
+ private Task>> OrderAuthors(IEnumerable authors, int index, int count, string sort = "")
+ {
+ switch(sort)
+ {
+ case "name":
+ authors = authors.OrderBy(a => a.Name);
+ break;
+ case "name_reverse":
+ authors = authors.OrderByDescending(a => a.Name);
+ break;
+ }
+ return Task.FromResult(Tuple.Create((long)authors.Count(), authors.Skip(index*count).Take(count)));
+ }
+
+ public async Task>> GetAuthors(int index, int count, string sort = "")
+ {
+ IEnumerable authors = Stub.Authors;
+ return await OrderAuthors(authors, index, count, sort);
+ }
+
+ public async Task