Compare commits

..

43 Commits

Author SHA1 Message Date
Emre KARTAL 5ba7ffaea9 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL ab3a4bba0c Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 998dff6490 Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 2c630c77d0 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL de4a02bcc8 Merge pull request 'ApiManager' (#11) from ApiManager into master
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 8f28944450 Correct some errors 🐛
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL f66fc1a48d completion of the ApiManager
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL dded54568b Beginning ApiManager
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL c2372ec447 Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 8c5a9d7b49 Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 40da19ed6f Correct error CI 🐛
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 91c36e266c correct some errors 🐛
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 43cf7792e6 Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL f929c72194 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 51afc1d03f Merge pull request 'MAUI_Settings' (#10) from MAUI_Settings into master
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 75f43c319f Merge branch 'MAUI_Settings' of https://codefirst.iut.uca.fr/git/emre.kartal/LolProject into MAUI_Settings
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL cf320b341b DbManager and MAUI Done
2 years ago
Emre KARTAL da5d3d7bef Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL b53c1e10e4 Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL ac20890cb6 Update README and completion of the DbManager Champion
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 9dfa473ad3 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL f5155dafb8 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 0b19d8b016 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL cb0c9e4071 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL ceeae34769 Mise à jour de 'README.md'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 7bd6b69cd0 Mise à jour de 'README.md'
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 8da497bd6e Add Client MAUI
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 00c5ad1c24 Changes to achievements
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL f1142a0f0e Merge pull request 'UT_EF_Manager' (#9) from UT_EF_Manager into master
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 78e19b25d5 Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL cfae72db6c Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL f0d1451095 Merge pull request 'API_RunePage_ReadMe_UT' (#8) from API_RunePage_ReadMe_UT into master
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 195db06bfd RunePagesController and UT done
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 48f4b27ae3 Addition of modifications of Mr Chevaldonne and rehabilitation of unit tests 🐛
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL b603bcdd0d Correct Error for UT
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 8e6fd3984a Again correct error ⚠️
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL c7f434a29c Correct error ⚠️
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL b937756b4b Dictionary for ChampionDto done and beginning the RunePageController 🙈
continuous-integration/drone/push Build is failing Details
2 years ago
Emre KARTAL 6d2d6f9ffd Update README
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 43001258c8 Merge branch 'API_RunePage_ReadMe_UT' of https://codefirst.iut.uca.fr/git/emre.kartal/LolProject into API_RunePage_ReadMe_UT
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 3794752e70 More UT and correct error
2 years ago
Emre KARTAL 0d4056e4fc Correction of errors in the README 🚩
continuous-integration/drone/push Build is passing Details
2 years ago
Emre KARTAL 7d8152215a Explanation of the achitecture in the README done ✏️
continuous-integration/drone/push Build is passing Details
2 years ago

@ -1,6 +1,6 @@
kind: pipeline kind: pipeline
type: docker type: docker
name: default name: LolProject
trigger: trigger:
event: event:
@ -14,28 +14,28 @@ steps:
path: /docs path: /docs
commands: commands:
- cd src/EntityFramework_LoL/Sources/ - cd src/EntityFramework_LoL/Sources/
- dotnet restore LeagueOfLegends.sln - dotnet restore LeagueOfLegendsCI.sln
- dotnet build LeagueOfLegends.sln -c Release --no-restore - dotnet build LeagueOfLegendsCI.sln -c Release --no-restore
- dotnet publish LeagueOfLegends.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release - dotnet publish LeagueOfLegendsCI.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release
- name: tests - name: tests
image: mcr.microsoft.com/dotnet/sdk:6.0 image: mcr.microsoft.com/dotnet/sdk:6.0
commands: commands:
- cd src/EntityFramework_LoL/Sources/ - cd src/EntityFramework_LoL/Sources/
- dotnet restore LeagueOfLegends.sln - dotnet restore LeagueOfLegendsCI.sln
- dotnet test LeagueOfLegends.sln --no-restore - dotnet test LeagueOfLegendsCI.sln --no-restore
depends_on: [build] depends_on: [build]
- name: code-analysis - name: code-analysis
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dronesonarplugin-dotnet6 image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dronesonarplugin-dotnet6
commands: commands:
- cd src/EntityFramework_LoL/Sources/ - cd src/EntityFramework_LoL/Sources/
- dotnet restore LeagueOfLegends.sln - dotnet restore LeagueOfLegendsCI.sln
- dotnet sonarscanner begin /k:LolProjectIUT /d:sonar.host.url=$${PLUGIN_SONAR_HOST} /d:sonar.coverageReportPaths="coveragereport/SonarQube.xml" /d:sonar.coverage.exclusions="Tests/**" /d:sonar.login=$${PLUGIN_SONAR_TOKEN} - dotnet sonarscanner begin /k:LolProjectIUT /d:sonar.host.url=$${PLUGIN_SONAR_HOST} /d:sonar.coverageReportPaths="coveragereport/SonarQube.xml" /d:sonar.coverage.exclusions="Tests/**,DbManager/**,Client/**" /d:sonar.login=$${PLUGIN_SONAR_TOKEN}
- dotnet build LeagueOfLegends.sln -c Release --no-restore - dotnet build LeagueOfLegendsCI.sln -c Release --no-restore
- dotnet test LeagueOfLegends.sln --logger trx --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --collect "XPlat Code Coverage" - dotnet test LeagueOfLegendsCI.sln --logger trx --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --collect "XPlat Code Coverage"
- reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport" - reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport"
- dotnet publish LeagueOfLegends.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release - dotnet publish LeagueOfLegendsCI.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release
- dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN} - dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN}
secrets: [ SECRET_SONAR_LOGIN ] secrets: [ SECRET_SONAR_LOGIN ]
settings: settings:

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -11,28 +11,57 @@
[![Duplicated Lines (%)](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=duplicated_lines_density&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT) [![Duplicated Lines (%)](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=duplicated_lines_density&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT)
[![Security Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=security_rating&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT) [![Security Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=security_rating&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT)
[![Vulnerabilities](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=vulnerabilities&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT) [![Vulnerabilities](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=vulnerabilities&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT)
[![Coverage](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=coverage&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT)
[![Bugs](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=bugs&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT)
[![Maintainability Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=LolProjectIUT&metric=sqale_rating&token=b65c8ed30f0fbe374e41e98340dc910942b77bba)](https://codefirst.iut.uca.fr/sonar/dashboard?id=LolProjectIUT)
--- ---
</div> </div>
**Thème du projet** : Réalisation d'une API et d'un ORM (Entity Framework) qui seront reliés à une base de données dans le thème de League of Legends <img src="https://logo-marque.com/wp-content/uploads/2020/11/League-of-Legends-Embleme.png" width="40" > **Thème du projet** : Réalisation d'une API Rest Full et d'un ORM (Entity Framework) qui seront reliés à une base de données (SQLite) dans le thème de League of Legends <img src="https://logo-marque.com/wp-content/uploads/2020/11/League-of-Legends-Embleme.png" width="40" >
</br> </br>
<img src="doc/Images/Title-Répartition.png" width="400"> <img src="doc/Images/Title-Répartition.png" width="400">
La racine de mon GitLab contient deux dossiers essentiels pour le projet : <u>La racine de mon GitLab contient deux dossiers :open_file_folder: essentiels pour le projet :</u>
[**src**](src) : **Toute la partie codage de l'application** [**src**](src) : **Toute la partie codage de l'application**
[**doc**](doc) : **Documentation de l'application** (Images + Schéma et description de l'architecture globale de l'application) [**doc**](doc) : **Documentation de l'application** (Images + Schéma de l'architecture globale de l'application)
👉 [**Solution de l'application**](src/EntityFramework_LoL/Sources/LeagueOfLegends.sln) 👉 [**Solution de l'application**](src/EntityFramework_LoL/Sources/LeagueOfLegends.sln)
👉 [**Solution de l'application pour la CI**](src/EntityFramework_LoL/Sources/LeagueOfLegendsCI.sln)
<img src="doc/Images/Title-Fonctionnement.png" width="460" > <img src="doc/Images/Title-Fonctionnement.png" width="460" >
- ### :building_construction: Comment est structurée l'architecture globale de l'application ?
Voici un **schéma** pour mieux représenter mon architecture :
<img src="doc/Schémas/Architecture_Global.png" width="1000" >
</br>
</br>
:information_source: Tout d'abord, il y a la partie client, qui correspond à tous les appareils :computer: qui vont effectuer des requêtes à mon API et recevoir, sous format *.json*:envelope: (JavaScript Object Notation), des informations sur des champions, des skins, etc.
La web API est chargée de transformer les classes métiers du modèle en DTO (Data Transfer Object), afin de filtrer et renvoyer seulement les données essentielles aux utilisateurs. Pour obtenir les données qu'elle va transmettre, elle utilise d'abord l'IDataManager du modèle, qui est hérité par le stub (:pushpin:un regroupement de fausses données qui permet de s'assurer que tout fonctionne et d'éviter de bloquer le développement), puis le DbManager, qui contactera la base de données et assurera la persistance des données.
Grâce à l'injection de dépendances dans le projet, la Web API n'a pas besoin d'être modifiée lorsqu'on veut passer du StubLib au DbManager (si vous ne savez pas ce que c'est, je vous invite à voir cette vidéo qui explique très clairement l'[Injection de dépendances](https://www.youtube.com/watch?v=OeWgBNR1BLU&t=10s&ab_channel=BaptisteMobileDev)).
La partie ```bases de données``` est gérée par le DbManager, qui utilise l'ORM Entity Framework (plus précisément le DbContext) pour récupérer les données dans la base de données. De plus, grâce à une factory :factory: (oui, comme celle de la web API), elle transforme les données en tables (appelées "Entities") en classes du modèle (et inversement).
Le client MAUI pourra effectuer des requêtes HTTP à l'API via l'API Manager, qui hérite de IDataManager et possède une liste de fonctions responsables d'exécuter les requêtes. De cette manière, le client n'aura pas besoin de connaître l'API pour interagir avec elle. :bulb:
- ### Comment récupérer le projet ? - ### Comment récupérer le projet ?
Tout d'abord, si ce n'est pas déjà fait, clonez le dépôt de la branche **master/main**. Pour ce faire, copiez le lien URL du dépôt git : Tout d'abord, si ce n'est pas déjà fait, clonez le dépôt de la branche **master/main**. Pour ce faire, copiez le lien URL du dépôt git :
@ -53,9 +82,9 @@ Vous pouvez le cloner via un terminal dans le répertoire de votre choix en util
:information_source: *Si vous ne disposez pas de Visual Studio, allez sur le site [Microsoft Visual Studio](https://visualstudio.microsoft.com/fr/downloads/) pour pouvoir le télécharger !!!* :information_source: *Si vous ne disposez pas de Visual Studio, allez sur le site [Microsoft Visual Studio](https://visualstudio.microsoft.com/fr/downloads/) pour pouvoir le télécharger !!!*
- ### Comment lancer l'API dotnet ? - ### Comment lancer l'API dotnet :question:
Pour pouvoir utiliser toutes les requêtes de l'API, il est nécessaire de récupérer le projet si cela n'a pas été fait, puis de le lancer à partir de Visual Studio. Vous pouvez directement cliquer sur la solution du projet. Ensuite, dans les projets de démarrage, choisissez "Api-Lol" : Pour pouvoir utiliser toutes les requêtes de l'API, il est nécessaire de récupérer le projet si cela n'a pas été fait, puis de le lancer à partir de Visual Studio. Vous pouvez directement cliquer sur la solution du projet. Ensuite, dans les projets de démarrage, choisissez **Api-Lol** :
<div align = center> <div align = center>
@ -63,7 +92,7 @@ Pour pouvoir utiliser toutes les requêtes de l'API, il est nécessaire de récu
</div> </div>
Normalement, tout est bon et vous serez redirigé vers Swagger, qui est l'interface graphique permettant d'effectuer facilement des requêtes. Il vous suffit ensuite de choisir la version en haut à droite. La version 3.0 est normalement la plus récente et la plus performante en termes de gestion d'erreur : Normalement, tout est bon et vous serez redirigé vers Swagger, qui est l'interface graphique permettant d'effectuer facilement des requêtes. Il vous suffit ensuite de choisir la version en haut à droite. La ```version 2.0``` est normalement la plus récente et la plus performante en termes de gestion d'erreur :
<div align = center> <div align = center>
@ -71,7 +100,7 @@ Normalement, tout est bon et vous serez redirigé vers Swagger, qui est l'interf
</div> </div>
Vous pouvez aussi utiliser l'API via cette url: https://codefirst.iut.uca.fr/containers/emrekartal-lolApi/Api/v3/champions :paperclip: Vous pouvez aussi utiliser l'API via cette url: https://codefirst.iut.uca.fr/containers/emrekartal-lolApi/Api/v3/champions
- ### Comment lancer Le projet Entity Framework ? - ### Comment lancer Le projet Entity Framework ?
@ -85,11 +114,11 @@ Assurez-vous également d'avoir installé les packages Nuget suivants sur Visual
</div> </div>
Ensuite, sur le terminal PowerShell ou Visual Studio, lancer la migration via la commande : **dotnet ef migrations add monNomDeMigration** (n'oubliez pas de vous situer dans le dossier "/MyFlib" lorsque vous l'exécutez)! Ensuite, sur le terminal PowerShell ou Visual Studio, lancer la migration via la commande : **dotnet ef migrations add monNomDeMigration** (n'oubliez pas de vous situer dans le dossier **/MyFlib** lorsque vous l'exécutez)!
- ### Comment voir la base de données ? - ### Comment voir la base de données ?
C'est bien beau toutes ces étapes, mais sil n'y a pas de résultat, à quoi cela sert ! ```C'est bien beau toutes ces étapes, mais sil n'y a pas de résultat, à quoi cela sert !```
Tout d'abord, veuillez regarder dans l'onglet Extensions si l'outil **SQLite and SQL Server Compact Toolbax** est bien installé. Tout d'abord, veuillez regarder dans l'onglet Extensions si l'outil **SQLite and SQL Server Compact Toolbax** est bien installé.
@ -114,6 +143,102 @@ réalisez à nouveau la migration (ou mettez à jour celle actuelle), puis suppr
:information_source: *Notez qu'il est également possible, grâce à SQLLite, d'ajouter, modifier ou supprimer des données dans les tables.* :information_source: *Notez qu'il est également possible, grâce à SQLLite, d'ajouter, modifier ou supprimer des données dans les tables.*
<br>
- ### Comment utiliser l'application MAUI ?
Si vous préférez éviter la manipulation de l'API, vous pouvez également utiliser le **client MAUI**. Celui-ci contacte directement l'ApiManager, qui se charge des requêtes HTTP à l'API, et vous permet de visualiser et de modifier les données grâce à une interface graphique.
Pour accomplir cela, veuillez configurer les propriétés de la solution en cliquant avec le bouton droit de la souris sur la solution, puis en sélectionnant "propriétés". De cette façon, vous pourrez lancer à la fois l'API et l'application League of Legends. Assurez-vous d'avoir les mêmes configurations :
<div align = center>
![HowToLaunch](doc/Images/HowToLaunch.png)
</div>
<u>Page **Home**:</u>
<div align = center>
![start BD](doc/Images/MauiClientHome.png)
</div>
<u>Page **Champions**:</u>
<div align = center>
![start BD](doc/Images/MauiClientChampions.gif)
</div>
Vous pouvez vous amuser à filtrer les champions sur cette page, visualiser leurs skins, les modifier, et même en ajouter ! :grin:
:information_source: *Pour utiliser cette application, vous devez avoir la dernière version de Visual Studio, avoir effectué la migration auparavant (comme indiqué ci-dessus), et avoir sélectionné la solution **LeagueOfLegends** plutôt que **LeagueOfLegendsCi**. Si vous avez besoin d'aide ou si vous souhaitez obtenir plus d'informations, vous pouvez contacter le technicien responsable de l'application (c'est-à-dire moi), en vous référant à mon mail ci-dessous. :email: Notez également qu'il est capable de lancer l'application soit à partir de votre téléphone Android, soit via un émulateur !*
- ### Tests Unitaires :triangular_flag_on_post:
Afin de garantir un code de qualité avec le moins d'erreurs possible, j'ai pris soin de réaliser des tests unitaires tout au long de ce projet à l'aide de la bibliothèque **XUnit**. J'ai ensuite intégré ces tests à mon processus d'intégration continue (CI) via l'outil ```Drone```, ce qui m'a permis de détecter rapidement toute erreur ou anomalie tout au long du projet. L'utilisation de tests unitaires et d'une intégration continue a été essentielle pour garantir la qualité du code, améliorer la maintenabilité et réduire le temps nécessaire pour détecter et corriger les erreurs.:bug:
Toute la partie EF et API a été testée correctement. Cependant, le DbManager et l'ApiManager qui les utilisent n'ont pas été testés et ont été retirés de la couverture de code sur **SonarQube**. Voici la couverture de code actuelle de chaque partie (le 26/03/23) :
<div align = center>
![Couverture de code](doc/Images/Tests-Coverage.png)
</div>
:information_source: *La partie API a été testée uniquement pour vérifier le bon fonctionnement de ses mécanismes de base. Cependant, je n'ai pas réalisé de tests pour vérifier les scénarios d'erreur possibles qui pourraient survenir lors de l'exécution de ces fonctions. De plus, la partie modèle et la bibliothèque Stublib ont été testées simultanément avec l'API.*
- ### Avancement du projet :construction_worker:
<u>Où en suis-je</u>:grey_question::grey_exclamation: (:white_check_mark: réalisé, :warning: presque abouti, :x: non commencé )
Côté API :
- :white_check_mark: [**Partie 1**](src/EntityFramework_Lol/Sources/ApiLol/Controllers) : **Mise en place de toutes les opérations CRUD**
- :white_check_mark: [**Partie 2**](src/EntityFramework_Lol/Sources/ApiLol/Controllers) : **Respect des règles de routage, utilisation des bons status code**
- :white_check_mark: [**Partie 3**](src/EntityFramework_Lol/Sources/ApiLol/Controllers) : **Versionnage de l'api**
- :white_check_mark: [**Partie 4**](src/EntityFramework_Lol/Sources/Tests/ApiTests) : **Tests unitaires**
- :white_check_mark: [**Partie 5**](.drone.yml) : **Dockerisation et Hébergement de l'API**
- :white_check_mark: [**Partie 6**](src/EntityFramework_Lol/Sources/ApiLol/Controllers) : **Logs**
- :white_check_mark: [**Partie 7**](src/EntityFramework_Lol/Sources/ApiLol/Controllers) : **Filtrage + Pagination des données**
- :x: [**Partie 8**](src/EntityFramework_Lol/Sources/ApiLol/) : **Utilisation des fichiers configurations**
- :warning: [**Partie 9**](src/EntityFramework_Lol/Sources/) : **Réalisation du client MAUI et liaison avec l'api**
- :white_check_mark: [**Partie 10**](src/EntityFramework_Lol/Sources/ApiLol/) : **Liaison avec la base de données**
Côté Entity_Framework :
- :white_check_mark: [**Partie 1**](src/EntityFramework_Lol/Sources/MyFlib/Entities) : **Réalisation des Entities**
- :white_check_mark: [**Partie 2**](src/EntityFramework_Lol/Sources/MyFlib/DataSeeder.cs) : **Data seeder**
- :white_check_mark: [**Partie 3**](src/EntityFramework_Lol/Sources/Tests/UT_EF) : **Tests unitaires**
- :white_check_mark: [**Partie 4**](src/EntityFramework_Lol/Sources/MyFlib) : **Many to many**
- :white_check_mark: [**Partie 5**](src/EntityFramework_Lol/Sources/) : **DbManager**
- :white_check_mark: [**Partie 6**](src/EntityFramework_Lol/Sources/) : **Mapping**
Autre :
- :white_check_mark: [**Partie 1**](.drone.yml) : **Mise en place de SonarQube**
- :white_check_mark: [**Partie 2**](.drone.yml) : **Schéma et description de l'architecture globale de l'application**
<img src="doc/Images/Title-Environnement.png" width="400" > <img src="doc/Images/Title-Environnement.png" width="400" >
Mon environnement de travail est basé sur un outil et un langage en particulier : 👇 Mon environnement de travail est basé sur un outil et un langage en particulier : 👇
@ -133,9 +258,19 @@ Mon environnement de travail est basé sur un outil et un langage en particulier
<img src="doc/Images/Title-Technicien.png" width="400" > <img src="doc/Images/Title-Technicien.png" width="400" >
⚙️ Emre KARTAL :mortar_board: **Emre KARTAL** - *Emre.kartal@etu.uca.fr*
<br> <br>
<div align = center> <div align = center>
<a href = "https://codefirst.iut.uca.fr/git/emre.kartal">
<img src="https://codefirst.iut.uca.fr/git/avatars/402cf312e853192f42c0135a888725c2?size=870" width="50" >
</br>
</a>
© PM2 © PM2
</div> </div>
<hr>
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/88x31.png" /></a><br />Ce(tte) œuvre est mise à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Licence Creative Commons Attribution - Pas d&#39;Utilisation Commerciale - Pas de Modification 4.0 International</a>.

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

@ -17,6 +17,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ApiMapping\ApiMapping.csproj" />
<ProjectReference Include="..\DbManager\DbManager.csproj" />
<ProjectReference Include="..\DTO\DTO.csproj" /> <ProjectReference Include="..\DTO\DTO.csproj" />
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\StubLib\StubLib.csproj" /> <ProjectReference Include="..\StubLib\StubLib.csproj" />

@ -0,0 +1,181 @@
using ApiMapping;
using DTO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Model;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace ApiLol.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class RunePagesController : ControllerBase
{
private readonly IDataManager _manager;
private readonly ILogger<RunePagesController> _logger;
public RunePagesController(IDataManager dataManager, ILogger<RunePagesController> logger)
{
_manager = dataManager;
_logger = logger;
}
// GET: api/<RunePagesController>
[HttpGet]
public async Task<IActionResult> Get([FromQuery] PageRequest pageRequest)
{
_logger.LogInformation("Executing {Action} - RUNEPAGE with parameters: {Parameters}", nameof(Get), pageRequest);
try
{
int nbTotal = await _manager.RunePagesMgr.GetNbItems();
if (pageRequest.count == 0)
{
pageRequest = new PageRequest() { index = 0, count = nbTotal, orderingPropertyName = pageRequest.orderingPropertyName, descending = pageRequest.descending, name = pageRequest.name };
}
else if (pageRequest.count * pageRequest.index >= nbTotal || pageRequest.count > nbTotal)
{
_logger.LogWarning("too many, maximum {number}", nbTotal);
return BadRequest($"RunePage limit exceed, max {nbTotal}");
}
IEnumerable<RunePageDto> dtos;
if (pageRequest.name == null)
{
dtos = (await _manager.RunePagesMgr.GetItems(pageRequest.index, pageRequest.count, pageRequest.orderingPropertyName, pageRequest.descending))
.Select(x => x.ToDto());
}
else
{
dtos = (await _manager.RunePagesMgr.GetItemsByName(pageRequest.name, pageRequest.index, pageRequest.count, pageRequest.orderingPropertyName, pageRequest.descending))
.Select(x => x.ToDto());
}
return Ok(new PageResponse<RunePageDto> { Data = dtos, index = pageRequest.index, count = pageRequest.count, total = nbTotal });
}
catch (Exception error)
{
_logger.LogError(error.Message);
return BadRequest(error.Message);
}
}
// GET api/<RunePagesController>/5
[HttpGet("{name}")]
public async Task<IActionResult> Get(string name)
{
_logger.LogInformation("method {Action} - RUNEPAGE call with {name}", nameof(Get), name);
try
{
var dtos = (await _manager.RunePagesMgr.GetItemByName(name, 0, await _manager.RunePagesMgr.GetNbItems()))
.Select(x => x.ToDto());
if (dtos.IsNullOrEmpty())
{
_logger.LogWarning($"{name} was not found");
return NotFound($"{name} was not found");
}
return Ok(dtos.First());
}
catch (Exception error)
{
_logger.LogError(error.Message);
return BadRequest(error.Message);
}
}
// POST api/<RunePagesController>
[HttpPost]
public async Task<IActionResult> Post([FromBody] RunePageDto runePage)
{
_logger.LogInformation("method {Action} - RUNEPAGE call with {item}", nameof(Post), runePage);
try
{
if (await _manager.RunePagesMgr.GetNbItemsByName(runePage.Name) == 0)
{
return CreatedAtAction(nameof(Get),
(await _manager.RunePagesMgr.AddItem(runePage.ToModel())).ToDto());
}
_logger.LogWarning($"Name : {runePage.Name} is already exist");
return BadRequest($"Name : {runePage.Name} is already exist");
}
catch (Exception error)
{
_logger.LogError(error.Message);
return BadRequest(error.Message);
}
}
// PUT api/<RunePagesController>/5
[HttpPut("{name}")]
public async Task<IActionResult> Put(string name, [FromBody] RunePageDto runePage)
{
_logger.LogInformation("method {Action} - RUNEPAGE call with {name} and {item}", nameof(Put), name, runePage);
try
{
var dtos = (await _manager.RunePagesMgr.GetItemByName(name, 0, await _manager.RunePagesMgr.GetNbItems()));
if (dtos.IsNullOrEmpty())
{
return NotFound($"Name {name} not exist");
}
// Checks if the new name exists
if (name != runePage.Name)
{
var dtos2 = (await _manager.RunesMgr.GetItemByName(runePage.Name, 0, await _manager.RunePagesMgr.GetNbItems()));
if (!dtos2.IsNullOrEmpty() || dtos2.Count() > 0)
{
return BadRequest($"New Name {runePage.Name} is already exist");
}
}
return Ok((await _manager.RunePagesMgr.UpdateItem(dtos.First(), runePage.ToModel())).ToDto());
}
catch (Exception error)
{
_logger.LogError(error.Message);
return BadRequest(error.Message);
}
}
// DELETE api/<RunePagesController>/5
[HttpDelete("{name}")]
public async Task<IActionResult> Delete(string name)
{
_logger.LogInformation("method {Action} - RUNEPAGE call with {name}", nameof(Delete), name);
try
{
var dtos = (await _manager.RunePagesMgr.GetItemByName(name, 0, await _manager.RunePagesMgr.GetNbItems()));
if (dtos.IsNullOrEmpty())
{
_logger.LogWarning("{name} was not found", name);
return NotFound($"{name} was not found");
}
await _manager.RunePagesMgr.DeleteItem(dtos.First());
return NoContent();
}
catch (Exception error)
{
_logger.LogError(error.Message);
return BadRequest(error.Message);
}
}
[HttpGet("/countRunePages")]
public async Task<ActionResult> GetCountRunePages()
{
_logger.LogInformation("method {Action} - RUNEPAGE call", nameof(GetCountRunePages));
try
{
return Ok(await _manager.RunePagesMgr.GetNbItems());
}
catch (Exception error)
{
_logger.LogError(error.Message);
return BadRequest(error.Message);
}
}
}
}

@ -1,4 +1,4 @@
using ApiLol.Mapper; using ApiMapping;
using DTO; using DTO;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -51,7 +51,7 @@ namespace ApiLol.Controllers
dtos = (await _manager.RunesMgr.GetItemsByName(pageRequest.name, pageRequest.index, pageRequest.count, pageRequest.orderingPropertyName, pageRequest.descending)) dtos = (await _manager.RunesMgr.GetItemsByName(pageRequest.name, pageRequest.index, pageRequest.count, pageRequest.orderingPropertyName, pageRequest.descending))
.Select(x => x.ToDto()); .Select(x => x.ToDto());
} }
return Ok(new PageResponse<RuneDto>{ Data = dtos, index = pageRequest.index, count = pageRequest.count, total = nbTotal }); return Ok(new PageResponse<RuneDto> { Data = dtos, index = pageRequest.index, count = pageRequest.count, total = nbTotal });
} }
catch (Exception error) catch (Exception error)
@ -94,7 +94,7 @@ namespace ApiLol.Controllers
if (await _manager.RunesMgr.GetNbItemsByName(rune.Name) == 0) if (await _manager.RunesMgr.GetNbItemsByName(rune.Name) == 0)
{ {
return CreatedAtAction(nameof(Get), return CreatedAtAction(nameof(Get),
(await _manager.RunesMgr.AddItem(rune.ToModel()))); (await _manager.RunesMgr.AddItem(rune.ToModel())).ToDto());
} }
_logger.LogWarning($"Name : {rune.Name} is already exist"); _logger.LogWarning($"Name : {rune.Name} is already exist");
return BadRequest($"Name : {rune.Name} is already exist"); return BadRequest($"Name : {rune.Name} is already exist");
@ -122,12 +122,12 @@ namespace ApiLol.Controllers
if (name != rune.Name) if (name != rune.Name)
{ {
var dtos2 = (await _manager.RunesMgr.GetItemByName(rune.Name, 0, await _manager.RunesMgr.GetNbItems())); var dtos2 = (await _manager.RunesMgr.GetItemByName(rune.Name, 0, await _manager.RunesMgr.GetNbItems()));
if (dtos2.IsNullOrEmpty() || dtos2.Count() > 0) if (!dtos2.IsNullOrEmpty() || dtos2.Count() > 0)
{ {
return BadRequest($"New Name {rune.Name} is already exist"); return BadRequest($"New Name {rune.Name} is already exist");
} }
} }
return Ok(await _manager.RunesMgr.UpdateItem(dtos.First(),rune.ToModel())); return Ok((await _manager.RunesMgr.UpdateItem(dtos.First(), rune.ToModel())).ToDto());
} }
catch (Exception error) catch (Exception error)
@ -148,9 +148,10 @@ namespace ApiLol.Controllers
if (dtos.IsNullOrEmpty()) if (dtos.IsNullOrEmpty())
{ {
_logger.LogWarning("{name} was not found", name); _logger.LogWarning("{name} was not found", name);
return BadRequest(); return NotFound($"{name} was not found");
} }
return Ok(await _manager.RunesMgr.DeleteItem(dtos.First())); await _manager.RunesMgr.DeleteItem(dtos.First());
return NoContent();
} }
catch (Exception error) catch (Exception error)
{ {
@ -160,8 +161,9 @@ namespace ApiLol.Controllers
} }
[HttpGet("/countRunes")] [HttpGet("/countRunes")]
public async Task<ActionResult<int>> GetCountSkins() public async Task<ActionResult> GetCountRunes()
{ {
_logger.LogInformation("method {Action} - RUNE call", nameof(GetCountRunes));
try try
{ {
return Ok(await _manager.RunesMgr.GetNbItems()); return Ok(await _manager.RunesMgr.GetNbItems());

@ -1,4 +1,4 @@
using ApiLol.Mapper; using ApiMapping;
using DTO; using DTO;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -67,7 +67,7 @@ namespace ApiLol.Controllers
_logger.LogInformation("method {Action} - SKIN call with {name}", nameof(Get), name); _logger.LogInformation("method {Action} - SKIN call with {name}", nameof(Get), name);
try try
{ {
var dtos = (await _manager.SkinsMgr.GetItemByName(name, 0, await _manager.ChampionsMgr.GetNbItems())) var dtos = (await _manager.SkinsMgr.GetItemByName(name, 0, await _manager.SkinsMgr.GetNbItems()))
.Select(x => x.ToDtoC()); .Select(x => x.ToDtoC());
if (dtos.IsNullOrEmpty()) if (dtos.IsNullOrEmpty())
{ {
@ -137,7 +137,7 @@ namespace ApiLol.Controllers
if (name != skin.Name) if (name != skin.Name)
{ {
var dtos2 = (await _manager.SkinsMgr.GetItemByName(skin.Name, 0, await _manager.SkinsMgr.GetNbItems())); var dtos2 = (await _manager.SkinsMgr.GetItemByName(skin.Name, 0, await _manager.SkinsMgr.GetNbItems()));
if (dtos2.IsNullOrEmpty() || dtos2.Count() > 0) if (!dtos2.IsNullOrEmpty() || dtos2.Count() > 0)
{ {
return BadRequest($"New Name {skin.Name} is already exist"); return BadRequest($"New Name {skin.Name} is already exist");
} }
@ -183,8 +183,9 @@ namespace ApiLol.Controllers
[HttpGet("/countSkins")] [HttpGet("/countSkins")]
public async Task<ActionResult<int>> GetCountSkins() public async Task<ActionResult> GetCountSkins()
{ {
_logger.LogInformation("method {Action} - SKIN call", nameof(GetCountSkins));
try try
{ {
return Ok(await _manager.SkinsMgr.GetNbItems()); return Ok(await _manager.SkinsMgr.GetNbItems());
@ -207,9 +208,10 @@ namespace ApiLol.Controllers
if (dtos.IsNullOrEmpty()) if (dtos.IsNullOrEmpty())
{ {
_logger.LogWarning("{name} was not found", name); _logger.LogWarning("{name} was not found", name);
return BadRequest(); return NotFound($"{name} was not found");
} }
return Ok(await _manager.SkinsMgr.DeleteItem(dtos.First())); await _manager.SkinsMgr.DeleteItem(dtos.First());
return NoContent();
} }
catch (Exception error) catch (Exception error)
{ {

@ -1,4 +1,4 @@
using ApiLol.Mapper; using ApiMapping;
using DTO; using DTO;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -61,9 +61,9 @@ namespace ApiLol.Controllers.v1
{ {
_logger.LogInformation("method {Action} - CHAMPION - V1.0 call with {name} and {item}", nameof(Put), name, champion); _logger.LogInformation("method {Action} - CHAMPION - V1.0 call with {name} and {item}", nameof(Put), name, champion);
var dtos = (await _manager.ChampionsMgr.GetItemByName(name, 0, await _manager.ChampionsMgr.GetNbItems())); var champs = (await _manager.ChampionsMgr.GetItemByName(name, 0, await _manager.ChampionsMgr.GetNbItems()));
return Ok((await _manager.ChampionsMgr.UpdateItem(dtos.First(), champion.ToModel())).ToDto()); return Ok((await _manager.ChampionsMgr.UpdateItem(champs.First(), champion.ToModel())).ToDto());
} }
@ -87,9 +87,10 @@ namespace ApiLol.Controllers.v1
{ {
_logger.LogInformation("method {Action} - CHAMPION - V1.0 call with {name}", nameof(Delete), name); _logger.LogInformation("method {Action} - CHAMPION - V1.0 call with {name}", nameof(Delete), name);
var dtos = (await _manager.ChampionsMgr.GetItemByName(name, 0, await _manager.ChampionsMgr.GetNbItems())); var champs = (await _manager.ChampionsMgr.GetItemByName(name, 0, await _manager.ChampionsMgr.GetNbItems()));
return Ok(await _manager.ChampionsMgr.DeleteItem(dtos.First())); await _manager.ChampionsMgr.DeleteItem(champs.First());
return NoContent();
} }
} }

@ -1,5 +1,4 @@
using ApiLol.Mapper; using ApiMapping;
using Azure.Core;
using DTO; using DTO;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -41,7 +40,7 @@ namespace ApiLol.Controllers.v2
return BadRequest($"Champion limit exceed, max {nbTotal}"); return BadRequest($"Champion limit exceed, max {nbTotal}");
} }
IEnumerable<ChampionDto> dtos = (await _manager.ChampionsMgr.GetItems(pageRequest.index, pageRequest.count)) IEnumerable<ChampionDto> dtos = (await _manager.ChampionsMgr.GetItems(pageRequest.index, pageRequest.count, pageRequest.orderingPropertyName, pageRequest.descending))
.Select(x => x.ToDto()); .Select(x => x.ToDto());
return Ok(dtos); return Ok(dtos);
} }
@ -81,7 +80,7 @@ namespace ApiLol.Controllers.v2
dtos = (await _manager.ChampionsMgr.GetItemsByName(pageRequest.name, pageRequest.index, pageRequest.count, pageRequest.orderingPropertyName, pageRequest.descending)) dtos = (await _manager.ChampionsMgr.GetItemsByName(pageRequest.name, pageRequest.index, pageRequest.count, pageRequest.orderingPropertyName, pageRequest.descending))
.Select(x => x.ToDto()); .Select(x => x.ToDto());
} }
return Ok(new PageResponse<ChampionDto>{ Data = dtos, index = pageRequest.index, count = pageRequest.count, total = nbTotal }); return Ok(new PageResponse<ChampionDto> { Data = dtos, index = pageRequest.index, count = pageRequest.count, total = nbTotal });
} }
catch (Exception error) catch (Exception error)
{ {
@ -151,7 +150,7 @@ namespace ApiLol.Controllers.v2
if (name != champion.Name) if (name != champion.Name)
{ {
var dtos2 = (await _manager.ChampionsMgr.GetItemByName(champion.Name, 0, await _manager.ChampionsMgr.GetNbItems())); var dtos2 = (await _manager.ChampionsMgr.GetItemByName(champion.Name, 0, await _manager.ChampionsMgr.GetNbItems()));
if (dtos2.IsNullOrEmpty() || dtos2.Count() > 0) if (!dtos2.IsNullOrEmpty() || dtos2.Count() > 0)
{ {
return BadRequest($"New Name {champion.Name} is already exist"); return BadRequest($"New Name {champion.Name} is already exist");
} }
@ -204,8 +203,9 @@ namespace ApiLol.Controllers.v2
} }
[HttpGet("/countChampions")] [HttpGet("/countChampions")]
public async Task<ActionResult<int>> GetCountChampions() public async Task<ActionResult> GetCountChampions()
{ {
_logger.LogInformation("method {Action} - CHAMPION - V2.0 call", nameof(GetCountChampions));
try try
{ {
return Ok(await _manager.ChampionsMgr.GetNbItems()); return Ok(await _manager.ChampionsMgr.GetNbItems());
@ -228,9 +228,10 @@ namespace ApiLol.Controllers.v2
if (dtos.IsNullOrEmpty()) if (dtos.IsNullOrEmpty())
{ {
_logger.LogWarning("{name} was not found", name); _logger.LogWarning("{name} was not found", name);
return BadRequest(); return NotFound($"{name} was not found");
} }
return Ok(await _manager.ChampionsMgr.DeleteItem(dtos.First())); await _manager.ChampionsMgr.DeleteItem(dtos.First());
return NoContent();
} }
catch (Exception error) catch (Exception error)
{ {

@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.OpenApi.Models;
using Model; using Model;
using StubLib;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -10,7 +10,11 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API v1", Version = "v1" });
options.SwaggerDoc("v2", new OpenApiInfo { Title = "My API v2", Version = "v2" });
});
builder.Services.AddApiVersioning(opt => builder.Services.AddApiVersioning(opt =>
@ -29,7 +33,7 @@ builder.Services.AddVersionedApiExplorer(setup =>
setup.SubstituteApiVersionInUrl = true; setup.SubstituteApiVersionInUrl = true;
}); });
builder.Services.AddSingleton<IDataManager, StubData>(); builder.Services.AddSingleton<IDataManager, DbLib.DbManager>();
var app = builder.Build(); var app = builder.Build();

@ -1,15 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ApiLol\ApiLol.csproj" />
<ProjectReference Include="..\DTO\DTO.csproj" /> <ProjectReference Include="..\DTO\DTO.csproj" />
<ProjectReference Include="..\Model\Model.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -1,7 +1,9 @@
using DTO; using ApiMapping;
using ApiMapping.enums;
using DTO;
using Model; using Model;
namespace ApiLol.Mapper namespace ApiMapping
{ {
public static class ChampionMapper public static class ChampionMapper
{ {
@ -14,7 +16,9 @@ namespace ApiLol.Mapper
Icon = champion.Icon, Icon = champion.Icon,
Image = champion.Image.ToDto(), Image = champion.Image.ToDto(),
Skins = champion.Skins.Select(e => e.ToDto()), Skins = champion.Skins.Select(e => e.ToDto()),
Skills = champion.Skills.Select(e => e.ToDto()) Skills = champion.Skills.Select(e => e.ToDto()),
Characteristics = champion.Characteristics.ToDictionary(c => c.Key, c => c.Value)
}; };
@ -25,6 +29,12 @@ namespace ApiLol.Mapper
{ {
champ.AddSkin(skin.ToModel(champ)); champ.AddSkin(skin.ToModel(champ));
} }
foreach (var skill in championDto.Skills)
{
champ.AddSkill(skill.ToModel());
}
if (championDto.Characteristics != null)
champ.AddCharacteristics(championDto.Characteristics.Select(c => Tuple.Create(c.Key, c.Value)).ToArray());
return champ; return champ;
} }

@ -1,7 +1,7 @@
using DTO; using DTO;
using Model; using Model;
namespace ApiLol.Mapper namespace ApiMapping
{ {
public static class LargeImageMapper public static class LargeImageMapper
{ {

@ -1,8 +1,9 @@
using ApiLol.Mapper.enums; using ApiMapping;
using ApiMapping.enums;
using DTO; using DTO;
using Model; using Model;
namespace ApiLol.Mapper namespace ApiMapping
{ {
public static class RuneMapper public static class RuneMapper
{ {

@ -0,0 +1,40 @@
using DTO;
using Model;
using static Model.RunePage;
namespace ApiMapping
{
public static class RunePageMapper
{
public static RunePageDto ToDto(this RunePage runePage)
{
return new RunePageDto()
{
Name = runePage.Name,
Runes = runePage.Runes.ToDictionary(c => c.Key.ToString(), r => r.Value.ToDto())
};
}
public static RunePage ToModel(this RunePageDto runePageDto)
{
Category category;
Dictionary<Category, Rune> runDico = runePageDto.Runes.ToDictionary(
r => (RunePage.Category)Enum.Parse(typeof(RunePage.Category), r.Key),
r => r.Value.ToModel()
);
var runePage = new RunePage(runePageDto.Name);
foreach (var rune in runePageDto.Runes)
{
if (!Enum.TryParse<Category>(rune.Key, true, out category))
{
continue;
}
runePage[category] = rune.Value.ToModel();
}
return runePage;
}
}
}

@ -1,7 +1,9 @@
using DTO; using ApiMapping;
using ApiMapping.enums;
using DTO;
using Model; using Model;
namespace ApiLol.Mapper namespace ApiMapping
{ {
public static class SkillMapper public static class SkillMapper
{ {

@ -1,7 +1,8 @@
using DTO; using ApiMapping;
using DTO;
using Model; using Model;
namespace ApiLol.Mapper namespace ApiMapping
{ {
public static class SkinMapper public static class SkinMapper
{ {

@ -0,0 +1,50 @@
using DTO;
using Model;
namespace ApiMapping.enums
{
public static class CategoryMapper
{
public static RunePageDto.CategoryDto ToDto(this RunePage.Category category)
{
switch (category)
{
case RunePage.Category.Major:
return RunePageDto.CategoryDto.Major;
case RunePage.Category.Minor1:
return RunePageDto.CategoryDto.Minor1;
case RunePage.Category.Minor2:
return RunePageDto.CategoryDto.Minor2;
case RunePage.Category.Minor3:
return RunePageDto.CategoryDto.Minor3;
case RunePage.Category.OtherMinor1:
return RunePageDto.CategoryDto.OtherMinor1;
case RunePage.Category.OtherMinor2:
return RunePageDto.CategoryDto.OtherMinor2;
default:
return RunePageDto.CategoryDto.Major;
}
}
public static RunePage.Category ToModel(this RunePageDto.CategoryDto category)
{
switch (category)
{
case RunePageDto.CategoryDto.Major:
return RunePage.Category.Major;
case RunePageDto.CategoryDto.Minor1:
return RunePage.Category.Minor1;
case RunePageDto.CategoryDto.Minor2:
return RunePage.Category.Minor2;
case RunePageDto.CategoryDto.Minor3:
return RunePage.Category.Minor3;
case RunePageDto.CategoryDto.OtherMinor1:
return RunePage.Category.OtherMinor1;
case RunePageDto.CategoryDto.OtherMinor2:
return RunePage.Category.OtherMinor2;
default:
return RunePage.Category.Major;
}
}
}
}

@ -1,7 +1,7 @@
using DTO; using DTO;
using Model; using Model;
namespace ApiLol.Mapper namespace ApiMapping.enums
{ {
public static class ChampionClassMapper public static class ChampionClassMapper
{ {

@ -2,7 +2,7 @@
using DTO.enums; using DTO.enums;
using Model; using Model;
namespace ApiLol.Mapper.enums namespace ApiMapping.enums
{ {
public static class RuneFamilyMapper public static class RuneFamilyMapper
{ {

@ -1,7 +1,7 @@
using DTO; using DTO;
using Model; using Model;
namespace ApiLol.Mapper namespace ApiMapping.enums
{ {
public static class SkillTypeMapper public static class SkillTypeMapper
{ {

@ -0,0 +1,184 @@
using ApiMapping;
using DTO;
using Model;
using System.Net.Http.Json;
namespace ApiManager
{
public partial class ApiManagerData
{
public class ChampionsManager : HttpClientManager, IChampionsManager
{
private const string UrlApiChampions = "/api/v2/champions";
public ChampionsManager(HttpClient httpClient) : base(httpClient) { }
public async Task<Champion?> AddItem(Champion? item)
{
try
{
var resp = await _httpClient.PostAsJsonAsync($"{UrlApiChampions}", item.ToDto());
if (resp.IsSuccessStatusCode)
{
var createdItem = await resp.Content.ReadFromJsonAsync<ChampionDto>();
return createdItem?.ToModel();
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error adding champion: {ex.Message}");
return null;
}
}
public async Task<bool> DeleteItem(Champion? item)
{
try
{
var resp = await _httpClient.DeleteAsync($"{UrlApiChampions}/{item?.Name}");
return resp.IsSuccessStatusCode;
}
catch (Exception ex)
{
Console.WriteLine($"Error deleting champion: {ex.Message}");
return false;
}
}
private Func<Champion, string, bool> filterByNameContains = (champ, substring) => champ.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
private Func<Champion, string, bool> filterByName = (champ, substring) => champ.Name.Equals(substring, StringComparison.InvariantCultureIgnoreCase);
public async Task<IEnumerable<Champion?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return response.Select(c => c.ToModel()).GetItemsWithFilterAndOrdering(champ => filterByName(champ, substring), index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<Champion?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var url = $"{UrlApiChampions}?index={index}&count={count}&orderingPropertyName={orderingPropertyName}&descending={descending}";
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(url);
return response.Select(c => c.ToModel());
}
private Func<Champion, string, bool> filterByCharacteristic = (champ, charName) => champ.Characteristics.Keys.Any(k => k.Contains(charName, StringComparison.InvariantCultureIgnoreCase));
public async Task<IEnumerable<Champion?>> GetItemsByCharacteristic(string charName, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return response.Select(c => c.ToModel()).GetItemsWithFilterAndOrdering(
champ => filterByCharacteristic(champ, charName),
index, count, orderingPropertyName, descending);
}
private Func<Champion, ChampionClass, bool> filterByClass = (champ, championClass) => champ.Class == championClass;
public async Task<IEnumerable<Champion?>> GetItemsByClass(ChampionClass championClass, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return response.Select(c => c.ToModel()).GetItemsWithFilterAndOrdering(
champ => filterByClass(champ, championClass),
index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<Champion?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return response.Select(c => c.ToModel()).GetItemsWithFilterAndOrdering(champ => filterByNameContains(champ, substring), index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<Champion?>> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
}
private Func<Champion, Skill?, bool> filterBySkill = (champ, skill) => skill != null && champ.Skills.Contains(skill!);
private static Func<Champion, string, bool> filterBySkillSubstring = (champ, skill) => champ.Skills.Any(s => s.Name.Contains(skill, StringComparison.InvariantCultureIgnoreCase));
public async Task<IEnumerable<Champion?>> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return response.Select(c => c.ToModel()).GetItemsWithFilterAndOrdering(champ => filterBySkill(champ, skill), index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<Champion?>> GetItemsBySkill(string skillSubstring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return response.Select(c => c.ToModel()).GetItemsWithFilterAndOrdering(champ => filterBySkillSubstring(champ, skillSubstring), index, count, orderingPropertyName, descending);
}
public async Task<int> GetNbItems()
{
var response = await _httpClient.GetAsync("/countChampions");
var content = await response.Content.ReadAsStringAsync();
return int.Parse(content);
}
public async Task<int> GetNbItemsByCharacteristic(string charName)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return await response.GetNbItemsWithFilter(champ => filterByCharacteristic(champ.ToModel(), charName));
}
public async Task<int> GetNbItemsByClass(ChampionClass championClass)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return response.Where(c => c.Class.Equals(championClass))
.Count();
}
public async Task<int> GetNbItemsByName(string substring)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return response.Where(c => c.Name.Equals(substring))
.Count();
}
public Task<int> GetNbItemsByRunePage(RunePage? runePage)
{
throw new NotImplementedException();
}
public async Task<int> GetNbItemsBySkill(Skill? skill)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return await response.GetNbItemsWithFilter(champ => filterBySkill(champ.ToModel(), skill));
}
public async Task<int> GetNbItemsBySkill(string skill)
{
var response = await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(UrlApiChampions);
return await response.GetNbItemsWithFilter(champ => filterBySkillSubstring(champ.ToModel(), skill));
}
public async Task<Champion?> UpdateItem(Champion? oldItem, Champion? newItem)
{
try
{
var resp = await _httpClient.PutAsJsonAsync($"{UrlApiChampions}/{oldItem?.Name}", newItem.ToDto());
if (resp.IsSuccessStatusCode)
{
var updatedItem = await resp.Content.ReadFromJsonAsync<ChampionDto>();
return updatedItem?.ToModel();
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error updating champion: {ex.Message}");
return null;
}
}
}
}
}

@ -0,0 +1,145 @@
using DTO;
using Model;
using System.Net.Http.Json;
using ApiMapping;
using System.Data.SqlTypes;
namespace ApiManager
{
public partial class ApiManagerData
{
public class RunePagesManager : HttpClientManager, IRunePagesManager
{
private const string UrlApiRunePages = "/api/RunePages";
public RunePagesManager(HttpClient httpClient) : base(httpClient) { }
public async Task<RunePage?> AddItem(RunePage? item)
{
try
{
var resp = await _httpClient.PostAsJsonAsync($"{UrlApiRunePages}", item.ToDto());
if (resp.IsSuccessStatusCode)
{
var createdItem = await resp.Content.ReadFromJsonAsync<RunePageDto>();
return createdItem?.ToModel();
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error adding runePage: {ex.Message}");
return null;
}
}
public async Task<bool> DeleteItem(RunePage? item)
{
try
{
var resp = await _httpClient.DeleteAsync($"{UrlApiRunePages}/{item?.Name}");
return resp.IsSuccessStatusCode;
}
catch (Exception ex)
{
Console.WriteLine($"Error deleting runePage: {ex.Message}");
return false;
}
}
private static Func<RunePage, string, bool> filterByName
= (rp, substring) => rp.Name.Equals(substring, StringComparison.InvariantCultureIgnoreCase);
private static Func<RunePage, string, bool> filterByNameContains
= (rp, substring) => rp.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
private static Func<RunePage, Rune?, bool> filterByRune
= (rp, rune) => rune != null && rp.Runes.Values.Contains(rune!);
public async Task<IEnumerable<RunePage?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var runePages = await _httpClient.GetFromJsonAsync<PageResponse<RunePageDto>>(UrlApiRunePages);
return runePages.Data.Select(r => r.ToModel()).GetItemsWithFilterAndOrdering(
rp => filterByName(rp, substring),
index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<RunePage?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var runePages = await _httpClient.GetFromJsonAsync<PageResponse<RunePageDto>>($"{UrlApiRunePages}?&index={index}&count={count}&descending={descending}");
return runePages.Data.Select(c => c.ToModel());
}
public async Task<IEnumerable<RunePage?>> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
}
public async Task<IEnumerable<RunePage?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var runePages = await _httpClient.GetFromJsonAsync<PageResponse<RunePageDto>>(UrlApiRunePages);
return runePages.Data.Select(r => r.ToModel()).GetItemsWithFilterAndOrdering(
rp => filterByNameContains(rp, substring),
index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<RunePage?>> GetItemsByRune(Rune? rune, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var runePages = await _httpClient.GetFromJsonAsync<PageResponse<RunePageDto>>(UrlApiRunePages);
return runePages.Data.Select(r => r.ToModel()).GetItemsWithFilterAndOrdering(
rp => filterByRune(rp, rune),
index, count, orderingPropertyName, descending);
}
public async Task<int> GetNbItems()
{
var response = await _httpClient.GetAsync("/countRunePages");
var content = await response.Content.ReadAsStringAsync();
return int.Parse(content);
}
public Task<int> GetNbItemsByChampion(Champion? champion)
{
throw new NotImplementedException();
}
public async Task<int> GetNbItemsByName(string substring)
{
var runePages = await _httpClient.GetFromJsonAsync<PageResponse<RunePageDto>>(UrlApiRunePages);
return await runePages.Data.Select(r => r.ToModel()).GetNbItemsWithFilter(
rp => filterByName(rp, substring));
}
public async Task<int> GetNbItemsByRune(Rune? rune)
{
var runePages = await _httpClient.GetFromJsonAsync<PageResponse<RunePageDto>>(UrlApiRunePages);
return await runePages.Data.Select(r => r.ToModel()).GetNbItemsWithFilter(
rp => filterByRune(rp, rune));
}
public async Task<RunePage?> UpdateItem(RunePage? oldItem, RunePage? newItem)
{
try
{
var resp = await _httpClient.PutAsJsonAsync($"{UrlApiRunePages}/{oldItem?.Name}", newItem.ToDto());
if (resp.IsSuccessStatusCode)
{
var updatedItem = await resp.Content.ReadFromJsonAsync<RunePageDto>();
return updatedItem?.ToModel();
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error updating runePage: {ex.Message}");
return null;
}
}
}
}
}

@ -0,0 +1,138 @@
using DTO;
using Model;
using System.Net.Http.Json;
using ApiMapping;
using System;
using System.Data.SqlTypes;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace ApiManager
{
public partial class ApiManagerData
{
public class RunesManager : HttpClientManager, IRunesManager
{
private const string UrlApiRunes = "/api/runes";
public RunesManager(HttpClient httpClient) : base(httpClient) { }
public async Task<Rune?> AddItem(Rune? item)
{
try
{
var resp = await _httpClient.PostAsJsonAsync($"{UrlApiRunes}", item.ToDto());
if (resp.IsSuccessStatusCode)
{
var createdItem = await resp.Content.ReadFromJsonAsync<RuneDto>();
return createdItem?.ToModel();
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error adding rune: {ex.Message}");
return null;
}
}
public async Task<bool> DeleteItem(Rune? item)
{
try
{
var resp = await _httpClient.DeleteAsync($"{UrlApiRunes}/{item?.Name}");
return resp.IsSuccessStatusCode;
}
catch (Exception ex)
{
Console.WriteLine($"Error deleting rune: {ex.Message}");
return false;
}
}
private static Func<Rune, RuneFamily, bool> filterByRuneFamily
= (rune, family) => rune.Family == family;
private static Func<Rune, string, bool> filterByName
= (rune, substring) => rune.Name.Equals(substring, StringComparison.InvariantCultureIgnoreCase);
private static Func<Rune, string, bool> filterByNameContains
= (rune, substring) => rune.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
public async Task<IEnumerable<Rune?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var runes = await _httpClient.GetFromJsonAsync<PageResponse<RuneDto>>(UrlApiRunes);
return runes.Data.Select(r => r.ToModel()).GetItemsWithFilterAndOrdering(
rune => filterByName(rune, substring),
index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<Rune?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var runes = await _httpClient.GetFromJsonAsync<PageResponse<RuneDto>>($"{UrlApiRunes}?&index={index}&count={count}&descending={descending}");
return runes.Data.Select(c => c.ToModel());
}
public async Task<IEnumerable<Rune?>> GetItemsByFamily(RuneFamily family, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var runes = await _httpClient.GetFromJsonAsync<PageResponse<RuneDto>>(UrlApiRunes);
return runes.Data.Select(r => r.ToModel()).GetItemsWithFilterAndOrdering(
rune => filterByRuneFamily(rune, family),
index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<Rune?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var runes = await _httpClient.GetFromJsonAsync<PageResponse<RuneDto>>(UrlApiRunes);
return runes.Data.Select(r => r.ToModel()).GetItemsWithFilterAndOrdering(
rune => filterByNameContains(rune, substring),
index, count, orderingPropertyName, descending);
}
public async Task<int> GetNbItems()
{
var response = await _httpClient.GetAsync("/countRunes");
var content = await response.Content.ReadAsStringAsync();
return int.Parse(content);
}
public async Task<int> GetNbItemsByFamily(RuneFamily family)
{
var runes = await _httpClient.GetFromJsonAsync<PageResponse<RuneDto>>(UrlApiRunes);
return await runes.Data.Select(r => r.ToModel()).GetNbItemsWithFilter(
rune => filterByRuneFamily(rune, family));
}
public async Task<int> GetNbItemsByName(string substring)
{
var runes = await _httpClient.GetFromJsonAsync<PageResponse<RuneDto>>(UrlApiRunes);
return await runes.Data.Select(r => r.ToModel()).GetNbItemsWithFilter(
rune => filterByName(rune, substring));
}
public async Task<Rune?> UpdateItem(Rune? oldItem, Rune? newItem)
{
try
{
var resp = await _httpClient.PutAsJsonAsync($"{UrlApiRunes}/{oldItem?.Name}", newItem.ToDto());
if (resp.IsSuccessStatusCode)
{
var updatedItem = await resp.Content.ReadFromJsonAsync<RuneDto>();
return updatedItem?.ToModel();
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error updating rune: {ex.Message}");
return null;
}
}
}
}
}

@ -0,0 +1,178 @@
using DTO;
using Model;
using System.Net.Http.Json;
using ApiMapping;
using System.Data.SqlTypes;
namespace ApiManager
{
public partial class ApiManagerData
{
public class SkinsManager : HttpClientManager, ISkinsManager
{
private const string UrlApiSkins = "/api/Skins";
public SkinsManager(HttpClient httpClient) : base(httpClient) { }
public async Task<Skin?> AddItem(Skin? item)
{
try
{
var resp = await _httpClient.PostAsJsonAsync($"{UrlApiSkins}", item.ToDtoC());
if (resp.IsSuccessStatusCode)
{
var createdItem = await resp.Content.ReadFromJsonAsync<SkinDtoC>();
var championManager = new ChampionsManager(_httpClient);
var champ = await championManager.GetItemByName(createdItem.ChampionName, 0, 1);
return createdItem?.ToModelC(champ.First());
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error adding skin: {ex.Message}");
return null;
}
}
public async Task<bool> DeleteItem(Skin? item)
{
try
{
var resp = await _httpClient.DeleteAsync($"{UrlApiSkins}/{item?.Name}");
return resp.IsSuccessStatusCode;
}
catch (Exception ex)
{
Console.WriteLine($"Error deleting skin: {ex.Message}");
return false;
}
}
public async Task<IEnumerable<Skin?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var dtoSkins = await _httpClient.GetFromJsonAsync<PageResponse<SkinDtoC>>(UrlApiSkins);
var skins = new List<Skin>();
var championManager = new ChampionsManager(_httpClient);
foreach (var skin in dtoSkins.Data)
{
var champ = await championManager.GetItemByName(skin.ChampionName, 0, 1);
skins.Add(skin.ToModelC(champ.First()));
}
return skins.GetItemsWithFilterAndOrdering(
skin => filterByName(skin, substring),
index, count, orderingPropertyName, descending);
}
public async Task<IEnumerable<Skin?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var dtoSkins = await _httpClient.GetFromJsonAsync<PageResponse<SkinDtoC>>($"{UrlApiSkins}?&index={index}&count={count}&descending={descending}");
var skins = new List<Skin>();
var championManager = new ChampionsManager(_httpClient);
foreach (var skin in dtoSkins.Data)
{
var champ = await championManager.GetItemByName(skin.ChampionName, 0, 1);
skins.Add(skin.ToModelC(champ.First()));
}
return skins;
}
public async Task<IEnumerable<Skin?>> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var dtoSkins = await _httpClient.GetFromJsonAsync<PageResponse<SkinDtoC>>(UrlApiSkins);
var skins = new List<Skin>();
var championManager = new ChampionsManager(_httpClient);
foreach (var skin in dtoSkins.Data)
{
var champ = await championManager.GetItemByName(skin.ChampionName, 0, 1);
skins.Add(skin.ToModelC(champ.First()));
}
return skins.GetItemsWithFilterAndOrdering(
skin => filterByChampion(skin, champion),
index, count, orderingPropertyName, descending);
}
private static Func<Skin, Champion?, bool> filterByChampion = (skin, champion) => champion != null && skin.Champion.Equals(champion!);
private static Func<Skin, string, bool> filterByName = (skin, substring) => skin.Name.Equals(substring, StringComparison.InvariantCultureIgnoreCase);
private static Func<Skin, string, bool> filterByNameContains = (skin, substring) => skin.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
public async Task<IEnumerable<Skin?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
var dtoSkins = await _httpClient.GetFromJsonAsync<PageResponse<SkinDtoC>>(UrlApiSkins);
var skins = new List<Skin>();
var championManager = new ChampionsManager(_httpClient);
foreach (var skin in dtoSkins.Data)
{
var champ = await championManager.GetItemByName(skin.ChampionName,0,1);
skins.Add(skin.ToModelC(champ.First()));
}
return skins.GetItemsWithFilterAndOrdering(
skin => filterByNameContains(skin, substring),
index, count, orderingPropertyName, descending);
}
public async Task<int> GetNbItems()
{
var response = await _httpClient.GetAsync("/countSkins");
var content = await response.Content.ReadAsStringAsync();
return int.Parse(content);
}
public async Task<int> GetNbItemsByChampion(Champion? champion)
{
var dtoSkins = await _httpClient.GetFromJsonAsync<PageResponse<SkinDtoC>>(UrlApiSkins);
var skins = new List<Skin>();
var championManager = new ChampionsManager(_httpClient);
foreach (var skin in dtoSkins.Data)
{
var champ = await championManager.GetItemByName(skin.ChampionName, 0, 1);
skins.Add(skin.ToModelC(champ.First()));
}
return await skins.GetNbItemsWithFilter(
skin => filterByChampion(skin, champion));
}
public async Task<int> GetNbItemsByName(string substring)
{
var dtoSkins = await _httpClient.GetFromJsonAsync<PageResponse<SkinDtoC>>(UrlApiSkins);
var skins = new List<Skin>();
var championManager = new ChampionsManager(_httpClient);
foreach (var skin in dtoSkins.Data)
{
var champ = await championManager.GetItemByName(skin.ChampionName, 0, 1);
skins.Add(skin.ToModelC(champ.First()));
}
return await skins.GetNbItemsWithFilter(
skin => filterByName(skin, substring));
}
public async Task<Skin?> UpdateItem(Skin? oldItem, Skin? newItem)
{
try
{
var resp = await _httpClient.PutAsJsonAsync($"{UrlApiSkins}/{oldItem?.Name}", newItem.ToDto());
if (resp.IsSuccessStatusCode)
{
var updatedItem = await resp.Content.ReadFromJsonAsync<SkinDtoC>();
var championManager = new ChampionsManager(_httpClient);
var champ = await championManager.GetItemByName(updatedItem.ChampionName, 0, 1);
return updatedItem?.ToModelC(champ.First());
}
else
{
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error updating skin: {ex.Message}");
return null;
}
}
}
}
}

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ApiMapping\ApiMapping.csproj" />
<ProjectReference Include="..\DTO\DTO.csproj" />
<ProjectReference Include="..\Model\Model.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,24 @@
using Model;
namespace ApiManager
{
public partial class ApiManagerData : IDataManager
{
public ApiManagerData(HttpClient httpClient)
{
ChampionsMgr = new ChampionsManager(httpClient);
SkinsMgr = new SkinsManager(httpClient);
RunesMgr = new RunesManager(httpClient);
RunePagesMgr = new RunePagesManager(httpClient);
}
public IChampionsManager ChampionsMgr { get; set; }
public ISkinsManager SkinsMgr { get; set; }
public IRunesManager RunesMgr { get; set; }
public IRunePagesManager RunePagesMgr { get; set; }
}
}

@ -1,42 +0,0 @@
using DTO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
namespace Client
{
public class ChampionHttpClient
{
private const string UrlApiChampions = "/api/v3/champions";
private readonly HttpClient _httpClient;
public ChampionHttpClient(HttpClient httpClient)
{
_httpClient = httpClient;
httpClient.BaseAddress = new Uri("https://localhost:7252");
}
public async Task<IEnumerable<ChampionDto>> GetChampion(int index, int count)
{
var url = $"{UrlApiChampions}?index={index}&count={count}";
return await _httpClient.GetFromJsonAsync<IEnumerable<ChampionDto>>(url);
}
/* public async void Add(ChampionDto champion)
{
await _httpClient.PostAsJsonAsync<ChampionDto>(ApiChampions, champion);
}*/
/* public async void Delete(ChampionDto champion)
{
await _httpClient.DeleteAsync(champion.Name);
}
public async void Update(ChampionDto champion)
{
await _httpClient.PutAsJsonAsync<ChampionDto>(ApiChampions, champion);
}*/
}
}

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiManager
{
static class Extensions
{
internal static IEnumerable<T?> GetItemsWithFilterAndOrdering<T>(this IEnumerable<T> collection,
Func<T, bool> filter, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
IEnumerable<T> temp = collection;
temp = temp.Where(item => filter(item));
if (orderingPropertyName != null)
{
var prop = typeof(T).GetProperty(orderingPropertyName!);
if (prop != null)
{
temp = descending ? temp.OrderByDescending(item => prop.GetValue(item))
: temp.OrderBy(item => prop.GetValue(item));
}
}
return temp.Skip(index * count).Take(count);
}
internal static Task<int> GetNbItemsWithFilter<T>(this IEnumerable<T> collection, Func<T, bool> filter)
{
return Task.FromResult(collection.Count(item => filter(item)));
}
}
}

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiManager
{
public class HttpClientManager
{
protected readonly HttpClient _httpClient;
public HttpClientManager(HttpClient httpClient)
{
_httpClient = httpClient;
_httpClient.BaseAddress = new Uri("https://localhost:7252");
}
}
}

@ -1,19 +1,18 @@
// See https://aka.ms/new-console-template for more information /*// See https://aka.ms/new-console-template for more information
using Client; using static ApiManager.ApiManagerData;
using DTO;
Console.WriteLine("Hello, World!"); Console.WriteLine("Hello, World!");
var championClient = new ChampionHttpClient(new HttpClient()); var championClient = new ChampionsManager(new HttpClient());
// Get all champions // Get all champions
var champions = await championClient.GetChampion(0,6); var champions = await championClient.GetItems(0,6);
Console.WriteLine("All champions:"); Console.WriteLine("All champions:");
foreach (var champion in champions) foreach (var champion in champions)
{ {
Console.WriteLine($"{champion.Name} ({champion.Bio})"); Console.WriteLine($"{champion.Name} ({champion.Bio})");
} }
/*// Add a new champion *//*// Add a new champion
var newChampion = new ChampionDto { Name = "Akali", Role = "Assassin" }; var newChampion = new ChampionDto { Name = "Akali", Role = "Assassin" };
championClient.Add(newChampion); championClient.Add(newChampion);
@ -34,4 +33,6 @@ if (championToUpdate != null)
Console.WriteLine($"{championToUpdate.Name} updated."); Console.WriteLine($"{championToUpdate.Name} updated.");
} }
*/ *//*
Console.ReadLine();*/

@ -7,8 +7,9 @@
public ChampionClassDto Class { get; set; } public ChampionClassDto Class { get; set; }
public string Icon { get; set; } public string Icon { get; set; }
public LargeImageDto Image { get; set; } public LargeImageDto Image { get; set; }
public IEnumerable<SkinDto> Skins { get; set; } public IEnumerable<SkinDto>? Skins { get; set; }
public IEnumerable<SkillDto> Skills { get; set; } public IEnumerable<SkillDto>? Skills { get; set; }
public Dictionary<string, int>? Characteristics { get; set; }
} }
} }

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DTO
{
public partial class RunePageDto
{
public string Name { get; set; }
public Dictionary<string, RuneDto> Runes { get; set; }
}
}

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DTO
{
public partial class RunePageDto
{
public enum CategoryDto
{
Major,
Minor1,
Minor2,
Minor3,
OtherMinor1,
OtherMinor2
}
}
}

@ -1,6 +1,8 @@
using Model; using DbManager.Mapper;
using Microsoft.EntityFrameworkCore;
using Model;
namespace DbManager namespace DbLib
{ {
public partial class DbManager public partial class DbManager
{ {
@ -11,94 +13,116 @@ namespace DbManager
public ChampionsManager(DbManager parent) public ChampionsManager(DbManager parent)
=> this.parent = parent; => this.parent = parent;
public Task<Champion?> AddItem(Champion? item) public async Task<Champion?> AddItem(Champion? item)
{ {
throw new NotImplementedException(); var champion = await parent.DbContext.Champions.AddAsync(item.ToEntity(parent.DbContext));
parent.DbContext.SaveChanges();
return champion.Entity.ToModel();
} }
public Task<bool> DeleteItem(Champion? item) public async Task<bool> DeleteItem(Champion? item)
{ {
throw new NotImplementedException(); var toDelete = parent.DbContext.Champions.Where(c => c.Name == item.Name).First();
} if (toDelete != null)
public Task<IEnumerable<Champion?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{ {
throw new NotImplementedException(); parent.DbContext.Champions.Remove(toDelete);
parent.DbContext.SaveChanges();
return true;
} }
return false;
public Task<IEnumerable<Champion?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
} }
public Task<IEnumerable<Champion?>> GetItemsByCharacteristic(string charName, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsByClass(ChampionClass championClass, int index, int count, string? orderingPropertyName = null, bool descending = false) private Func<Champion, string, bool> filterByNameContains = (champ, substring) => champ.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) private Func<Champion, string, bool> filterByName = (champ, substring) => champ.Name.Equals(substring, StringComparison.InvariantCultureIgnoreCase);
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null, bool descending = false) public async Task<IEnumerable<Champion?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{ => parent.DbContext.Champions.Include(c => c.Skills).Include(c => c.Characteristics).Include(c => c.Skins).Include(c => c.Image).GetItemsWithFilterAndOrdering(champ => filterByName(champ.ToModel(), substring), index, count, orderingPropertyName, descending)
throw new NotImplementedException(); .Select(c => c.ToModel());
}
public Task<IEnumerable<Champion?>> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsBySkill(string skill, int index, int count, string? orderingPropertyName = null, bool descending = false) public async Task<IEnumerable<Champion?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{ => parent.DbContext.Champions.Include(c => c.Skills).Include(c => c.Characteristics).Include(c => c.Skins).Include(c => c.Image).GetItemsWithFilterAndOrdering(
throw new NotImplementedException(); c => true,
} index, count,
orderingPropertyName, descending).Select(c => c.ToModel());
public Task<int> GetNbItems() private Func<Champion, string, bool> filterByCharacteristic = (champ, charName) => champ.Characteristics.Keys.Any(k => k.Contains(charName, StringComparison.InvariantCultureIgnoreCase));
{
throw new NotImplementedException(); public async Task<IEnumerable<Champion?>> GetItemsByCharacteristic(string charName, int index, int count, string? orderingPropertyName = null, bool descending = false)
} => parent.DbContext.Champions.Include(c => c.Skills).Include(c => c.Characteristics).Include(c => c.Skins).Include(c => c.Image).GetItemsWithFilterAndOrdering(
champ => filterByCharacteristic(champ.ToModel(), charName),
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
private Func<Champion, ChampionClass, bool> filterByClass = (champ, championClass) => champ.Class == championClass;
public async Task<IEnumerable<Champion?>> GetItemsByClass(ChampionClass championClass, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Champions.Include(c => c.Skills).Include(c => c.Characteristics).Include(c => c.Skins).Include(c => c.Image).GetItemsWithFilterAndOrdering(
champ => filterByClass(champ.ToModel(), championClass),
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public async Task<IEnumerable<Champion?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Champions.Include(c => c.Skills).Include(c => c.Characteristics).Include(c => c.Skins).Include(c => c.Image).GetItemsWithFilterAndOrdering(champ => filterByNameContains(champ.ToModel(), substring), index, count, orderingPropertyName, descending)
.Select(c => c.ToModel());
public async Task<IEnumerable<Champion?>> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Champions.Include(c => c.Skills).Include(c => c.Characteristics).Include(c => c.Skins).Include(c => c.Image).GetItemsWithFilterAndOrdering(
c => c.RunePages.Any(rp => rp.Equals(runePage.ToEntity(parent.DbContext))),
index, count,
orderingPropertyName, descending).Select(c => c.ToModel());
public async Task<IEnumerable<Champion?>> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Champions.Include(c => c.Skills).Include(c => c.Characteristics).Include(c => c.Skins).Include(c => c.Image).GetItemsWithFilterAndOrdering(champ => filterBySkill(champ.ToModel(), skill), index, count, orderingPropertyName, descending)
.Select(c => c.ToModel());
public async Task<IEnumerable<Champion?>> GetItemsBySkill(string skill, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Champions.Include(c => c.Skills).Include(c => c.Characteristics).Include(c => c.Skins).Include(c => c.Image).GetItemsWithFilterAndOrdering(champ => filterBySkillSubstring(champ.ToModel(), skill), index, count, orderingPropertyName, descending)
.Select(c => c.ToModel());
public async Task<int> GetNbItems()
=> parent.DbContext.Champions.Count();
public Task<int> GetNbItemsByCharacteristic(string charName) public Task<int> GetNbItemsByCharacteristic(string charName)
{ => parent.DbContext.Champions.GetNbItemsWithFilter(champ => filterByCharacteristic(champ.ToModel(), charName));
throw new NotImplementedException();
}
public Task<int> GetNbItemsByClass(ChampionClass championClass) public async Task<int> GetNbItemsByClass(ChampionClass championClass)
{ => parent.DbContext.Champions.Where(c => c.Class.Equals(championClass))
throw new NotImplementedException(); .Count();
}
public Task<int> GetNbItemsByName(string substring) public async Task<int> GetNbItemsByName(string substring)
{ => parent.DbContext.Champions.Where(c => c.Name.Equals(substring))
throw new NotImplementedException(); .Count();
}
public async Task<int> GetNbItemsByRunePage(RunePage? runePage)
=> parent.DbContext.Champions.Where(c => c.RunePages.Any(rp => rp.Equals(runePage.ToEntity(parent.DbContext))))
.Count();
public Task<int> GetNbItemsByRunePage(RunePage? runePage)
{ private Func<Champion, Skill?, bool> filterBySkill = (champ, skill) => skill != null && champ.Skills.Contains(skill!);
throw new NotImplementedException();
}
public Task<int> GetNbItemsBySkill(Skill? skill) public Task<int> GetNbItemsBySkill(Skill? skill)
{ => parent.DbContext.Champions.GetNbItemsWithFilter(champ => filterBySkill(champ.ToModel(), skill));
throw new NotImplementedException();
}
public Task<int> GetNbItemsBySkill(string skill) private static Func<Champion, string, bool> filterBySkillSubstring = (champ, skill) => champ.Skills.Any(s => s.Name.Contains(skill, StringComparison.InvariantCultureIgnoreCase));
{
throw new NotImplementedException();
}
public Task<Champion?> UpdateItem(Champion? oldItem, Champion? newItem) public Task<int> GetNbItemsBySkill(string skill)
{ => parent.DbContext.Champions.GetNbItemsWithFilter(champ => filterBySkillSubstring(champ.ToModel(), skill));
throw new NotImplementedException();
public async Task<Champion?> UpdateItem(Champion? oldItem, Champion? newItem)
{
var toUpdate = parent.DbContext.Champions.FirstOrDefault(champ => champ.Name == oldItem.Name);
var newEntity = newItem.ToEntity(parent.DbContext);
toUpdate.Bio = newEntity.Bio;
toUpdate.Class = newEntity.Class;
toUpdate.Icon = newEntity.Icon;
toUpdate.Image = newEntity.Image;
toUpdate.Skins = newEntity.Skins;
toUpdate.Skills = newEntity.Skills;
toUpdate.Characteristics = newEntity.Characteristics;
parent.DbContext.SaveChanges();
return toUpdate?.ToModel();
} }
} }
} }

@ -1,11 +1,8 @@
using Model; using DbManager.Mapper;
using System; using Microsoft.EntityFrameworkCore;
using System.Collections.Generic; using Model;
using System.Linq;
using System.Text; namespace DbLib
using System.Threading.Tasks;
namespace DbManager
{ {
public partial class DbManager public partial class DbManager
{ {
@ -16,64 +13,83 @@ namespace DbManager
public RunePagesManager(DbManager parent) public RunePagesManager(DbManager parent)
=> this.parent = parent; => this.parent = parent;
public Task<RunePage?> AddItem(RunePage? item) public async Task<RunePage?> AddItem(RunePage? item)
{ {
throw new NotImplementedException(); var RunePage = await parent.DbContext.RunePages.AddAsync(item.ToEntity(parent.DbContext));
parent.DbContext.SaveChanges();
return RunePage.Entity.ToModel(parent.DbContext);
} }
public Task<bool> DeleteItem(RunePage? item) public async Task<bool> DeleteItem(RunePage? item)
{ {
throw new NotImplementedException(); var toDelete = parent.DbContext.RunePages.Find(item.Name);
} if (toDelete != null)
public Task<IEnumerable<RunePage?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{ {
throw new NotImplementedException(); parent.DbContext.RunePages.Remove(toDelete);
parent.DbContext.SaveChanges();
return true;
} }
return false;
public Task<IEnumerable<RunePage?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
} }
public Task<IEnumerable<RunePage?>> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false) private static Func<RunePage, string, bool> filterByName
{ = (rp, substring) => rp.Name.Equals(substring, StringComparison.InvariantCultureIgnoreCase);
throw new NotImplementedException();
}
public Task<IEnumerable<RunePage?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) private static Func<RunePage, string, bool> filterByNameContains
{ = (rp, substring) => rp.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
throw new NotImplementedException();
}
public Task<IEnumerable<RunePage?>> GetItemsByRune(Model.Rune? rune, int index, int count, string? orderingPropertyName = null, bool descending = false) private static Func<RunePage, Rune?, bool> filterByRune
= (rp, rune) => rune != null && rp.Runes.Values.Contains(rune!);
public async Task<IEnumerable<RunePage?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.RunePages.Include(rp => rp.Champions).Include(rp => rp.DictionaryCategoryRunes).GetItemsWithFilterAndOrdering(
rp => filterByName(rp.ToModel(parent.DbContext), substring),
index, count, orderingPropertyName, descending).Select(c => c.ToModel(parent.DbContext));
public async Task<IEnumerable<RunePage?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{ {
throw new NotImplementedException(); parent.DbContext.Runes.Include(r => r.Image);
return parent.DbContext.RunePages.Include(rp => rp.Champions).Include(rp => rp.DictionaryCategoryRunes).Include(rp => rp.DictionaryCategoryRunes).GetItemsWithFilterAndOrdering(
rp => true,
index, count, orderingPropertyName, descending).Select(c => c.ToModel(parent.DbContext));
} }
public async Task<IEnumerable<RunePage?>> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.RunePages.Include(rp => rp.Champions).Include(rp => rp.DictionaryCategoryRunes).GetItemsWithFilterAndOrdering(
rp => rp.Champions.Any(c => c.Name.Equals(champion.Name)),
index, count,
orderingPropertyName, descending).Select(rp => rp.ToModel(parent.DbContext));
public async Task<IEnumerable<RunePage?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.RunePages.Include(rp => rp.Champions).Include(rp => rp.DictionaryCategoryRunes).GetItemsWithFilterAndOrdering(
rp => filterByNameContains(rp.ToModel(parent.DbContext), substring),
index, count, orderingPropertyName, descending).Select(c => c.ToModel(parent.DbContext));
public async Task<IEnumerable<RunePage?>> GetItemsByRune(Rune? rune, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.RunePages.Include(rp => rp.Champions).Include(rp => rp.DictionaryCategoryRunes).GetItemsWithFilterAndOrdering(
rp => filterByRune(rp.ToModel(parent.DbContext), rune),
index, count, orderingPropertyName, descending).Select(c => c.ToModel(parent.DbContext));
public Task<int> GetNbItems() public Task<int> GetNbItems()
{ => parent.DbContext.RunePages.GetNbItemsWithFilter(
throw new NotImplementedException(); rp => true);
}
public Task<int> GetNbItemsByChampion(Champion? champion) public async Task<int> GetNbItemsByChampion(Champion? champion)
{ => parent.DbContext.RunePages.Where(rp => rp.Champions.Any(c => c.Name.Equals(champion.Name))).Count();
throw new NotImplementedException();
}
public Task<int> GetNbItemsByName(string substring)
{
throw new NotImplementedException();
}
public Task<int> GetNbItemsByRune(Model.Rune? rune) public async Task<int> GetNbItemsByName(string substring)
{ => parent.DbContext.RunePages.Where(rp => rp.Name.Contains(substring)).Count();
throw new NotImplementedException();
} public async Task<int> GetNbItemsByRune(Rune? rune)
=> parent.DbContext.RunePages.Where(rp => rp.DictionaryCategoryRunes.Any(r => r.RuneName.Equals(rune.Name))).Count();
public Task<RunePage?> UpdateItem(RunePage? oldItem, RunePage? newItem) public async Task<RunePage?> UpdateItem(RunePage? oldItem, RunePage? newItem)
{ {
throw new NotImplementedException(); var toUpdate = parent.DbContext.RunePages.Find(oldItem.Name);
toUpdate.DictionaryCategoryRunes = newItem.ToEntity(parent.DbContext).DictionaryCategoryRunes;
parent.DbContext.SaveChanges();
return toUpdate.ToModel(parent.DbContext);
} }
} }
} }

@ -1,11 +1,8 @@
using Model; using DbManager.Mapper;
using System; using Microsoft.EntityFrameworkCore;
using System.Collections.Generic; using Model;
using System.Linq;
using System.Text; namespace DbLib
using System.Threading.Tasks;
namespace DbManager
{ {
public partial class DbManager public partial class DbManager
{ {
@ -15,54 +12,77 @@ namespace DbManager
public RunesManager(DbManager parent) public RunesManager(DbManager parent)
=> this.parent = parent; => this.parent = parent;
public Task<Model.Rune?> AddItem(Model.Rune? item) public async Task<Rune?> AddItem(Rune? item)
{ {
throw new NotImplementedException(); var rune = await parent.DbContext.Runes.AddAsync(item.ToEntity());
parent.DbContext.SaveChanges();
return rune.Entity.ToModel();
} }
public Task<bool> DeleteItem(Model.Rune? item) public async Task<bool> DeleteItem(Rune? item)
{ {
throw new NotImplementedException(); var toDelete = parent.DbContext.Runes.Find(item.Name);
} if (toDelete != null)
public Task<IEnumerable<Model.Rune?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{ {
throw new NotImplementedException(); parent.DbContext.Runes.Remove(toDelete);
parent.DbContext.SaveChanges();
return true;
} }
return false;
public Task<IEnumerable<Model.Rune?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
} }
public Task<IEnumerable<Model.Rune?>> GetItemsByFamily(RuneFamily family, int index, int count, string? orderingPropertyName = null, bool descending = false) private static Func<Rune, RuneFamily, bool> filterByRuneFamily
{ = (rune, family) => rune.Family == family;
throw new NotImplementedException();
}
public Task<IEnumerable<Model.Rune?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) private static Func<Rune, string, bool> filterByName
{ = (rune, substring) => rune.Name.Equals(substring, StringComparison.InvariantCultureIgnoreCase);
throw new NotImplementedException();
} private static Func<Rune, string, bool> filterByNameContains
= (rune, substring) => rune.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
public async Task<IEnumerable<Rune?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Runes.Include(r => r.Image).GetItemsWithFilterAndOrdering(
rune => filterByName(rune.ToModel(), substring),
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public async Task<IEnumerable<Rune?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Runes.Include(r => r.Image).GetItemsWithFilterAndOrdering(
r => true,
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public async Task<IEnumerable<Rune?>> GetItemsByFamily(RuneFamily family, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Runes.Include(r => r.Image).GetItemsWithFilterAndOrdering(
rune => filterByRuneFamily(rune.ToModel(), family),
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public async Task<IEnumerable<Rune?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Runes.Include(r => r.Image).GetItemsWithFilterAndOrdering(
rune => filterByNameContains(rune.ToModel(), substring),
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public Task<int> GetNbItems() public Task<int> GetNbItems()
{ => parent.DbContext.Runes.GetNbItemsWithFilter(
throw new NotImplementedException(); rune => true);
}
public Task<int> GetNbItemsByFamily(RuneFamily family) public Task<int> GetNbItemsByFamily(RuneFamily family)
{ => parent.DbContext.Runes.GetNbItemsWithFilter(
throw new NotImplementedException(); rune => filterByRuneFamily(rune.ToModel(), family));
}
public Task<int> GetNbItemsByName(string substring) public Task<int> GetNbItemsByName(string substring)
{ => parent.DbContext.Runes.GetNbItemsWithFilter(
throw new NotImplementedException(); rune => filterByName(rune.ToModel(), substring));
}
public Task<Model.Rune?> UpdateItem(Model.Rune? oldItem, Model.Rune? newItem) public async Task<Rune?> UpdateItem(Rune? oldItem, Rune? newItem)
{ {
throw new NotImplementedException(); var toUpdate = parent.DbContext.Runes.Find(oldItem.Name);
var newEntity = newItem.ToEntity();
toUpdate.Description = newEntity.Description;
toUpdate.Icon = newEntity.Icon;
toUpdate.Family = newEntity.Family;
toUpdate.Image = newEntity.Image;
parent.DbContext.SaveChanges();
return toUpdate.ToModel();
} }
} }

@ -1,11 +1,13 @@
using Model; using DbManager.Mapper;
using Microsoft.EntityFrameworkCore;
using Model;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace DbManager namespace DbLib
{ {
public partial class DbManager public partial class DbManager
{ {
@ -16,54 +18,74 @@ namespace DbManager
public SkinsManager(DbManager parent) public SkinsManager(DbManager parent)
=> this.parent = parent; => this.parent = parent;
public Task<Skin?> AddItem(Skin? item) public async Task<Skin?> AddItem(Skin? item)
{ {
throw new NotImplementedException(); var skin = await parent.DbContext.Skins.AddAsync(item.ToEntity(parent.DbContext));
parent.DbContext.SaveChanges();
return skin.Entity.ToModel();
} }
public Task<bool> DeleteItem(Skin? item) public async Task<bool> DeleteItem(Skin? item)
{ {
throw new NotImplementedException(); var toDelete = parent.DbContext.Skins.Find(item.Name);
} if (toDelete != null)
public Task<IEnumerable<Skin?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{ {
throw new NotImplementedException(); parent.DbContext.Skins.Remove(toDelete);
parent.DbContext.SaveChanges();
return true;
} }
return false;
public Task<IEnumerable<Skin?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
} }
public Task<IEnumerable<Skin?>> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false) private static Func<Skin, Champion?, bool> filterByChampion = (skin, champion) => champion != null && skin.Champion.Equals(champion!);
{
throw new NotImplementedException();
}
public Task<IEnumerable<Skin?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) private static Func<Skin, string, bool> filterByName = (skin, substring) => skin.Name.Equals(substring, StringComparison.InvariantCultureIgnoreCase);
{
throw new NotImplementedException(); private static Func<Skin, string, bool> filterByNameContains = (skin, substring) => skin.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
}
public async Task<IEnumerable<Skin?>> GetItemByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Skins.Include(s => s.Champion).Include(s => s.Image).GetItemsWithFilterAndOrdering(
skin => filterByName(skin.ToModel(), substring),
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public async Task<IEnumerable<Skin?>> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Skins.Include(s => s.Champion).Include(s => s.Image).GetItemsWithFilterAndOrdering(
skin => true,
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public async Task<IEnumerable<Skin?>> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Skins.Include(s => s.Champion).Include(s => s.Image).GetItemsWithFilterAndOrdering(
skin => filterByChampion(skin.ToModel(), champion),
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public async Task<IEnumerable<Skin?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
=> parent.DbContext.Skins.Include(s => s.Champion).Include(s => s.Image).GetItemsWithFilterAndOrdering(
skin => filterByNameContains(skin.ToModel(), substring),
index, count, orderingPropertyName, descending).Select(c => c.ToModel());
public Task<int> GetNbItems() public Task<int> GetNbItems()
{ => parent.DbContext.Skins.GetNbItemsWithFilter(
throw new NotImplementedException(); c => true);
}
public Task<int> GetNbItemsByChampion(Champion? champion) public Task<int> GetNbItemsByChampion(Champion? champion)
{ => parent.DbContext.Skins.GetNbItemsWithFilter(
throw new NotImplementedException(); skin => filterByChampion(skin.ToModel(), champion));
}
public Task<int> GetNbItemsByName(string substring) public Task<int> GetNbItemsByName(string substring)
{ => parent.DbContext.Skins.GetNbItemsWithFilter(
throw new NotImplementedException(); skin => filterByName(skin.ToModel(), substring));
}
public Task<Skin?> UpdateItem(Skin? oldItem, Skin? newItem) public async Task<Skin?> UpdateItem(Skin? oldItem, Skin? newItem)
{ {
throw new NotImplementedException(); var toUpdate = parent.DbContext.Skins.Find(oldItem.Name);
var newEntity = newItem.ToEntity(parent.DbContext);
toUpdate.Description = newEntity.Description;
toUpdate.Icon = newEntity.Icon;
toUpdate.Price = newEntity.Price;
toUpdate.Champion = newEntity.Champion;
toUpdate.Image = newEntity.Image;
parent.DbContext.SaveChanges();
return toUpdate.ToModel();
} }
} }

@ -1,12 +1,21 @@
using Model; using Model;
using MyFlib; using MyFlib;
namespace DbManager namespace DbLib
{ {
public partial class DbManager : IDataManager public partial class DbManager : IDataManager
{ {
protected LolDbContext DbContext { get; set; } protected LolDbContext DbContext { get; set; }
public DbManager()
{
DbContext = new LolDbContext();
ChampionsMgr = new ChampionsManager(this);
SkinsMgr = new SkinsManager(this);
RunesMgr = new RunesManager(this);
RunePagesMgr = new RunePagesManager(this);
}
public DbManager(LolDbContext dbContext) public DbManager(LolDbContext dbContext)
{ {
DbContext = dbContext; DbContext = dbContext;

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DbLib
{
static class Extensions
{
internal static IEnumerable<T?> GetItemsWithFilterAndOrdering<T>(this IEnumerable<T> collection,
Func<T, bool> filter, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
IEnumerable<T> temp = collection;
temp = temp.Where(item => filter(item));
if (orderingPropertyName != null)
{
var prop = typeof(T).GetProperty(orderingPropertyName!);
if (prop != null)
{
temp = descending ? temp.OrderByDescending(item => prop.GetValue(item))
: temp.OrderBy(item => prop.GetValue(item));
}
}
return temp.Skip(index * count).Take(count);
}
internal static Task<int> GetNbItemsWithFilter<T>(this IEnumerable<T> collection, Func<T, bool> filter)
{
return Task.FromResult(collection.Count(item => filter(item)));
}
}
}

@ -8,14 +8,21 @@ namespace DbManager.Mapper
{ {
public static Champion ToModel(this ChampionEntity championEntity) public static Champion ToModel(this ChampionEntity championEntity)
{ {
Champion champion = new (championEntity.Name, championEntity.Class.ToModel(), championEntity.Icon, championEntity.Image.Base64.ToString(), championEntity.Bio); Champion champion = new (championEntity.Name, championEntity.Class.ToModel(), championEntity.Icon, championEntity.Image.Base64, championEntity.Bio);
foreach (var skill in championEntity.Skills) foreach (var skill in championEntity.Skills)
{ {
champion.AddSkill(skill.ToModel()); champion.AddSkill(skill.ToModel());
} }
foreach (var skin in championEntity.Skins) foreach (var skin in championEntity.Skins)
{ {
champion.AddSkin(skin.ToModel()); champion.AddSkin(new Skin(skin.Name, champion, skin.Price, skin.Icon, "", skin.Description));
}
if (championEntity.Characteristics != null)
{
foreach (var c in championEntity.Characteristics)
{
champion.AddCharacteristics(c.ToModel());
}
} }
return champion; return champion;
} }
@ -31,12 +38,13 @@ namespace DbManager.Mapper
}; };
foreach (var skill in champion.Skills) foreach (var skill in champion.Skills)
{ {
champ.Skills.Add(skill.ToEntity(champ)); champ.Skills.Add(skill.ToEntity(champ, context));
} }
foreach (var skin in champion.Skins) foreach (var skin in champion.Skins)
{ {
champ.Skins.Add(skin.ToEntity(context)); champ.Skins.Add(skin.ToEntity(context));
} }
champ.Characteristics = champion.Characteristics.Select(x => x.ToEntity(champ, context)).ToList();
return champ; return champ;
} }
} }

@ -0,0 +1,27 @@
using MyFlib.Entities;
using MyFlib;
namespace DbManager.Mapper
{
public static class CharacteristicMapper
{
public static CharacteristicEntity ToEntity(this KeyValuePair<string, int> item, ChampionEntity champion, LolDbContext context)
{
var characteristicEntity = context.Characteristic.Find(item.Key, champion.Id);
if (characteristicEntity == null)
{
return new()
{
Name = item.Key,
Value = item.Value,
ChampionForeignKey = champion.Id
};
}
return characteristicEntity;
}
public static Tuple<string, int> ToModel(this CharacteristicEntity entity)
=> new(entity.Name, entity.Value);
}
}

@ -6,7 +6,7 @@ namespace DbManager.Mapper
{ {
public static class RuneMapper public static class RuneMapper
{ {
public static Rune ToModel(this RuneEntity rune) => new(rune.Name, rune.Family.ToModel(), rune.Icon, rune.Image.Base64, rune.Description); public static Rune ToModel(this RuneEntity rune) => new(rune.Name, rune.Family.ToModel(), rune.Icon, "", rune.Description);
public static RuneEntity ToEntity(this Rune rune) public static RuneEntity ToEntity(this Rune rune)
=> new() => new()
{ {

@ -1,4 +1,5 @@
using DbManager.Mapper.enums; using DbManager.Mapper.enums;
using Microsoft.EntityFrameworkCore;
using Model; using Model;
using MyFlib; using MyFlib;
using MyFlib.Entities; using MyFlib.Entities;
@ -20,5 +21,29 @@ namespace DbManager.Mapper
} }
return runePage; return runePage;
} }
public static RunePageEntity ToEntity(this RunePage runePage, LolDbContext context)
{
RunePageEntity? runePageEntity = context.RunePages.Find(runePage.Name);
if (runePageEntity == null)
{
runePageEntity = new()
{
Name = runePage.Name,
};
runePageEntity.DictionaryCategoryRunes = new List<DictionaryCategoryRune>();
foreach (var r in runePage.Runes)
{
runePageEntity.DictionaryCategoryRunes.Add(new DictionaryCategoryRune()
{
category = r.Key.ToEntity(),
rune = r.Value.ToEntity(),
});
}
}
return runePageEntity;
}
} }
} }

@ -8,8 +8,10 @@ namespace DbManager.Mapper
{ {
public static Skill ToModel(this SkillEntity skillEntity) => new(skillEntity.Name, skillEntity.Type.ToModel(), skillEntity.Description); public static Skill ToModel(this SkillEntity skillEntity) => new(skillEntity.Name, skillEntity.Type.ToModel(), skillEntity.Description);
public static SkillEntity ToEntity(this Skill skill, ChampionEntity championEntity, LolDbContext context)
public static SkillEntity ToEntity(this Skill skill, ChampionEntity championEntity) {
var skillSearch = context.Skills.Find(skill.Name);
if (skillSearch == null)
{ {
return new() return new()
{ {
@ -19,6 +21,8 @@ namespace DbManager.Mapper
Champion = championEntity Champion = championEntity
}; };
} }
throw new Exception("Skill was already exist");
}
} }
} }

@ -9,14 +9,21 @@ namespace DbManager.Mapper
=> new(skinEntity.Name, skinEntity.Champion.ToModel(), skinEntity.Price, skinEntity.Icon, skinEntity.Image.Base64, skinEntity.Description); => new(skinEntity.Name, skinEntity.Champion.ToModel(), skinEntity.Price, skinEntity.Icon, skinEntity.Image.Base64, skinEntity.Description);
public static SkinEntity ToEntity(this Skin skin, LolDbContext context) public static SkinEntity ToEntity(this Skin skin, LolDbContext context)
=> new() {
var skinSearch = context.Skins.Find(skin.Name);
if(skinSearch == null)
{
return new()
{ {
Name = skin.Name, Name = skin.Name,
Description = skin.Description, Description = skin.Description,
Icon = skin.Icon, Icon = skin.Icon,
Price = skin.Price, Price = skin.Price,
Champion = context.Champions.Find(skin.Champion.Name), Champion = context.Champions.FirstOrDefault(c => c.Name == skin.Champion.Name),
Image = skin.Image.ToEntity() Image = skin.Image.ToEntity()
}; };
} }
throw new Exception("Skin was already exist");
}
}
} }

@ -1,2 +0,0 @@
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

@ -21,13 +21,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DTO", "DTO\DTO.csproj", "{3
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiTests", "Tests\ApiTests\ApiTests.csproj", "{1779D8A4-2E12-47F3-BDA2-2E7F04B758EB}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiTests", "Tests\ApiTests\ApiTests.csproj", "{1779D8A4-2E12-47F3-BDA2-2E7F04B758EB}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{464DAB04-BE65-429D-9A39-3E1BB43C521A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiManager", "Client\ApiManager.csproj", "{464DAB04-BE65-429D-9A39-3E1BB43C521A}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyFlib", "MyFlib\MyFlib.csproj", "{2142AB69-B483-4B0A-96DC-CFA87DEB11A5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyFlib", "MyFlib\MyFlib.csproj", "{2142AB69-B483-4B0A-96DC-CFA87DEB11A5}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UT_EF", "Tests\UT_EF\UT_EF.csproj", "{F896C30B-A6FE-42B2-BAC8-08360BC48DC6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UT_EF", "Tests\UT_EF\UT_EF.csproj", "{F896C30B-A6FE-42B2-BAC8-08360BC48DC6}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbManager", "DbManager\DbManager.csproj", "{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbManager", "DbManager\DbManager.csproj", "{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LolApp", "LolApp\LolApp.csproj", "{0C898A04-092A-49AA-BE65-8AE818A2AF50}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ViewModels", "ViewModels\ViewModels.csproj", "{65135247-E1AB-4EE4-9473-DFDE6AFCC250}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiMapping", "ApiMapping\ApiMapping.csproj", "{F8D44A32-788B-4E63-B379-278B90216E28}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -79,6 +85,20 @@ Global
{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Debug|Any CPU.Build.0 = Debug|Any CPU {71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Release|Any CPU.ActiveCfg = Release|Any CPU {71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Release|Any CPU.Build.0 = Release|Any CPU {71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Release|Any CPU.Build.0 = Release|Any CPU
{0C898A04-092A-49AA-BE65-8AE818A2AF50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C898A04-092A-49AA-BE65-8AE818A2AF50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C898A04-092A-49AA-BE65-8AE818A2AF50}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{0C898A04-092A-49AA-BE65-8AE818A2AF50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C898A04-092A-49AA-BE65-8AE818A2AF50}.Release|Any CPU.Build.0 = Release|Any CPU
{0C898A04-092A-49AA-BE65-8AE818A2AF50}.Release|Any CPU.Deploy.0 = Release|Any CPU
{65135247-E1AB-4EE4-9473-DFDE6AFCC250}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65135247-E1AB-4EE4-9473-DFDE6AFCC250}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65135247-E1AB-4EE4-9473-DFDE6AFCC250}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65135247-E1AB-4EE4-9473-DFDE6AFCC250}.Release|Any CPU.Build.0 = Release|Any CPU
{F8D44A32-788B-4E63-B379-278B90216E28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8D44A32-788B-4E63-B379-278B90216E28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8D44A32-788B-4E63-B379-278B90216E28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8D44A32-788B-4E63-B379-278B90216E28}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

@ -0,0 +1,95 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C76D0C23-1FFA-4963-93CD-E12BD643F030}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTests", "Tests\ConsoleTests\ConsoleTests.csproj", "{1889FA6E-B7C6-416E-8628-9449FB9070B9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{3B720C0C-53FE-4642-A2DB-87FD8634CD74}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stub", "Stub", "{2C607793-B163-4731-A4D1-AFE8A7C4C170}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubLib", "StubLib\StubLib.csproj", "{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiLol", "ApiLol\ApiLol.csproj", "{D59C9C7B-9BC2-4601-959D-BFA97E46D017}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DTO", "DTO\DTO.csproj", "{3919E408-EB12-4422-989B-C6ED4816D465}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiTests", "Tests\ApiTests\ApiTests.csproj", "{1779D8A4-2E12-47F3-BDA2-2E7F04B758EB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyFlib", "MyFlib\MyFlib.csproj", "{2142AB69-B483-4B0A-96DC-CFA87DEB11A5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UT_EF", "Tests\UT_EF\UT_EF.csproj", "{F896C30B-A6FE-42B2-BAC8-08360BC48DC6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbManager", "DbManager\DbManager.csproj", "{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiManager", "Client\ApiManager.csproj", "{1903905B-13B3-4DA2-94E2-917F39588032}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.Build.0 = Release|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.Build.0 = Release|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.Build.0 = Release|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Release|Any CPU.Build.0 = Release|Any CPU
{D59C9C7B-9BC2-4601-959D-BFA97E46D017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D59C9C7B-9BC2-4601-959D-BFA97E46D017}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D59C9C7B-9BC2-4601-959D-BFA97E46D017}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D59C9C7B-9BC2-4601-959D-BFA97E46D017}.Release|Any CPU.Build.0 = Release|Any CPU
{3919E408-EB12-4422-989B-C6ED4816D465}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3919E408-EB12-4422-989B-C6ED4816D465}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3919E408-EB12-4422-989B-C6ED4816D465}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3919E408-EB12-4422-989B-C6ED4816D465}.Release|Any CPU.Build.0 = Release|Any CPU
{1779D8A4-2E12-47F3-BDA2-2E7F04B758EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1779D8A4-2E12-47F3-BDA2-2E7F04B758EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1779D8A4-2E12-47F3-BDA2-2E7F04B758EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1779D8A4-2E12-47F3-BDA2-2E7F04B758EB}.Release|Any CPU.Build.0 = Release|Any CPU
{2142AB69-B483-4B0A-96DC-CFA87DEB11A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2142AB69-B483-4B0A-96DC-CFA87DEB11A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2142AB69-B483-4B0A-96DC-CFA87DEB11A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2142AB69-B483-4B0A-96DC-CFA87DEB11A5}.Release|Any CPU.Build.0 = Release|Any CPU
{F896C30B-A6FE-42B2-BAC8-08360BC48DC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F896C30B-A6FE-42B2-BAC8-08360BC48DC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F896C30B-A6FE-42B2-BAC8-08360BC48DC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F896C30B-A6FE-42B2-BAC8-08360BC48DC6}.Release|Any CPU.Build.0 = Release|Any CPU
{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71DDCC06-D993-47B0-92E3-5DD6E295FB8B}.Release|Any CPU.Build.0 = Release|Any CPU
{1903905B-13B3-4DA2-94E2-917F39588032}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1903905B-13B3-4DA2-94E2-917F39588032}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1903905B-13B3-4DA2-94E2-917F39588032}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1903905B-13B3-4DA2-94E2-917F39588032}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1889FA6E-B7C6-416E-8628-9449FB9070B9} = {C76D0C23-1FFA-4963-93CD-E12BD643F030}
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {2C607793-B163-4731-A4D1-AFE8A7C4C170}
{1779D8A4-2E12-47F3-BDA2-2E7F04B758EB} = {C76D0C23-1FFA-4963-93CD-E12BD643F030}
{F896C30B-A6FE-42B2-BAC8-08360BC48DC6} = {C76D0C23-1FFA-4963-93CD-E12BD643F030}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {92F3083D-793F-4552-8A9A-0AD6534159C9}
EndGlobalSection
EndGlobal

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:LolApp.ViewModels"
xmlns:myviews="clr-namespace:LolApp.ContentViews"
xmlns:appvm="clr-namespace:LolApp.ViewModels"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="LolApp.AddChampionPage"
Title="AddChampionPage"
x:Name="root">
<Grid RowDefinitions="Auto,*, Auto" BackgroundColor="{StaticResource Black}">
<VerticalStackLayout>
<Label Text="Nouveau Champion" IsVisible="{Binding IsNew}"
Style="{StaticResource title}"/>
<Label Text="Modifier le Champion" IsVisible="{Binding IsNew, Converter={StaticResource invertedBoolConverter}}"
Style="{StaticResource title}"/>
<Grid><Line Stroke="{StaticResource Primary}"
X1="0" Y1="0" X2="200" Y2="0"
HorizontalOptions="Center"/>
</Grid>
</VerticalStackLayout>
<ScrollView Grid.Row="1">
<Grid ColumnDefinitions="*, 3*" RowDefinitions="Auto, Auto, Auto, 162, 162, Auto, Auto, Auto, Auto">
<Label Text="Nom :"
Style="{StaticResource labelForEntry}"/>
<Entry Grid.Column="1" Placeholder="Nom du champion" Text="{Binding Champion.Name}"
Style="{StaticResource defaultEntry}"
IsEnabled="{Binding IsNew}"/>
<Label Text="Icone :" Grid.Row="1" Style="{StaticResource labelForEntry}"/>
<ImageButton Grid.Row="1" Grid.Column="1" HeightRequest="42" WidthRequest="42"
Source="{Binding Champion.IconBase64, TargetNullValue='lol.png',
Converter={StaticResource base64ToImageSourceConverter}}"
BackgroundColor="{StaticResource Secondary}"
HorizontalOptions="Start"
Margin="6"
Command="{Binding PickIconCommand}"/>
<Label Text="Image :" Grid.Row="2" Style="{StaticResource labelForEntry}"/>
<Grid Grid.Row="2" Grid.Column="1" x:Name="largeImageGrid" Margin="0, 0, 12, 0">
<ImageButton WidthRequest="{Binding Width, Source={x:Reference largeImageGrid}}"
HeightRequest="150"
Source="{Binding Champion.LargeImageBase64, TargetNullValue='lollogo.jpg',
Converter={StaticResource base64ToImageSourceConverter}}"
BackgroundColor="{StaticResource Secondary}"
HorizontalOptions="Start"
Margin="6"
Command="{Binding PickLargeImageCommand}"/>
</Grid>
<Label Text="Bio :" Grid.Row="3"
Style="{StaticResource labelForEntry}"/>
<Editor Grid.Column="1" Grid.Row="3"
Text="{Binding Champion.Bio}" Style="{StaticResource defaultEditor}"/>
<Label Text="Classe :" Grid.Row="4"
Style="{StaticResource labelForEntry}"/>
<myviews:ChampionClassSelector Grid.Row="4" Grid.Column="1" MaximumWidthRequest="{OnPlatform WinUI=400}"
CheckedColor="{StaticResource Primary}"
UncheckedColor="{StaticResource Secondary}"
SelectedValue="{Binding Champion.ChampionClass, Mode=TwoWay}"/>
<Label Text="Caractéristiques :" Grid.Row="5" Grid.RowSpan="2"
Style="{StaticResource labelForEntry}" VerticalOptions="Start"/>
<Border Stroke="{StaticResource Secondary}" Grid.Row="5" Grid.Column="1" VerticalOptions="FillAndExpand"> <ListView ItemsSource="{Binding Champion.Characteristics}"
Margin="6" HeightRequest="100" HorizontalOptions="Fill" VerticalOptions="Fill"
BackgroundColor="{StaticResource Black}" SeparatorColor="{StaticResource Secondary}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Command="{Binding Source={x:Reference root}, Path=BindingContext.RemoveCharacteristicCommand}"
CommandParameter="{Binding .}"
IsDestructive="True" Text="Delete"/>
</ViewCell.ContextActions>
<Border Margin="0,4" BackgroundColor="{StaticResource Secondary}">
<Border.StrokeShape>
<RoundRectangle CornerRadius="10, 10, 0, 10"/>
</Border.StrokeShape>
<Grid ColumnDefinitions="*, Auto">
<Label Text="{Binding Key}" TextColor="{StaticResource Black}"
HorizontalOptions="Start" VerticalOptions="Center" Margin="4, 0, 0, 0"/>
<Label Text="{Binding Value}" Grid.Column="1" TextColor="{StaticResource Black}"
HorizontalOptions="End" VerticalOptions="Center" Margin="0, 0, 4, 0"/>
</Grid>
</Border>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Border>
<Grid Grid.Column="1" Grid.Row="6" ColumnDefinitions="*, 58, Auto">
<Entry Style="{StaticResource defaultEntry}" Placeholder="Caractéristique" Text="{Binding NewCharacteristicDescription}"/>
<Entry Style="{StaticResource defaultEntry}" Placeholder="Valeur" Grid.Column="1" Text="{Binding NewCharacteristicValue}" Keyboard="Numeric">
<Entry.Behaviors>
<toolkit:NumericValidationBehavior Flags="ValidateOnValueChanged"
MinimumValue="0"
MaximumValue="9999999"
MaximumDecimalPlaces="0"
InvalidStyle="{StaticResource InvalidEntryStyle}"
ValidStyle="{StaticResource defaultEntry}"/>
</Entry.Behaviors>
</Entry>
<Button Grid.Column="2" Margin="4,8" CornerRadius="22"
Text="{StaticResource plus}"
Command="{Binding AddCharacteristicCommand}"/>
</Grid>
<Label Style="{StaticResource labelForEntry}" Text="Compétences :" Grid.Row="7" VerticalOptions="Start"/>
<Grid Grid.Row="7" Grid.Column="1" ColumnDefinitions="*, Auto">
<ListView ItemsSource="{Binding Champion.Skills}" Margin="6"
HeightRequest="100" HorizontalOptions="Fill" VerticalOptions="Fill" HasUnevenRows="True"
BackgroundColor="{StaticResource Black}" SeparatorColor="{StaticResource Secondary}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowDefinitions="Auto, Auto, *">
<Grid.Resources>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource Primary}"/>
</Style>
</Grid.Resources>
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" VerticalOptions="Center"/>
<Label Text="{Binding Type}" Grid.Row="1" VerticalOptions="Center" FontAttributes="Italic" FontSize="Micro"/>
<Label Text="{Binding Description}" FontSize="Micro" FontAttributes="Italic"
Grid.Row="2"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Grid.Column="1" Margin="4,8" CornerRadius="22"
Text="{StaticResource plus}" VerticalOptions="Start"
Command="{Binding AddSkillCommand}"/>
</Grid>
</Grid>
</ScrollView>
<HorizontalStackLayout Grid.Row="2" HorizontalOptions="Center" Spacing="40" Margin="0, 10, 0, 20">
<Button Text="Ajouter" Command="{Binding AddChampionCommand}" IsVisible="{Binding IsNew}"/>
<Button Text="Modifier" Command="{Binding EditChampionCommand}" IsVisible="{Binding IsNew, Converter={StaticResource invertedBoolConverter}}"/>
<Button Text="Annuler" Command="{Binding CancelCommand}"/>
</HorizontalStackLayout>
</Grid>
</ContentPage>

@ -0,0 +1,13 @@
using LolApp.ViewModels;
using ViewModels;
namespace LolApp;
public partial class AddChampionPage : ContentPage
{
public AddChampionPage(ChampionsMgrVM championsMgrVM, ChampionVM champion = null)
{
InitializeComponent();
BindingContext = new AddChampionPageVM(championsMgrVM, champion);
}
}

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LolApp.AddOrEditSkinPage"
Title="AddOrEditSkinPage"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit">
<Grid RowDefinitions="Auto,*, Auto" BackgroundColor="{StaticResource Black}">
<VerticalStackLayout>
<Label Text="Nouveau Skin" IsVisible="{Binding IsNew}"
Style="{StaticResource title}"/>
<Label Text="Modifier le Skin" IsVisible="{Binding IsNew, Converter={StaticResource invertedBoolConverter}}"
Style="{StaticResource title}"/>
<Grid><Line Stroke="{StaticResource Primary}"
X1="0" Y1="0" X2="200" Y2="0"
HorizontalOptions="Center"/>
</Grid>
</VerticalStackLayout>
<ScrollView Grid.Row="1">
<Grid ColumnDefinitions="*, 3*" RowDefinitions="Auto, Auto, Auto, Auto, 162">
<Label Text="Nom :"
Style="{StaticResource labelForEntry}"/>
<Entry Grid.Column="1" Placeholder="Nom du skin" Text="{Binding Skin.Name}"
Style="{StaticResource defaultEntry}"
IsEnabled="{Binding IsNew}"/>
<Label Text="Icone :" Grid.Row="1" Style="{StaticResource labelForEntry}"/>
<ImageButton Grid.Row="1" Grid.Column="1" HeightRequest="42" WidthRequest="42"
Source="{Binding Skin.IconBase64, TargetNullValue='lol.png',
Converter={StaticResource base64ToImageSourceConverter}}"
BackgroundColor="{StaticResource Secondary}"
HorizontalOptions="Start"
Margin="6"
Command="{Binding PickIconCommand}"/>
<Label Text="Image :" Grid.Row="2" Style="{StaticResource labelForEntry}"/>
<Grid Grid.Row="2" Grid.Column="1" x:Name="largeImageGrid" Margin="0, 0, 12, 0">
<ImageButton WidthRequest="{Binding Width, Source={x:Reference largeImageGrid}}"
HeightRequest="150"
Source="{Binding Skin.LargeImageBase64, TargetNullValue='lollogo.jpg',
Converter={StaticResource base64ToImageSourceConverter}}"
BackgroundColor="{StaticResource Secondary}"
HorizontalOptions="Start"
Margin="6"
Command="{Binding PickLargeImageCommand}"/>
</Grid>
<Label Text="Prix :" Grid.Row="3"
Style="{StaticResource labelForEntry}"/>
<HorizontalStackLayout Grid.Column="1" Grid.Row="3" Margin="6">
<Image Source="rp.png" HeightRequest="16" WidthRequest="16"/>
<Entry Grid.Column="1" Placeholder="Nom du skin" Text="{Binding Skin.Price}"
Style="{StaticResource defaultEntry}" Margin="4, 0, 0, 0" HorizontalTextAlignment="Start">
<Entry.Behaviors>
<toolkit:NumericValidationBehavior Flags="ValidateOnValueChanged"
MinimumValue="0"
MaximumValue="9999999"
MaximumDecimalPlaces="0"
InvalidStyle="{StaticResource InvalidEntryStyle}"
ValidStyle="{StaticResource defaultEntry}"/>
</Entry.Behaviors>
</Entry>
</HorizontalStackLayout>
<Label Text="Description :" Grid.Row="4"
Style="{StaticResource labelForEntry}"/>
<Editor Grid.Column="1" Grid.Row="4"
Text="{Binding Skin.Description}" Style="{StaticResource defaultEditor}"/>
</Grid>
</ScrollView>
<HorizontalStackLayout Grid.Row="2" HorizontalOptions="Center" Spacing="40" Margin="0, 10, 0, 20">
<Button Text="Ajouter" Command="{Binding AddSkinCommand}" IsVisible="{Binding IsNew}"/>
<Button Text="Modifier" Command="{Binding EditSkinCommand}" IsVisible="{Binding IsNew, Converter={StaticResource invertedBoolConverter}}"/>
<Button Text="Annuler" Command="{Binding CancelCommand}"/>
</HorizontalStackLayout>
</Grid>
</ContentPage>

@ -0,0 +1,24 @@
using LolApp.ViewModels;
using ViewModels;
namespace LolApp;
public partial class AddOrEditSkinPage : ContentPage
{
AddOrEditSkinPage()
{
InitializeComponent();
}
public AddOrEditSkinPage(SkinsMgrVM skinsMgrVM, SkinVM skin)
:this()
{
BindingContext = new AddOrEditSkinPageVM(skinsMgrVM, skin);
}
public AddOrEditSkinPage(SkinsMgrVM skinsMgrVM, ChampionVM champion)
:this()
{
BindingContext = new AddOrEditSkinPageVM(skinsMgrVM, champion);
}
}

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LolApp.AddSkill"
xmlns:appvm="clr-namespace:LolApp.ViewModels"
Title="AddSkill">
<Grid RowDefinitions="Auto,*, Auto" BackgroundColor="{StaticResource Gray900}">
<VerticalStackLayout>
<Label Text="Nouvelle Compétence"
Style="{StaticResource title}"/>
<Grid>
<Line Stroke="{StaticResource Primary}"
X1="0" Y1="0" X2="200" Y2="0"
HorizontalOptions="Center"/>
</Grid>
</VerticalStackLayout>
<ScrollView Grid.Row="1">
<Grid ColumnDefinitions="*, 3*" RowDefinitions="Auto, Auto, *">
<Label Text="Nom :" Style="{StaticResource labelForEntry}"/>
<Entry Text="{Binding Name}" Style="{StaticResource defaultEntry}"
Grid.Column="1"/>
<Label Text="Type :" Style="{StaticResource labelForEntry}" Grid.Row="1"/>
<Picker ItemsSource="{Binding AllSkills}" SelectedItem="{Binding SkillType}"
Grid.Row="1" Grid.Column="1"
Style="{StaticResource defaultPicker}"/>
<Label Text="Description :" Style="{StaticResource labelForEntry}" Grid.Row="2"/>
<Editor Grid.Row="2" Grid.Column="1" Text="{Binding Description}"
Style="{StaticResource defaultEditor}"/>
</Grid>
</ScrollView>
<HorizontalStackLayout Grid.Row="2" HorizontalOptions="Center" Spacing="40" Margin="0, 10, 0, 20">
<Button Text="Ajouter" Command="{Binding AddSkillToChampionCommand}"/>
<Button Text="Annuler" Command="{Binding CancelCommand}"/>
</HorizontalStackLayout>
</Grid>
</ContentPage>

@ -0,0 +1,13 @@
using LolApp.ViewModels;
using ViewModels;
namespace LolApp;
public partial class AddSkill : ContentPage
{
public AddSkill(EditableChampionVM champion)
{
InitializeComponent();
BindingContext = new AddSkillVM(champion);
}
}

@ -0,0 +1,18 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:LolApp"
x:Class="LolApp.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/FontAwesomeGlyphs.xaml" x:Name="Colors" />
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
<ResourceDictionary Source="Resources/Styles/MyStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

@ -0,0 +1,12 @@
namespace LolApp;
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
}

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="LolApp.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:LolApp"
Shell.FlyoutBehavior="Disabled">
<TabBar>
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage"
Icon="{OnPlatform 'lol.png'}" />
<ShellContent
Title="Champions"
ContentTemplate="{DataTemplate local:ChampionsPage}"
Route="Championspage"
Icon="{OnPlatform 'sword.png'}" />
</TabBar>
</Shell>

@ -0,0 +1,10 @@
namespace LolApp;
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="LolApp.ChampionPage"
Title="ChampionPage"
x:Name="root"
BackgroundColor="Black">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Modifier" Command="{Binding AppVM.NavigateToEditChampionPageCommand, Source={x:Reference root}}"
CommandParameter="{Binding}"/>
</ContentPage.ToolbarItems>
<ScrollView>
<VerticalStackLayout>
<AbsoluteLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
MaximumHeightRequest="{OnPlatform WinUI=300}"
HeightRequest="{Binding Width,
Source={RelativeSource AncestorType={x:Type ContentPage}},
Converter={StaticResource imageRatioConverter},
ConverterParameter={StaticResource imageRatio}}">
<Image Source="{Binding Image, Converter={StaticResource base64ToImageSourceConverter}}"
Aspect="AspectFit"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
MaximumHeightRequest="{OnPlatform WinUI=300}"/>
</AbsoluteLayout>
<Grid Padding="10" BackgroundColor="{StaticResource Black}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding Name}" FontAttributes="Bold" TextColor="{StaticResource Primary}"
FontSize="Title"/>
<VerticalStackLayout Grid.Column="1" HorizontalOptions="Center">
<Image Source="{Binding Class, Converter={StaticResource championClassToIconConverter}}"
HeightRequest="26" WidthRequest="26" x:Name="imgClass" PropertyChanged="imgClass_PropertyChanged">
<Image.Behaviors>
<toolkit:IconTintColorBehavior TintColor="{StaticResource Primary}"
x:Name="tintColor"/>
</Image.Behaviors>
</Image>
<Label Text="{Binding Class}" TextColor="{StaticResource Primary}"
FontSize="Micro"/>
</VerticalStackLayout>
</Grid>
<ScrollView VerticalScrollBarVisibility="Always" BackgroundColor="Black" >
<Label Text="{Binding Bio}" TextColor="{StaticResource Primary}" Padding="10" FontAttributes="Italic"/>
</ScrollView>
<Label Padding="10" Text="Caractéristiques" FontSize="Title" TextColor="{StaticResource Primary}"
BackgroundColor="Black"/>
<Grid MaximumHeightRequest="240">
<Grid.Resources>
<x:Double x:Key="gridHeight">120</x:Double>
<x:Int32 x:Key="nbCellsPerLine">3</x:Int32>
</Grid.Resources>
<Grid.HeightRequest>
<MultiBinding Converter="{StaticResource multiMathExpressionConverter}"
ConverterParameter="ceiling(x1/x2)*x0">
<Binding Source="{StaticResource gridHeight}"/>
<Binding Path="Characteristics.Count"/>
<Binding Source="{StaticResource nbCellsPerLine}"/>
</MultiBinding>
</Grid.HeightRequest>
<CollectionView ItemsSource="{Binding Characteristics}"
ItemsLayout="VerticalGrid, 3"
VerticalScrollBarVisibility="Always">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10" HeightRequest="120">
<Border Stroke="{StaticResource PrimaryBrush}" StrokeThickness="2" BackgroundColor="{StaticResource Black}">
<Grid RowDefinitions="4*,3*">
<Label Text="{Binding Key}" HorizontalOptions="Center" TextColor="{StaticResource Primary}"
FontSize="Small" FontAttributes="Bold" VerticalOptions="End" HorizontalTextAlignment="Center"
Margin="0, 0, 0, 5"/>
<Label Grid.Row="1" Text="{Binding Value}" HorizontalOptions="Center" TextColor="{StaticResource Primary}"
VerticalOptions="Start" HorizontalTextAlignment="Center"
FontSize="Small"/>
</Grid>
</Border>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
<Label Padding="10" Text="Compétences" FontSize="Title" TextColor="{StaticResource Primary}"
BackgroundColor="Black"/>
<ListView ItemsSource="{Binding Skills}" Margin="10"
BackgroundColor="Black" HasUnevenRows="True" VerticalScrollBarVisibility="Always"
MaximumHeightRequest="400">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.Resources>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource Primary}"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" VerticalOptions="Center"/>
<Label Text="{Binding Type}" Grid.Column="1" VerticalOptions="Center" FontAttributes="Italic" FontSize="Micro"/>
<Label Text="{Binding Description}" FontSize="Micro" FontAttributes="Italic"
Grid.ColumnSpan="2" Grid.Row="1"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Grid ColumnDefinitions="*, Auto">
<Label Padding="10" Text="Skins" FontSize="Title" TextColor="{StaticResource Primary}"
BackgroundColor="Black"/>
<Button Grid.Column="1" Text="{StaticResource plus}" CornerRadius="22" BackgroundColor="{StaticResource Primary}"
TextColor="{StaticResource Black}" FontSize="Header"
Command="{Binding AppVM.NavigateToAddNewSkinPageCommand, Source={x:Reference root}}"
CommandParameter="{Binding}"
VerticalOptions="Center" HorizontalOptions="Center"
Margin="6"/>
</Grid>
<ListView BindingContext="{Binding AppVM, Source={x:Reference root}}"
ItemsSource="{Binding SkinsMgrVM.Skins}" HasUnevenRows="True"
BackgroundColor="{StaticResource Black}"
x:Name="listSkins">
<ListView.Behaviors>
<toolkit:EventToCommandBehavior
EventName="ItemSelected"
Command="{Binding NavigateToSkinDetailsPageCommand}"
EventArgsConverter="{StaticResource SelectedItemEventArgsConverter}"
/>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem IsDestructive="True"
Text="Supprimer"
Command="{Binding BindingContext.SkinsMgrVM.DeleteSkinCommand, Source={x:Reference listSkins}}"
CommandParameter="{Binding .}"/>
<MenuItem Text="Modifier"
Command="{Binding Source={x:Reference listSkins}, Path=BindingContext.NavigateToEditSkinPageCommand}"
CommandParameter="{Binding .}"/>
</ViewCell.ContextActions>
<Border Stroke="{StaticResource Primary}" Padding="8,4" HeightRequest="60" Margin="4"
StrokeThickness="3" BackgroundColor="{StaticResource Black}">
<Border.StrokeShape>
<RoundRectangle CornerRadius="0, 10, 10, 10"/>
</Border.StrokeShape>
<HorizontalStackLayout VerticalOptions="Center">
<Image Source="{Binding Icon, Converter={StaticResource base64ToImageSourceConverter}}"
HeightRequest="46" WidthRequest="46"/>
<Label Text="{Binding Name}" TextColor="{StaticResource Primary}" FontSize="Small"
VerticalOptions="Center" Margin="10,4"/>
</HorizontalStackLayout>
</Border>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</VerticalStackLayout>
</ScrollView>
</ContentPage>

@ -0,0 +1,31 @@
using CommunityToolkit.Maui.Behaviors;
using LolApp.ViewModels;
using ViewModels;
namespace LolApp;
public partial class ChampionPage : ContentPage
{
public ApplicationVM AppVM { get; set; }
public ChampionVM Champion { get; }
public ChampionPage(ChampionVM cvm, ApplicationVM appVM)
{
AppVM = appVM;
BindingContext = Champion = cvm;
InitializeComponent();
}
void imgClass_PropertyChanged(System.Object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
Image img = sender as Image;
if(e.PropertyName == "Source" && img != null && img.Behaviors.Any(b => b is IconTintColorBehavior))
{
var beh = (img.Behaviors.First(b => b is IconTintColorBehavior) as IconTintColorBehavior);
var color = beh.TintColor;
img.Behaviors.Remove(beh);
img.Behaviors.Add(new IconTintColorBehavior() { TintColor = color});
}
}
}

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:myviews="clr-namespace:LolApp.ContentViews"
xmlns:vm="clr-namespace:ViewModels;assembly=ViewModels"
xmlns:appvm="clr-namespace:LolApp.ViewModels"
x:Class="LolApp.ChampionsPage"
Title="Champions"
x:Name="root">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Ajouter" Command="{Binding AppVM.NavigateToAddNewChampionPageCommand}" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ControlTemplate x:Key="searchByStringControl">
<Grid Margin="20,4" HeightRequest="{OnPlatform 30, Android=40}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Entry Placeholder="{TemplateBinding PlaceHolder}"
Text="{TemplateBinding Text, Mode=TwoWay}"/>
<Button Text="{StaticResource magnifying-glass}"
FontFamily="FASolid"
Grid.Column="1" Margin="4, 0, 0, 0"
Command="{TemplateBinding Command}"
CommandParameter="{TemplateBinding CommandParameter}"/>
</Grid>
</ControlTemplate>
</ContentPage.Resources>
<ContentPage.Behaviors>
<toolkit:EventToCommandBehavior
EventName = "Loaded"
Command="{Binding AppVM.ChampionsMgrVM.LoadChampionsCommand}"/>
</ContentPage.Behaviors>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<toolkit:Expander Grid.Row="1">
<toolkit:Expander.Header>
<HorizontalStackLayout>
<Label Text="Chercher par "
HorizontalOptions="Center"/>
<Label Text="nom" IsVisible="{Binding VM.SearchedName, Converter={StaticResource isStringNotNullOrWhiteSpaceConverter}}"/>
<Label Text="compétence" IsVisible="{Binding VM.SearchedSkill, Converter={StaticResource isStringNotNullOrWhiteSpaceConverter}}"/>
<Label Text=" "/>
<Label Text="{Binding IsExpanded,
Source={RelativeSource AncestorType={x:Type toolkit:Expander}},
Converter={StaticResource isExpandedToCaretConverter}}"
FontFamily="FASolid"
VerticalOptions="Center"/>
</HorizontalStackLayout>
</toolkit:Expander.Header>
<VerticalStackLayout HorizontalOptions="Fill" BackgroundColor="WhiteSmoke">
<myviews:SearchByStringView ControlTemplate="{StaticResource searchByStringControl}"
PlaceHolder="Entrez un nom"
Text="{Binding VM.SearchedName, Mode=TwoWay}"
Command="{Binding AppVM.ChampionsMgrVM.LoadChampionsByNameCommand}"
CommandParameter="{Binding VM.SearchedName}"/>
<myviews:SearchByStringView ControlTemplate="{StaticResource searchByStringControl}"
PlaceHolder="Entrez une compétence"
Text="{Binding VM.SearchedSkill, Mode=TwoWay}"
Command="{Binding AppVM.ChampionsMgrVM.LoadChampionsBySkillCommand}"
CommandParameter="{Binding VM.SearchedSkill}"/>
<myviews:SearchByStringView ControlTemplate="{StaticResource searchByStringControl}"
PlaceHolder="Entrez une caractéristique"
Text="{Binding VM.SearchedCharacteristic, Mode=TwoWay}"
Command="{Binding AppVM.ChampionsMgrVM.LoadChampionsByCharacteristicCommand}"
CommandParameter="{Binding VM.SearchedCharacteristic}"/>
<Label Text="Filtrer par classe :" Margin="20, 4, 0, 0"
FontSize="Micro"/>
<CollectionView ItemsSource="{x:Static appvm:ChampionClassVM.Classes}" ItemsLayout="VerticalGrid, 3"
SelectionMode="Single" HeightRequest="110" x:Name="classesView"
SelectionChangedCommand="{Binding AppVM.ChampionsMgrVM.LoadChampionsByClassCommand}"
SelectionChangedCommandParameter="{Binding VM.SelectedItem, Source={RelativeSource Self}}"
SelectedItem="{Binding VM.SelectedClass, Source={x:Reference root}, Mode=TwoWay}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid HorizontalOptions="Center" RowDefinitions="*, *" WidthRequest="100" Padding="10, 10, 10, 0"
BackgroundColor="{Binding IsSelected, Converter={StaticResource isSelectedToColorConverter}}">
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference root}, Path=BindingContext.VM.SelectedChampionClassChangedCommand}"
CommandParameter="{Binding}" />
</Grid.GestureRecognizers>
<Image Source="{Binding Model, Converter={StaticResource championClassToIconConverter}}" HeightRequest="26" WidthRequest="26"
/>
<Label Text="{Binding Model}" TextColor="{StaticResource Black}"
HorizontalOptions="Center" Grid.Row="1"
FontSize="Micro">
</Label>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</toolkit:Expander>
<ListView Grid.Row="2" CachingStrategy="RecycleElementAndDataTemplate"
ItemsSource="{Binding AppVM.ChampionsMgrVM.Champions}"
RowHeight="50"
SelectedItem="{Binding AppVM.ChampionsMgrVM.SelectedChampion, Mode=TwoWay}">
<ListView.Behaviors>
<toolkit:EventToCommandBehavior
EventName="ItemSelected"
Command="{Binding AppVM.NavigateToChampionDetailsPageCommand}"
EventArgsConverter="{StaticResource SelectedItemEventArgsConverter}"
/>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Command="{Binding Source={x:Reference root}, Path=BindingContext.AppVM.ChampionsMgrVM.DeleteChampionCommand}"
CommandParameter="{Binding .}"
IsDestructive="True" Text="Supprimer"/>
<MenuItem Command="{Binding Source={x:Reference root}, Path=BindingContext.AppVM.NavigateToEditChampionPageCommand}"
CommandParameter="{Binding .}"
IsDestructive="False" Text="Modifier"/>
</ViewCell.ContextActions>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Image Source="{Binding Icon, Converter={StaticResource base64ToImageSourceConverter}}"
HeightRequest="40"
WidthRequest="40"
Grid.RowSpan="2"
VerticalOptions="Center"
Margin="0, 0, 10, 0"/>
<Label Text="{Binding Name}" Grid.Column="1"
FontAttributes="Bold"
FontSize="{OnPlatform Header, WinUI=Small}"
VerticalOptions="Center"/>
<Label Text="{Binding Class}" Grid.Row="1" Grid.Column="1"
FontAttributes="Italic"
FontSize="Caption"
VerticalOptions="Center"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Grid Grid.Row="3" HorizontalOptions="Center" HeightRequest="45"
IsVisible="{Binding AppVM.ChampionsMgrVM.NbChampions, Converter={StaticResource intToBoolConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Style="{StaticResource iconButton}"
Command="{Binding AppVM.ChampionsMgrVM.PreviousPageCommand}">
<Button.ImageSource>
<FontImageSource Glyph="{StaticResource angle-left}"
FontFamily="FASolid"
Size="Title"/>
</Button.ImageSource>
</Button>
<StackLayout Orientation="Horizontal" Grid.Column="1"
HorizontalOptions="Center" VerticalOptions="Center">
<StackLayout.Resources>
<Style BasedOn="{StaticResource defaultLabel}" TargetType="Label">
<Setter Property="Margin" Value="2"/>
</Style>
</StackLayout.Resources>
<Label Text="{Binding AppVM.ChampionsMgrVM.Index, Converter={StaticResource plusOneConverter}}" HorizontalOptions="End"/>
<Label Text="/"/>
<Label Text="{Binding AppVM.ChampionsMgrVM.NbPages}" HorizontalOptions="Start"/>
</StackLayout>
<Button Grid.Column="2" Style="{StaticResource iconButton}"
Command="{Binding AppVM.ChampionsMgrVM.NextPageCommand}">
<Button.ImageSource>
<FontImageSource Glyph="{StaticResource angle-right}" FontFamily="FASolid"
Size="Title"/>
</Button.ImageSource>
</Button>
</Grid>
</Grid>
</ContentPage>

@ -0,0 +1,17 @@
using LolApp.ViewModels;
using ViewModels;
namespace LolApp;
public partial class ChampionsPage : ContentPage
{
public ApplicationVM AppVM { get; }
public ChampionsPageVM VM { get; }
public ChampionsPage(ApplicationVM appVM)
{
InitializeComponent();
AppVM = appVM;
VM = new ChampionsPageVM(AppVM.ChampionsMgrVM);
BindingContext = this;
}
}

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:model="clr-namespace:Model;assembly=Model"
x:Class="LolApp.ContentViews.ChampionClassSelector"
x:Name="root">
<ContentView.Resources>
<model:ChampionClass x:Key="assassin">Assassin</model:ChampionClass>
<model:ChampionClass x:Key="fighter">Fighter</model:ChampionClass>
<model:ChampionClass x:Key="mage">Mage</model:ChampionClass>
<model:ChampionClass x:Key="marksman">Marksman</model:ChampionClass>
<model:ChampionClass x:Key="support">Support</model:ChampionClass>
<model:ChampionClass x:Key="tank">Tank</model:ChampionClass>
<ControlTemplate x:Key="RadioButtonTemplate">
<Border Stroke="{StaticResource Transparent}"
BackgroundColor="{StaticResource Transparent}"
HorizontalOptions="Fill"
VerticalOptions="Fill"
Padding="0">
<Border.StrokeShape>
<RoundRectangle CornerRadius="40, 40, 0, 40"/>
</Border.StrokeShape>
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CheckedStates">
<VisualState x:Name="Checked">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="{Binding CheckedColor, Source={x:Reference root}}" />
<Setter Property="Stroke"
Value="{Binding CheckedColor, Source={x:Reference root}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="{Binding UncheckedColor, Source={x:Reference root}}" />
<Setter Property="Stroke"
Value="{Binding UncheckedColor, Source={x:Reference root}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
<Grid>
<ContentPresenter VerticalOptions="Center" HorizontalOptions="Center" />
</Grid>
</Border>
</ControlTemplate>
<Style TargetType="RadioButton">
<Setter Property="ControlTemplate"
Value="{StaticResource RadioButtonTemplate}" />
</Style>
</ContentView.Resources>
<Grid ColumnDefinitions="*, *, *" RowDefinitions="*, *"
Margin="6" ColumnSpacing="6" RowSpacing="6"
RadioButtonGroup.GroupName="championClasses"
RadioButtonGroup.SelectedValue="{Binding SelectedValue, Source={x:Reference root}, Mode=TwoWay}">
<Grid.Resources>
<Style TargetType="Label">
<Setter Property="FontSize" Value="{OnPlatform Micro, WinUI=12}"/>
</Style>
</Grid.Resources>
<RadioButton Value="{Binding Source={StaticResource assassin}}">
<RadioButton.Content>
<VerticalStackLayout>
<Image Source="{Binding Source={StaticResource assassin}, Converter={StaticResource championClassToIconConverter}}"
WidthRequest="26" HeightRequest="26" HorizontalOptions="Center"/>
<Label Text="Assassin" HorizontalOptions="Center"/>
</VerticalStackLayout>
</RadioButton.Content>
</RadioButton>
<RadioButton Grid.Column="1"
Value="{Binding Source={StaticResource fighter}}">
<RadioButton.Content>
<VerticalStackLayout>
<Image Source="{Binding Source={StaticResource fighter}, Converter={StaticResource championClassToIconConverter}}"
WidthRequest="26" HeightRequest="26" HorizontalOptions="Center"/>
<Label Text="Fighter" HorizontalOptions="Center"/>
</VerticalStackLayout>
</RadioButton.Content>
</RadioButton>
<RadioButton Grid.Column="2"
Value="{Binding Source={StaticResource mage}}">
<RadioButton.Content>
<VerticalStackLayout>
<Image Source="{Binding Source={StaticResource mage}, Converter={StaticResource championClassToIconConverter}}"
WidthRequest="26" HeightRequest="26" HorizontalOptions="Center"/>
<Label Text="Mage" HorizontalOptions="Center"/>
</VerticalStackLayout>
</RadioButton.Content>
</RadioButton>
<RadioButton Grid.Row="1" Grid.Column="0"
Value="{Binding Source={StaticResource marksman}}">
<RadioButton.Content>
<VerticalStackLayout>
<Image Source="{Binding Source={StaticResource marksman}, Converter={StaticResource championClassToIconConverter}}"
WidthRequest="26" HeightRequest="26" HorizontalOptions="Center"/>
<Label Text="Marksman" HorizontalOptions="Center"/>
</VerticalStackLayout>
</RadioButton.Content>
</RadioButton>
<RadioButton Grid.Row="1" Grid.Column="1"
Value="{Binding Source={StaticResource support}}">
<RadioButton.Content>
<VerticalStackLayout>
<Image Source="{Binding Source={StaticResource support}, Converter={StaticResource championClassToIconConverter}}"
WidthRequest="26" HeightRequest="26" HorizontalOptions="Center"/>
<Label Text="Support" HorizontalOptions="Center"/>
</VerticalStackLayout>
</RadioButton.Content>
</RadioButton>
<RadioButton Grid.Row="1" Grid.Column="2"
Value="{Binding Source={StaticResource tank}}">
<RadioButton.Content>
<VerticalStackLayout>
<Image Source="{Binding Source={StaticResource tank}, Converter={StaticResource championClassToIconConverter}}"
WidthRequest="26" HeightRequest="26" HorizontalOptions="Center"/>
<Label Text="Tank" HorizontalOptions="Center"/>
</VerticalStackLayout>
</RadioButton.Content>
</RadioButton>
</Grid>
</ContentView>

@ -0,0 +1,34 @@
using Model;
namespace LolApp.ContentViews;
public partial class ChampionClassSelector : ContentView
{
public ChampionClassSelector()
{
InitializeComponent();
}
public static readonly BindableProperty SelectedValueProperty = BindableProperty.Create(nameof(SelectedValue), typeof(ChampionClass), typeof(ChampionClassSelector), ChampionClass.Unknown, BindingMode.TwoWay);
public ChampionClass SelectedValue
{
get => (ChampionClass)GetValue(SelectedValueProperty);
set => SetValue(SelectedValueProperty, value);
}
public static readonly BindableProperty CheckedColorProperty = BindableProperty.Create(nameof(CheckedColor), typeof(Color), typeof(ChampionClassSelector), Colors.DarkSalmon);
public Color CheckedColor
{
get => (Color)GetValue(CheckedColorProperty);
set => SetValue(CheckedColorProperty, value);
}
public static readonly BindableProperty UncheckedColorProperty = BindableProperty.Create(nameof(UncheckedColor), typeof(Color), typeof(ChampionClassSelector), Colors.DarkSalmon);
public Color UncheckedColor
{
get => (Color)GetValue(UncheckedColorProperty);
set => SetValue(UncheckedColorProperty, value);
}
}

@ -0,0 +1,38 @@
using System.Windows.Input;
namespace LolApp.ContentViews;
public class SearchByStringView : ContentView
{
public static readonly BindableProperty PlaceHolderProperty = BindableProperty.Create(nameof(PlaceHolder), typeof(string), typeof(SearchByStringView), string.Empty);
public string PlaceHolder
{
get => (string)GetValue(PlaceHolderProperty);
set => SetValue(PlaceHolderProperty, value);
}
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(SearchByStringView), string.Empty);
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(SearchByStringView), null);
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(SearchByStringView), null);
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
}

@ -0,0 +1,100 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>LolApp</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Display name -->
<ApplicationTitle>LolApp</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>fr.uca.iut.lolapp</ApplicationId>
<ApplicationIdGuid>d3cd18a9-c614-4933-bd36-3008e72004d5</ApplicationIdGuid>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
<ProjectGuid>{0C898A04-092A-49AA-BE65-8AE818A2AF50}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net7.0-ios|AnyCPU'">
<CreatePackage>false</CreatePackage>
<CodesignProvision>appleIUT_TP2022</CodesignProvision>
<CodesignKey>iPhone Developer: Cedric BOUHOURS (M2E3ZQNZ3K)</CodesignKey>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net7.0-maccatalyst|AnyCPU'">
<CreatePackage>false</CreatePackage>
<CodesignKey>Developer ID Application</CodesignKey>
<PackageSigningKey>3rd Party Mac Developer Installer</PackageSigningKey>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net7.0-ios|AnyCPU'">
<CreatePackage>false</CreatePackage>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.22621.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
<MauiIcon Include="Resources\AppIcon\appicon.png" />
</ItemGroup>
<ItemGroup>
<None Remove="Resources\Images\fighter.svg" />
<None Remove="Resources\Images\lollogo.jpg" />
<None Remove="Resources\Images\sword.png" />
<None Remove="Resources\Images\lol.png" />
<None Remove="Resources\Fonts\Font Awesome 6 Free-Solid-900.otf" />
<None Remove="Resources\Images\support.svg" />
<None Remove="Resources\Images\tank.svg" />
<None Remove="Resources\Images\marksman.svg" />
<None Remove="Resources\Images\assassin.svg" />
<None Remove="Resources\Images\mage.svg" />
<None Remove="Resources\AppIcon\appicon.png" />
<None Remove="Resources\Splash\tank.svg" />
<None Remove="Resources\Splash\splash.png" />
<None Remove="Resources\Images\rp.png" />
</ItemGroup>
<ItemGroup>
<MauiImage Include="Resources\Images\lollogo.jpg" />
<MauiImage Include="Resources\Images\sword.png" />
<MauiImage Include="Resources\Images\lol.png" />
<MauiImage Include="Resources\Images\tank.svg" />
<MauiImage Include="Resources\Images\support.svg" />
<MauiImage Include="Resources\Images\marksman.svg" />
<MauiImage Include="Resources\Images\mage.svg" />
<MauiImage Include="Resources\Images\fighter.svg" />
<MauiImage Include="Resources\Images\assassin.svg" />
<MauiImage Include="Resources\Images\rp.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Client\ApiManager.csproj" />
<ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj" />
<ProjectReference Include="..\StubLib\StubLib.csproj" />
<ProjectReference Include="..\ViewModels\ViewModels.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Maui" Version="5.0.0" />
<PackageReference Include="CommunityToolkit.Maui.Markup" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
<PackageReference Include="Microsoft.Maui.Graphics.Skia" Version="7.0.59" />
</ItemGroup>
<ItemGroup>
<MauiSplashScreen Include="Resources\Splash\splash.png" />
</ItemGroup>
</Project>

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LolApp.MainPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="lollogo.jpg"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="League of Legends Data"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"/>
<Label
Text="Find information about champions, skins and runes"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"/>
</VerticalStackLayout>
</ScrollView>
</ContentPage>

@ -0,0 +1,11 @@
namespace LolApp;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}

@ -0,0 +1,38 @@
using ApiManager;
using CommunityToolkit.Maui;
using LolApp.ViewModels;
using Microsoft.Extensions.Logging;
using Model;
using StubLib;
using ViewModels;
namespace LolApp;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkit()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
fonts.AddFont("Font Awesome 6 Free-Solid-900.otf", "FASolid");
});
builder.Services.AddSingleton<IDataManager, StubData>()
.AddSingleton<ChampionsMgrVM>()
.AddSingleton<SkinsMgrVM>()
.AddSingleton<ApplicationVM>()
.AddSingleton<ChampionsPage>();
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
</manifest>

@ -0,0 +1,11 @@
using Android.App;
using Android.Content.PM;
using Android.OS;
namespace LolApp;
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
}

@ -0,0 +1,16 @@
using Android.App;
using Android.Runtime;
namespace LolApp;
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#512BD4</color>
<color name="colorPrimaryDark">#2B0B98</color>
<color name="colorAccent">#2B0B98</color>
</resources>

@ -0,0 +1,10 @@
using Foundation;
namespace LolApp;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
<key>NSCameraUsageDescription</key>
<string>New Entry</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>New Entry</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>New Entry</string>
</dict>
</plist>

@ -0,0 +1,16 @@
using ObjCRuntime;
using UIKit;
namespace LolApp;
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}

@ -0,0 +1,17 @@
using System;
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
namespace LolApp;
class Program : MauiApplication
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
static void Main(string[] args)
{
var app = new Program();
app.Run(args);
}
}

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="maui-application-id-placeholder" version="0.0.0" api-version="7" xmlns="http://tizen.org/ns/packages">
<profile name="common" />
<ui-application appid="maui-application-id-placeholder" exec="LolApp.dll" multiple="false" nodisplay="false" taskmanage="true" type="dotnet" launch_mode="single">
<label>maui-application-title-placeholder</label>
<icon>maui-appicon-placeholder</icon>
<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
</ui-application>
<shortcut-list />
<privileges>
<privilege>http://tizen.org/privilege/internet</privilege>
</privileges>
<dependencies />
<provides-appdefined-privileges />
</manifest>

@ -0,0 +1,9 @@
<maui:MauiWinUIApplication
x:Class="LolApp.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui"
xmlns:local="using:LolApp.WinUI">
</maui:MauiWinUIApplication>

@ -0,0 +1,25 @@
using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace LolApp.WinUI;
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : MauiWinUIApplication
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
<mp:PhoneIdentity PhoneProductId="B9226665-2A86-4F1D-BB62-983AD09442FD" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>$placeholder$</DisplayName>
<PublisherDisplayName>User Name</PublisherDisplayName>
<Logo>$placeholder$.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="$placeholder$"
Description="$placeholder$"
Square150x150Logo="$placeholder$.png"
Square44x44Logo="$placeholder$.png"
BackgroundColor="transparent">
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
<uap:SplashScreen Image="$placeholder$.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="LolApp.WinUI.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- The combination of below two tags have the following effect:
1) Per-Monitor for >= Windows 10 Anniversary Update
2) System < Windows 10 Anniversary Update
-->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

@ -0,0 +1,10 @@
using Foundation;
namespace LolApp;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
<key>NSCameraUsageDescription</key>
<string>New Entry</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Pour accéder aux images...</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Pour accéder aux images...</string>
</dict>
</plist>

@ -0,0 +1,16 @@
using ObjCRuntime;
using UIKit;
namespace LolApp;
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}

@ -0,0 +1,8 @@
{
"profiles": {
"Windows Machine": {
"commandName": "MsixPackage",
"nativeDebugging": false
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
</svg>

@ -0,0 +1,34 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using CommunityToolkit.Maui.Converters;
namespace LolApp.Resources.Converters
{
public class Base64ToImageSourceConverter : ByteArrayToImageSourceConverter, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string base64 = value as string;
if (string.IsNullOrWhiteSpace(base64)) return null;
try
{
byte[] bytes = System.Convert.FromBase64String(base64);
return base.ConvertFrom(bytes, culture);
}
catch
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
ImageSource source = value as ImageSource;
if (source == null) return null;
byte[] bytes = base.ConvertBackTo(source, culture) as byte[];
return System.Convert.ToBase64String(bytes);
}
}
}

@ -0,0 +1,42 @@
using System;
using System.Globalization;
using Model;
namespace LolApp.Resources.Converters
{
public class ChampionClassToIconConverter : IValueConverter
{
private static Dictionary<ChampionClass, string> icons = new()
{
[ChampionClass.Assassin] = "assassin.png",
[ChampionClass.Fighter] = "fighter.png",
[ChampionClass.Mage] = "mage.png",
[ChampionClass.Marksman] = "marksman.png",
[ChampionClass.Support] = "support.png",
[ChampionClass.Tank] = "tank.png"
};
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
ChampionClass champClass = (ChampionClass)value;
if(!icons.TryGetValue(champClass, out string icon))
{
return "";
}
return ImageSource.FromFile($"{icon}");
}
catch
{
return "";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

@ -0,0 +1,28 @@
using System;
using System.Globalization;
namespace LolApp.Resources.Converters
{
public class ImageRatioConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
double parentWidth = (double)value;
double ratio = (double)parameter;
return parentWidth*ratio;
}
catch
{
return 0.0;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

@ -0,0 +1,28 @@
using System;
using System.Globalization;
namespace LolApp.Resources.Converters
{
public class PlusOneConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int i = -1;
try
{
i = (int)value;
}
catch (InvalidCastException e)
{
throw new InvalidCastException("PlusOneConverter : the value must be an int");
}
return i + 1;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save