Compare commits

...

33 Commits

Author SHA1 Message Date
Corentin RICHARD f211a89651 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R 47b35b48e3 Merge branch 'master' of https://codefirst.iut.uca.fr/git/corentin.richard/EntityFramework_ConsoDeServices_TP
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R 3f58547a01 fix error
2 years ago
Pierre FERREIRA fe13bf5d7d Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R 8489b0b848 Merge branch 'master' of https://codefirst.iut.uca.fr/git/corentin.richard/EntityFramework_ConsoDeServices_TP
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R f46b2d9aec quality review
2 years ago
Pierre FERREIRA b0166276bf Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin RICHARD f4dd0dd152 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R b2b59223ec suppression Maui
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R 8059cf28f3 Merge branch 'master' of https://codefirst.iut.uca.fr/git/corentin.richard/EntityFramework_ConsoDeServices_TP
2 years ago
Corentin R f82c425e30 modification README
2 years ago
Pierre Ferreira 28e5a0e570 correction du count, desormais fonctionnel en ligne de commande
continuous-integration/drone/push Build is failing Details
2 years ago
Pierre Ferreira d38600ce4b test maui
2 years ago
Pierre FERREIRA 3e605c9fec Merge pull request 'DevPF' (#38) from DevPF into master
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre Ferreira 446d2d84a2 Merge branch 'master' of https://codefirst.iut.uca.fr/git/corentin.richard/EntityFramework_ConsoDeServices_TP into DevPF
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R 3aba9a431a Merge branch 'master' of https://codefirst.iut.uca.fr/git/corentin.richard/EntityFramework_ConsoDeServices_TP
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre FERREIRA 71cee62cad Merge pull request 'RuneBranch' (#36) from RuneBranch into master
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R fee25f5dff adding client console
2 years ago
Corentin R 5280f569ea merge
2 years ago
Corentin R b94825d358 Ajout d'un client utilisant http
2 years ago
Pierre Ferreira 116d150949 Merge branch 'master' into RuneBranch
continuous-integration/drone/push Build is failing Details
2 years ago
Pierre Ferreira f3274ca258 Merge branch 'master' of https://codefirst.iut.uca.fr/git/corentin.richard/EntityFramework_ConsoDeServices_TP into DevPF
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin RICHARD 45d4366003 Merge pull request 'Creation du client console' (#35) from ConsoleClient into master
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin R 0720e06c14 Creation du client console
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre FERREIRA 31bfa2b056 Ajout Coordonnée
continuous-integration/drone/push Build is passing Details
2 years ago
Corentin RICHARD b99148bc73 Merge pull request 'advancedController' (#34) from advancedController into master
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre FERREIRA 03507e9c8a Maj état des livrables EF
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre FERREIRA 9d2d8c3805 logs ✔️
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre FERREIRA c2a4916dc7 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre Ferreira 41de783e44 ajout d'un RuneController (et donc de RuneMapper et RuneDTO) 📦
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre Ferreira 3da8ab952a Ajout des liaisons One to many pour champion et skill, et pour runepage et rune, migration fonctionnel avec comme context le loldbcontext, mais pas avec le stubbed
continuous-integration/drone/push Build is passing Details
2 years ago
Pierre Ferreira 93a1c42ad2 🧪 ajout du premier test et des charactéristiques(pb sur cette dernière nonobstant..) 🩹
2 years ago
Pierre Ferreira 9536d38745 🚀 création d'une branche perso pour eviter les conflits, et mise sur le depots du code : la creation de champion en base de donnée avec nom, bio et icone
2 years ago

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33213.308
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EF_LoL", "EF_LoL\EF_LoL.csproj", "{1AF6FE09-1ABF-4C51-8EC6-D2938876AAD2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "TestProject\TestProject.csproj", "{1A0B75E2-ECCE-47F3-A8FB-79F48F76E9A1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1AF6FE09-1ABF-4C51-8EC6-D2938876AAD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1AF6FE09-1ABF-4C51-8EC6-D2938876AAD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1AF6FE09-1ABF-4C51-8EC6-D2938876AAD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1AF6FE09-1ABF-4C51-8EC6-D2938876AAD2}.Release|Any CPU.Build.0 = Release|Any CPU
{1A0B75E2-ECCE-47F3-A8FB-79F48F76E9A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A0B75E2-ECCE-47F3-A8FB-79F48F76E9A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A0B75E2-ECCE-47F3-A8FB-79F48F76E9A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A0B75E2-ECCE-47F3-A8FB-79F48F76E9A1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1EA5AF67-3A7C-4B6B-BE39-837D683F5AB3}
EndGlobalSection
EndGlobal

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EF_LoL
{
public class ChampionDBContext : DbContext
{
public ChampionDBContext()
{ }
public ChampionDBContext(DbContextOptions<ChampionDBContext> options)
: base(options)
{ }
//ChampionEntity champ1 = new ChampionEntity("Bob");
//ChampionEntity champ2 = new ChampionEntity("Fanta");
public DbSet<ChampionEntity> ChampionEntity { get; set; }
//protected override void OnConfiguring(DbContextOptionsBuilder options)
// => options.UseSqlite("Data Source= EF_LoL.MyDataBase.db");
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
if (!options.IsConfigured)
{
options.UseSqlite("Data Source= EF_LoL.MyDataBase.db");
}
}
}
}

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;
namespace EF_LoL
{
public class ChampionEntity
{
//dotnet ef database update --context ChampionDBContext --project EF_LoL
[Key]
public string Name
{
get => name;
private init
{
if (string.IsNullOrWhiteSpace(value))
{
name = "Unknown";
return;
}
name = value;
}
}
private readonly string name = null!;
public string Bio
{
get => bio;
set
{
if (value == null)
{
bio = "";
return;
}
bio = value;
}
}
private string bio = "";
public string Icon { get; set; }
public ChampionEntity(string name, string icon = "", string bio = "")
{
Name = name;
Icon = icon;
Bio = bio;
///Characteristics = new ReadOnlyDictionary<string, int>(characteristics);
}
///public ReadOnlyDictionary<string, int> Characteristics { get; private set; }
///private readonly Dictionary<string, int> characteristics = new Dictionary<string, int>();
// creer table avec db context et db set de champion
// puis ajout d'un nouveau champion
// pour ajouté un attribut : supprimer nos migrations et nos db
public override bool Equals(object? obj)
{
if (ReferenceEquals(obj, null)) return false;
if (ReferenceEquals(obj, this)) return true;
if (GetType() != obj.GetType()) return false;
return Equals(obj as ChampionEntity);
}
public override int GetHashCode()
=> Name.GetHashCode() % 997;
public bool Equals(ChampionEntity? other)
=> Name.Equals(other?.Name);
public override string ToString()
{
StringBuilder sb = new StringBuilder($"{Name}");
if (!string.IsNullOrWhiteSpace(bio))
{
sb.AppendLine($"\t{bio}");
}
return sb.ToString();
}
///// Characteristique
////public void AddCharacteristics(params Tuple<string, int>[] someCharacteristics)
////{
//// foreach (var c in someCharacteristics)
//// {
//// characteristics[c.Item1] = c.Item2;
//// }
////}
////public bool RemoveCharacteristics(string label)
//// => characteristics.Remove(label);
////public int? this[string label]
////{
//// get
//// {
//// if (!characteristics.TryGetValue(label, out int value)) return null;
//// else return value;
//// }
//// set
//// {
//// if (!value.HasValue)
//// {
//// RemoveCharacteristics(label);
//// return;
//// }
//// characteristics[label] = value.Value;
//// }
////}
}
}

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

@ -0,0 +1,42 @@
// <auto-generated />
using EF_LoL;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace EFLoL.Migrations
{
[DbContext(typeof(ChampionDBContext))]
[Migration("20230204093038_MyMigration")]
partial class MyMigration
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
modelBuilder.Entity("EF_LoL.ChampionEntity", b =>
{
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Bio")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Icon")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Name");
b.ToTable("ChampionEntity");
});
#pragma warning restore 612, 618
}
}
}

@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace EFLoL.Migrations
{
/// <inheritdoc />
public partial class MyMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ChampionEntity",
columns: table => new
{
Name = table.Column<string>(type: "TEXT", nullable: false),
Bio = table.Column<string>(type: "TEXT", nullable: false),
Icon = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ChampionEntity", x => x.Name);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ChampionEntity");
}
}
}

@ -0,0 +1,39 @@
// <auto-generated />
using EF_LoL;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace EFLoL.Migrations
{
[DbContext(typeof(ChampionDBContext))]
partial class ChampionDBContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
modelBuilder.Entity("EF_LoL.ChampionEntity", b =>
{
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Bio")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Icon")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Name");
b.ToTable("ChampionEntity");
});
#pragma warning restore 612, 618
}
}
}

@ -0,0 +1,28 @@
// See https://aka.ms/new-console-template for more information
using EF_LoL;
Console.WriteLine("Hello, World!");
ChampionEntity chewie = new ChampionEntity("Chewbacca");
ChampionEntity yoda = new ChampionEntity ("Yoda");
ChampionEntity ewok = new ChampionEntity ("Ewok");
using (var context = new ChampionDBContext())
{
// Crée des Champion et les insère dans la base
Console.WriteLine("Creates and inserts new Champion");
context.ChampionEntity.Add(chewie);
context.ChampionEntity.Add(yoda);
context.ChampionEntity.Add(ewok);
context.SaveChanges();
}
using (var context = new ChampionDBContext())
{
foreach (var n in context.ChampionEntity)
{
Console.WriteLine($"{n.Name} - {n.Bio} [ {n.Icon} ]");
}
context.SaveChanges();
}

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EF_LoL\EF_LoL.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,45 @@
using EF_LoL;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using Xunit;
namespace TestProject
{
public class UnitTest1
{
[Fact]
public void Test1()
{
var options = new DbContextOptionsBuilder<ChampionDBContext>()
.UseInMemoryDatabase(databaseName: "Add_Test_database")
.Options;
//prepares the database with one instance of the context
using (var context = new ChampionDBContext(options))
{
ChampionEntity chewie = new ChampionEntity("Chewbacca");
ChampionEntity yoda = new ChampionEntity("Yoda");
ChampionEntity ewok = new ChampionEntity("Ewok");
Console.WriteLine("Creates and inserts new Champion for tests");
context.ChampionEntity.Add(chewie);
context.ChampionEntity.Add(yoda);
context.ChampionEntity.Add(ewok);
context.SaveChanges();
}
//prepares the database with one instance of the context
using (var context = new ChampionDBContext(options))
{
Assert.Equal(3, context.ChampionEntity.Count());
Assert.Equal("Chewbacca", context.ChampionEntity.First().Name);
}
}
}
}

@ -0,0 +1 @@
global using Xunit;

@ -1,81 +1,156 @@
# :alien: Consomation et Développement de services :construction_worker:
# Projet d'Entity FrameWork et Consomation et Développement de services
Notre projet à pour objectif la liaison entre une base de donnée et un client, par l'utilisation d' ``EntityFramework`` et d'une ``API`` C#.
![C#](https://img.shields.io/badge/c%23-%23239120.svg?style=for-the-badge&logo=c-sharp&logoColor=white)
![JWT](https://img.shields.io/badge/JWT-black?style=for-the-badge&logo=JSON%20web%20tokens)
![Markdown](https://img.shields.io/badge/markdown-%23000000.svg?style=for-the-badge&logo=markdown&logoColor=white)
#### :steam_locomotive: Comment lancer le projet ?
> (Explication...) :construction:
> *A noter que seul la v1 est prise en compte, la v2 et v2.2 ne sont presentes uniquement pour prouver notre capacité à versionner*
### Ce projet est decoupé en deux parties :
# :alien: Consomation et Développement de services
### :checkered_flag: État des livrables :
#### :checkered_flag: Etat des livrables :
:construction:
>:heavy_check_mark: Mise en place de toutes les opérations CRUD
>:heavy_check_mark: API RESTful (respect des règles de routage, utilisation des bons status code ...)
>:heavy_exclamation_mark: Utilisation des fichiers configurations
>:heavy_check_mark: Versionnage de l'api (avec versionnage de la doc)
>:construction: Logs
>:heavy_check_mark: Tests unitaires
> :heavy_exclamation_mark: Réalisation du client MAUI et liaison avec l'api
>:heavy_check_mark:Liaison avec la base de données
>:heavy_check_mark:Filtrage + Pagination des données
>:construction: Propreté du code (Vous pouvez vous servir de sonarqube)
>:heavy_check_mark: Dockerisation et Hébergement des API (CodeFirst)
> * :heavy_check_mark: Mise en place de toutes les opérations CRUD
> * :heavy_check_mark: API RESTful (respect des règles de routage, utilisation des bons status code ...)
> * :heavy_check_mark: Utilisation des fichiers configurations
> * :heavy_check_mark: Versionnage de l'api (avec versionnage de la doc)
> * :heavy_check_mark: Logs
> * :heavy_check_mark: Tests unitaires
> * :heavy_exclamation_mark: Réalisation du client MAUI et liaison avec l'api
> * :heavy_check_mark:Liaison avec la base de données
> * :heavy_check_mark:Filtrage + Pagination des données
> * :heavy_check_mark: Propreté du code (Vous pouvez vous servir de sonarqube)
> * :heavy_check_mark: Dockerisation et Hébergement des API (CodeFirst)
> :heavy_exclamation_mark: Sécurité
> :heavy_check_mark: Utilisation SonarQube
> * :heavy_exclamation_mark: Sécurité
> * :heavy_check_mark: Utilisation SonarQube
[![Build Status](https://codefirst.iut.uca.fr/api/badges/corentin.richard/EntityFramework_ConsoDeServices_TP/status.svg)](https://codefirst.iut.uca.fr/corentin.richard/EntityFramework_ConsoDeServices_TP)
#### Diagramme d'architechture :
=> Disponible à `./Diagramme d'architecture.jpg`
---
# :package: Entity FrameWork :construction_worker:
:construction:
# :package: Entity FrameWork
### :checkered_flag: État des livrables :
Partie 1 :
* Exo1 :
* Exo1 : :heavy_check_mark:
une base de données
une table de champion
utilisation du client console/mobile
requetes CRUD (+ tri, filtrage)
* Exo2 :
* Exo2 : :heavy_check_mark:
UT
Base de données stubbée
SQLiteInMemory
* Exo3 :
* Exo3 : :heavy_check_mark:
Déploiement EF et tests via code#0
---
Partie 2 :
* Exo4 :
* Exo4 : :heavy_check_mark:
implémentation des runes et skins (1 table -> pas de relation)
* Exo5 :
* Exo5 : :heavy_check_mark:
Relation entre champion et skin (OneToMany)
* Exo6 :
Relation entre Champion RunePage et Rune (ManyToMany)
* Exo6 : :heavy_check_mark:
Relation entre Champion, RunePage et Rune (ManyToMany)
> La relation entre Rune et RunePage à été simplifiée par manque de temps, il ne s'agit donc pas d'un dictionaire mais d'un OneToMany.
* Exo7 :
* Exo7 : :heavy_check_mark:
mapping entre model et entité (intégration de qualité)
(en 1 table et avec relations)
* Exo8 :
* Exo8 : :heavy_exclamation_mark:
Ajouter le paterne UnitOfWork (rollback en cas de probleme sur les transaction)
---
# Sujet principal :
---
### Diagramme d'architechture :
---
# prepaLoL
![](./docAsset/Diagramme%20d'architecture.jpg)
Le schéma ci-dessus décris l'architecture finale que doit avoir le projet,
# Implémentation attendue :
Tout en haut du schéma, la partie client est composé du client MAUI et et du client Console, ceux-ci permettent l'affichage des ressources, l'utilisation de l'architecture et donc de tester si tout le projet fonctionne. Celui-ci utilise le HTTPDataManager qui lui permet d'effectuer les requêtes à l'API afin de récupérer les données. Il hérite de IDataManager et peux donc être remplacé par EFDataManager, court-circuitant ainsi l'API ou par StubLib, n'utilisant pas l'API et l'EF. Le DataManager utilise l'une des extensions mapper pour convertir les objets DTO en Model.
> On indique aux client d'utiliser le HttpDataManager :
builder.Services.AddScoped<IDataManager,HTTPDataManager>();
En second, la partie API, celle-ci s'occupe de recevoir les requêtes et de renvoyer les objet en conséquent. Dans l'implémentation idéale, l'API utilise l'EFDataManger pour faire appel aux données stockés en base de données. Il hérite lui aussi de IDataManager mais ne peut être remplacé que par le StubLib.Il utilise lui aussi des extensions mapper pour convertir les objets Entity en Model.
> On indique à l'API d'utiliser le EFDataManager :
builder.Services.AddScoped<IDataManager,EFDataManager>();
Enfin, le dernier service implémenté est EntityFramework, l'ORM utilisé pour communiquer avec la base de données, celle-ci elle-même basé sur les données du StubLib grâce à la méthode HasData dans notre DbContext, il récupère et enregistre les objets Entity grâce aux DBSet d'objets. La fluent API permet de définir précisement les attributs de la base de données
# Implémentation Réelle
Actuellement, l'entiereté du projet est relié ensemble, cependant les fonctionnalités n'ont été implémentés que partielement, suite à un manque de temps nous avons préféré effectuer le squelette du projet et de relier l'ensemble plutôt que de rajouter des méthodes qui ne seraient pas utilisées.
## 1 - **Clients**
Premièrement, les clients, ils dépendent de l'implémentation de HTTPDataManager :
Le client MAUI : Suite à des difficultées de compatibilité et par manque de temps nous n'avons pas pu l'implémenter après plusieurs essais, le client console le remplace donc.
Le client console est fonctionnel mais ne peut effectuer que peu de méthodes dans sont menu textuel :
- Compter les champions
- Afficher les champions
## 2 - **API**
L'**HTTPDataManger** permet d'appeler les méthodes basiques de la partie Champion de l'API.
L'**API** ne présente qu'un seul controlleur, celui de champion. Nous avons préféré faire un seul complet plutôt que plusieurs incomplets. Celui-ci a l'utilisation des **logs**, des **codes de retours** et respecte les **règles Rest**, celui-ci implémentant les méthodes **CRUD**. Une seconde **version** est disponible pour implémenter un versionning.
La méthode GET permet le **filtrage et la pagination** des données, ces méthodes sont **testées unitairement** et l'API est **déployé** avec le projet en conteneur.
## 3 - **EntityFramework**
L'**EFDataManger** permet d'effectuer les méthodes CRUD sur EntityFramework.
L'**EntityFramework** a été implémenté avec toutes les classes **Entity** dérivant du modèle, en utilisant **OneToMany** et **ManyToMany** de facon dérivé de celle prévue. Elle est utilsé sur **base** du stub et est **testé** unitairement grâce à **SQLiteInMemory**. Ces méthodes **CRUD** sont implémentées grâce à l'utilisation de l'**EFDataManager**, le *Mapper* entre entity et model est alors requis. Enfin il est **deployé**, cependant nous n'avons pas eu le temps d'aborder le pattern ***UnitOfWork***.
# :rocket: Comment lancer le projet
## 1 - Cloner le dépot
Premièrement il faut cloner le depot git à l'addresse suivant :
git clone https://codefirst.iut.uca.fr/git/corentin.richard/EntityFramework_ConsoDeServices_TP.git
## 2 - Ouvir le projet avec VisualStudio
clique droit sur le dossier cloné > ouvrir avec Visual Studio
## 3 - Configurer le démarrage du projet
> clique droit sur le projet dans l'explorateur de solution > Configure Startup Projects ... > Multpile Startup Project
Et mettez l'action Start à LoLAPI et à ConsoleApplication(c#) ou LoLApp(MAUI)
## 4 - Lancement du projet
Vous pouvez alors lancer le projet grâce à la flèche verte, bonne navigation !
# Développeurs :
``Corentin Richard`` : **[corentin.richard@etu.uca.fr](https://codefirst.iut.uca.fr/git/corentin.richard)**
``Pierre Ferreira`` : **[pierre.ferreira@etu.uca.fr](https://codefirst.iut.uca.fr/git/pierre.ferreira)**
# Diagrammes du Model Initial
## Diagramme de classes du modèle
```mermaid

@ -0,0 +1,124 @@
using API_LoL.Mapper;
using DTO;
using EntityFramework;
using Microsoft.AspNetCore.Mvc;
using Model;
namespace API_LoL.Controllers
{
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class RunesController : ControllerBase
{
public RunesController(IDataManager Manager)
{
this.RunesManager = Manager.RunesMgr;
}
private IRunesManager RunesManager;
// GET api/<ChampionController>/5
[HttpGet("count")]
public async Task<IActionResult> GetCount()
{
return Ok(RunesManager.GetNbItems());
}
[HttpGet]
public async Task<IActionResult> Get(string? name = null, string desc = null, EnumRuneFamily Family = EnumRuneFamily.Unknown, LargeImage Image = null, int index = 0, int size = 10)
{
if (size - index > 10)
{
return BadRequest();
}
if (!string.IsNullOrEmpty(name))
{
var list = await RunesManager.GetItemsByName(name, index, size);
if (list.Count() != 0)
{
return Ok(list.Select(rune => rune?.ToDTO()));
}
else { return NoContent(); }
}
else
{
var list = await RunesManager.GetItems(index, size);
if (list.Count() != 0)
{
return Ok(list.Select(champion => champion?.ToDTO()));
}
else { return NoContent(); }
}
}
[HttpGet("name")]
public async Task<IActionResult> GetByName(String name)
{
if (string.IsNullOrEmpty(name)) return BadRequest();
var list = await RunesManager.GetItemsByName(name, 0, 1);
if (list.Count() == 1)
{
return Ok(list.Select(rune => rune?.ToDTO()).First());
}
else { return NoContent(); }
}
// POST api/<ChampionController>
[HttpPost]
public async Task<IActionResult> Post(RuneDTO rune)
{
if (rune == null)
{
return UnprocessableEntity();
}
else
{
var champ = await RunesManager.GetItemsByName(rune.Name, 0, 1);
if(champ.Count() > 0)
if (champ.Where(c => c.Name == rune.Name).Count() == 1)
{
return Conflict(rune);
}
await RunesManager.AddItem(rune.ToRune());
return CreatedAtAction("Post", rune);
}
}
// PUT api/<ChampionController>/5
[HttpPut("name")]
public async Task<IActionResult> Put(string name, RuneDTO rune)
{
if (string.IsNullOrEmpty(name))
return BadRequest();
if (rune == null)
return UnprocessableEntity();
var list = await RunesManager.GetItemsByName(name, 0, 1);
if (list.Count() == 1)
{
return Ok(RunesManager.UpdateItem(list.First(), rune.ToRune()));
}
else { return NoContent(); }
}
// DELETE api/<ChampionController>/5
[HttpDelete("name")]
public async Task<IActionResult> Delete(string name)
{
if (string.IsNullOrEmpty(name))
return BadRequest();
var list = await RunesManager.GetItemsByName(name, 0, 1);
if (list.Count() == 1)
{
return Ok(await RunesManager.DeleteItem(list.First()));
}
else { return NoContent(); }
}
}
}

@ -0,0 +1,19 @@
using DTO;
using Model;
namespace API_LoL.Mapper
{
public static class RuneMapper
{
public static RuneDTO ToDTO(this Rune rune)
{
return new RuneDTO(rune.Name, rune.Description, rune.Family, rune.Image, rune.Icon);
}
public static Rune ToRune(this RuneDTO rune)
{
return new Rune(rune.Name, rune.Family, rune.Icon, rune.Image.Base64, rune.Description);
}
}
}

Binary file not shown.

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

@ -0,0 +1,44 @@

using ConsoleApplication;
using EntityFramework;
using HttpClient;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Model;
var builder = WebApplication.CreateBuilder();
builder.Services.AddDbContext<LoLDBContextWithStub>();
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetService<LoLDBContextWithStub>();
context.Database.EnsureCreated();
}
IDataManager dataManager = new HttpClientManager();
string choice = "0";
while (choice != "9")
{
Utils.showMainMenu();
choice = Console.ReadLine();
switch (choice)
{
case "1":
{
Utils.championMenu(dataManager.ChampionsMgr);
break;
}
case "2":
{
//Utils.
break;
}
}
}

@ -0,0 +1,56 @@
using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication
{
public static class Utils
{
public static void showMainMenu()
{
Console.WriteLine("-------- Menu -------");
Console.WriteLine(" 1 - Champions ");
Console.WriteLine(" 2 - Skills ");
Console.WriteLine("\n 9 - Quitter");
}
public static void showChampionMenu()
{
Console.WriteLine("-------- Champion -------");
Console.WriteLine(" 1 - Count ");
Console.WriteLine(" 2 - Default ");
Console.WriteLine("\n 9 - Quitter");
}
public static async Task championMenu(IChampionsManager championsManager ) {
string choix = "0";
while (choix != "9")
{
Utils.showChampionMenu();
choix = Console.ReadLine();
switch (choix)
{
case "1":
var json = await championsManager.GetNbItems();
Console.WriteLine("# result : "+ json);
break;
case "2":
var list = await championsManager.GetItems(0, 10);
foreach(var cham in list)
{
Console.WriteLine("# result : " +cham.ToString());
}
break;
}
}
}
}
}

@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\EntityFramework\EntityFramework.csproj" />
<ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\StubLib\StubLib.csproj" />
</ItemGroup>

@ -0,0 +1,43 @@
using EntityFramework;
using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DTO
{
public class RuneDTO
{
public RuneDTO(string name, string desc, RuneFamily family, LargeImage image, string icon)
{
Name = name;
Description = desc;
Family = family;
Image = image;
Icon = icon;
}
public string Name { get; set; }
public string Description { get; set; }
public RuneFamily Family { get; set; }
public string Icon { get; set; }
public LargeImage Image { get; set; }
public bool equals(RuneDTO other)
{
return other.Name == Name
&& other.Description == Description
&& other.Family == Family
&& other.Image == Image
&& other.Icon == Icon;
}
public string toString()
{
return Name + Description + Family.ToString();
}
}
}

@ -13,8 +13,9 @@ namespace EntityFramework
public DbSet<SkinEntity> Skins { get; set; }
public DbSet<LargeImageEntity> Image { get; set; }
public DbSet<SkillEntity> Skills { get; set; }
public DbSet<LargeImageEntity> Image { get; set; }
public DbSet<RuneEntity> Rune { get; set; }
@ -46,7 +47,8 @@ namespace EntityFramework
modelBuilder.Entity<ChampionEntity>().Property(entity => entity.Name)
.IsRequired()
.HasMaxLength(50);
.HasMaxLength(50)
.ValueGeneratedOnAdd();
modelBuilder.Entity<ChampionEntity>().Property(entity => entity.Bio)
.HasMaxLength(500)
@ -76,11 +78,32 @@ namespace EntityFramework
.HasForeignKey("ChampionEntityForeignKey");
/// One to many
/// ChampionEntity ---> * SkillEntity
//création de la table ChampionEntity
//modelBuilder.Entity<ChampionEntity>().HasKey(c => c.Name); //définition de la clé primaire
//modelBuilder.Entity<ChampionEntity>().Property(c => c.Name)
// .ValueGeneratedOnAdd(); //définition du mode de génération de la clé : génération à l'insertion
//création de la table SkillEntity
modelBuilder.Entity<SkillEntity>().HasKey(s => s.Name); //définition de la clé primaire
modelBuilder.Entity<SkillEntity>().Property(s => s.Name)
.ValueGeneratedOnAdd(); //définition du mode de génération de la clé : génération à l'insertion
// Add the shadow property to the model
modelBuilder.Entity<SkillEntity>()
.Property<string>("ChampionEntityToSkillForeignKey");
// Use the shadow property as a foreign key
modelBuilder.Entity<SkillEntity>()
.HasOne(s => s.Champion)
.WithMany(c => c.Skills)
.HasForeignKey("ChampionEntityToSkillForeignKey");
// Many to Many ChampionEntity - RunePageEntity
modelBuilder.Entity<RuneEntity>().HasKey(entity => entity.Name);
/// Many to Many ChampionEntity - RunePageEntity
modelBuilder.Entity<RunePageEntity>().HasKey(entity => entity.Name);
modelBuilder.Entity<RunePageEntity>().HasKey(entity => entity.Name);
modelBuilder.Entity<RunePageEntity>().ToTable("RunePage");
@ -95,6 +118,23 @@ namespace EntityFramework
.HasMany(c => c.RunePageEntities)
.WithMany(r => r.Champion);
//.HasForeignKey("AlbumForeignKey");
//création de la table RuneEntity
modelBuilder.Entity<RuneEntity>().HasKey(r => r.Name); //définition de la clé primaire
modelBuilder.Entity<RuneEntity>().Property(r => r.Name)
.ValueGeneratedOnAdd(); //définition du mode de génération de la clé : génération à l'insertion
modelBuilder.Entity<RuneEntity>()
.Property<string>("RuneForeignKey");
modelBuilder.Entity<RuneEntity>()
.HasOne(r => r.RunePage)
.WithMany(rp => rp.Runes)
.HasForeignKey("RuneForeignKey");
}
}
}

@ -0,0 +1,225 @@
// <auto-generated />
using EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace EntityFramework.Migrations
{
[DbContext(typeof(LoLDbContext))]
[Migration("20230325150121_MigrSkill")]
partial class MigrSkill
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
modelBuilder.Entity("ChampionEntityRunePageEntity", b =>
{
b.Property<string>("ChampionName")
.HasColumnType("TEXT");
b.Property<string>("RunePageEntitiesName")
.HasColumnType("TEXT");
b.HasKey("ChampionName", "RunePageEntitiesName");
b.HasIndex("RunePageEntitiesName");
b.ToTable("ChampionEntityRunePageEntity");
});
modelBuilder.Entity("EntityFramework.ChampionEntity", b =>
{
b.Property<string>("Name")
.ValueGeneratedOnAdd()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<string>("Bio")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("string")
.HasColumnName("Bio");
b.Property<string>("Icon")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Image")
.HasColumnType("TEXT");
b.HasKey("Name");
b.ToTable("Champions", (string)null);
});
modelBuilder.Entity("EntityFramework.LargeImageEntity", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Base64")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Image");
});
modelBuilder.Entity("EntityFramework.RuneEntity", b =>
{
b.Property<string>("Name")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("RuneForeignKey")
.HasColumnType("TEXT");
b.HasKey("Name");
b.HasIndex("RuneForeignKey");
b.ToTable("Rune");
});
modelBuilder.Entity("EntityFramework.RunePageEntity", b =>
{
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("RuneName")
.HasColumnType("TEXT");
b.HasKey("Name");
b.HasIndex("RuneName");
b.ToTable("RunePage", (string)null);
});
modelBuilder.Entity("EntityFramework.SkillEntity", b =>
{
b.Property<string>("Name")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("ChampionEntityToSkillForeignKey")
.HasColumnType("TEXT");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Name");
b.HasIndex("ChampionEntityToSkillForeignKey");
b.ToTable("Skills");
});
modelBuilder.Entity("EntityFramework.SkinEntity", b =>
{
b.Property<string>("Name")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("ChampionEntityForeignKey")
.HasColumnType("TEXT");
b.Property<string>("Description")
.HasColumnType("TEXT");
b.Property<string>("Icon")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Image")
.HasColumnType("TEXT");
b.Property<float>("Price")
.HasColumnType("REAL");
b.HasKey("Name");
b.HasIndex("ChampionEntityForeignKey");
b.ToTable("Skins");
});
modelBuilder.Entity("ChampionEntityRunePageEntity", b =>
{
b.HasOne("EntityFramework.ChampionEntity", null)
.WithMany()
.HasForeignKey("ChampionName")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("EntityFramework.RunePageEntity", null)
.WithMany()
.HasForeignKey("RunePageEntitiesName")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("EntityFramework.RuneEntity", b =>
{
b.HasOne("EntityFramework.RunePageEntity", "RunePage")
.WithMany("Runes")
.HasForeignKey("RuneForeignKey");
b.Navigation("RunePage");
});
modelBuilder.Entity("EntityFramework.RunePageEntity", b =>
{
b.HasOne("EntityFramework.RuneEntity", "Rune")
.WithMany()
.HasForeignKey("RuneName");
b.Navigation("Rune");
});
modelBuilder.Entity("EntityFramework.SkillEntity", b =>
{
b.HasOne("EntityFramework.ChampionEntity", "Champion")
.WithMany("Skills")
.HasForeignKey("ChampionEntityToSkillForeignKey");
b.Navigation("Champion");
});
modelBuilder.Entity("EntityFramework.SkinEntity", b =>
{
b.HasOne("EntityFramework.ChampionEntity", "Champion")
.WithMany("skins")
.HasForeignKey("ChampionEntityForeignKey");
b.Navigation("Champion");
});
modelBuilder.Entity("EntityFramework.ChampionEntity", b =>
{
b.Navigation("Skills");
b.Navigation("skins");
});
modelBuilder.Entity("EntityFramework.RunePageEntity", b =>
{
b.Navigation("Runes");
});
#pragma warning restore 612, 618
}
}
}

@ -0,0 +1,197 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace EntityFramework.Migrations
{
/// <inheritdoc />
public partial class MigrSkill : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Champions",
columns: table => new
{
Name = table.Column<string>(type: "TEXT", maxLength: 50, nullable: false),
Bio = table.Column<string>(type: "string", maxLength: 500, nullable: false),
Icon = table.Column<string>(type: "TEXT", nullable: false),
Image = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Champions", x => x.Name);
});
migrationBuilder.CreateTable(
name: "Image",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Base64 = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Image", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Skills",
columns: table => new
{
Name = table.Column<string>(type: "TEXT", nullable: false),
Type = table.Column<int>(type: "INTEGER", nullable: false),
Description = table.Column<string>(type: "TEXT", nullable: false),
ChampionEntityToSkillForeignKey = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Skills", x => x.Name);
table.ForeignKey(
name: "FK_Skills_Champions_ChampionEntityToSkillForeignKey",
column: x => x.ChampionEntityToSkillForeignKey,
principalTable: "Champions",
principalColumn: "Name");
});
migrationBuilder.CreateTable(
name: "Skins",
columns: table => new
{
Name = table.Column<string>(type: "TEXT", nullable: false),
Description = table.Column<string>(type: "TEXT", nullable: true),
Icon = table.Column<string>(type: "TEXT", nullable: false),
Image = table.Column<string>(type: "TEXT", nullable: true),
Price = table.Column<float>(type: "REAL", nullable: false),
ChampionEntityForeignKey = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Skins", x => x.Name);
table.ForeignKey(
name: "FK_Skins_Champions_ChampionEntityForeignKey",
column: x => x.ChampionEntityForeignKey,
principalTable: "Champions",
principalColumn: "Name");
});
migrationBuilder.CreateTable(
name: "ChampionEntityRunePageEntity",
columns: table => new
{
ChampionName = table.Column<string>(type: "TEXT", nullable: false),
RunePageEntitiesName = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ChampionEntityRunePageEntity", x => new { x.ChampionName, x.RunePageEntitiesName });
table.ForeignKey(
name: "FK_ChampionEntityRunePageEntity_Champions_ChampionName",
column: x => x.ChampionName,
principalTable: "Champions",
principalColumn: "Name",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Rune",
columns: table => new
{
Name = table.Column<string>(type: "TEXT", nullable: false),
RuneForeignKey = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Rune", x => x.Name);
});
migrationBuilder.CreateTable(
name: "RunePage",
columns: table => new
{
Name = table.Column<string>(type: "TEXT", nullable: false),
RuneName = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_RunePage", x => x.Name);
table.ForeignKey(
name: "FK_RunePage_Rune_RuneName",
column: x => x.RuneName,
principalTable: "Rune",
principalColumn: "Name");
});
migrationBuilder.CreateIndex(
name: "IX_ChampionEntityRunePageEntity_RunePageEntitiesName",
table: "ChampionEntityRunePageEntity",
column: "RunePageEntitiesName");
migrationBuilder.CreateIndex(
name: "IX_Rune_RuneForeignKey",
table: "Rune",
column: "RuneForeignKey");
migrationBuilder.CreateIndex(
name: "IX_RunePage_RuneName",
table: "RunePage",
column: "RuneName");
migrationBuilder.CreateIndex(
name: "IX_Skills_ChampionEntityToSkillForeignKey",
table: "Skills",
column: "ChampionEntityToSkillForeignKey");
migrationBuilder.CreateIndex(
name: "IX_Skins_ChampionEntityForeignKey",
table: "Skins",
column: "ChampionEntityForeignKey");
migrationBuilder.AddForeignKey(
name: "FK_ChampionEntityRunePageEntity_RunePage_RunePageEntitiesName",
table: "ChampionEntityRunePageEntity",
column: "RunePageEntitiesName",
principalTable: "RunePage",
principalColumn: "Name",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Rune_RunePage_RuneForeignKey",
table: "Rune",
column: "RuneForeignKey",
principalTable: "RunePage",
principalColumn: "Name");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Rune_RunePage_RuneForeignKey",
table: "Rune");
migrationBuilder.DropTable(
name: "ChampionEntityRunePageEntity");
migrationBuilder.DropTable(
name: "Image");
migrationBuilder.DropTable(
name: "Skills");
migrationBuilder.DropTable(
name: "Skins");
migrationBuilder.DropTable(
name: "Champions");
migrationBuilder.DropTable(
name: "RunePage");
migrationBuilder.DropTable(
name: "Rune");
}
}
}

@ -0,0 +1,222 @@
// <auto-generated />
using EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace EntityFramework.Migrations
{
[DbContext(typeof(LoLDbContext))]
partial class LoLDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
modelBuilder.Entity("ChampionEntityRunePageEntity", b =>
{
b.Property<string>("ChampionName")
.HasColumnType("TEXT");
b.Property<string>("RunePageEntitiesName")
.HasColumnType("TEXT");
b.HasKey("ChampionName", "RunePageEntitiesName");
b.HasIndex("RunePageEntitiesName");
b.ToTable("ChampionEntityRunePageEntity");
});
modelBuilder.Entity("EntityFramework.ChampionEntity", b =>
{
b.Property<string>("Name")
.ValueGeneratedOnAdd()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<string>("Bio")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("string")
.HasColumnName("Bio");
b.Property<string>("Icon")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Image")
.HasColumnType("TEXT");
b.HasKey("Name");
b.ToTable("Champions", (string)null);
});
modelBuilder.Entity("EntityFramework.LargeImageEntity", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Base64")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Image");
});
modelBuilder.Entity("EntityFramework.RuneEntity", b =>
{
b.Property<string>("Name")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("RuneForeignKey")
.HasColumnType("TEXT");
b.HasKey("Name");
b.HasIndex("RuneForeignKey");
b.ToTable("Rune");
});
modelBuilder.Entity("EntityFramework.RunePageEntity", b =>
{
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("RuneName")
.HasColumnType("TEXT");
b.HasKey("Name");
b.HasIndex("RuneName");
b.ToTable("RunePage", (string)null);
});
modelBuilder.Entity("EntityFramework.SkillEntity", b =>
{
b.Property<string>("Name")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("ChampionEntityToSkillForeignKey")
.HasColumnType("TEXT");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Name");
b.HasIndex("ChampionEntityToSkillForeignKey");
b.ToTable("Skills");
});
modelBuilder.Entity("EntityFramework.SkinEntity", b =>
{
b.Property<string>("Name")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("ChampionEntityForeignKey")
.HasColumnType("TEXT");
b.Property<string>("Description")
.HasColumnType("TEXT");
b.Property<string>("Icon")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Image")
.HasColumnType("TEXT");
b.Property<float>("Price")
.HasColumnType("REAL");
b.HasKey("Name");
b.HasIndex("ChampionEntityForeignKey");
b.ToTable("Skins");
});
modelBuilder.Entity("ChampionEntityRunePageEntity", b =>
{
b.HasOne("EntityFramework.ChampionEntity", null)
.WithMany()
.HasForeignKey("ChampionName")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("EntityFramework.RunePageEntity", null)
.WithMany()
.HasForeignKey("RunePageEntitiesName")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("EntityFramework.RuneEntity", b =>
{
b.HasOne("EntityFramework.RunePageEntity", "RunePage")
.WithMany("Runes")
.HasForeignKey("RuneForeignKey");
b.Navigation("RunePage");
});
modelBuilder.Entity("EntityFramework.RunePageEntity", b =>
{
b.HasOne("EntityFramework.RuneEntity", "Rune")
.WithMany()
.HasForeignKey("RuneName");
b.Navigation("Rune");
});
modelBuilder.Entity("EntityFramework.SkillEntity", b =>
{
b.HasOne("EntityFramework.ChampionEntity", "Champion")
.WithMany("Skills")
.HasForeignKey("ChampionEntityToSkillForeignKey");
b.Navigation("Champion");
});
modelBuilder.Entity("EntityFramework.SkinEntity", b =>
{
b.HasOne("EntityFramework.ChampionEntity", "Champion")
.WithMany("skins")
.HasForeignKey("ChampionEntityForeignKey");
b.Navigation("Champion");
});
modelBuilder.Entity("EntityFramework.ChampionEntity", b =>
{
b.Navigation("Skills");
b.Navigation("skins");
});
modelBuilder.Entity("EntityFramework.RunePageEntity", b =>
{
b.Navigation("Runes");
});
#pragma warning restore 612, 618
}
}
}

@ -38,64 +38,101 @@ using ( var context = new LoLDbContext())
context.SaveChanges();
IDataManager dataManager = new EFDataManager();
IChampionsManager championsManager = dataManager.ChampionsMgr;
IEnumerable<Champion?> champions = await championsManager.GetItemsByName("A", 0, 1);
Console.WriteLine(champions.First().Name);
//using ( var context = new LoLDbContext())
//{
// //context.Add(new ChampionEntity{ Name = "test", Bio = "test", Icon = "test" } );
// context.SaveChanges();
// ChampionEntity champ = context.Find<ChampionEntity>("Akali");
// if( champ != null)
// {
// Console
// .WriteLine(champ.ToString());
// }
// else
// {
// Console.WriteLine("Not Found");
// }
// //Test BDD Skills
// ChampionEntity champSkill = new ChampionEntity { Name="nomSkill", Bio="bioSkill", Icon="iconSkill" };
// //SkillEntity s1 = new SkillEntity { Name = "Skill1", Description = "desc", Type = SkillType.Unknown };
// SkillEntity s2 = new SkillEntity { Name="Skill2", Description="desc2", Type=SkillType.Ultimate };
// SkillEntity s3 = new SkillEntity { Name = "Skill3", Description = "desc3", Type = SkillType.Passive };
// champSkill.AddSkill(new SkillEntity { Name = "Skill1", Description = "desc", Type = SkillType.Unknown });
// champSkill.AddSkill(s2);
// champSkill.AddSkill(s3);
// context.Add(champSkill);
// context.SaveChanges();
IDataManager dataManager = new EFDataManager();
IChampionsManager championsManager = dataManager.ChampionsMgr;
IEnumerable<Champion?> champions = await championsManager.GetItemsByName("A", 0, 1);
//Console.WriteLine(champions.First().Name);
//using ( var context = new LoLDbContext())
//{
// //context.Add(new ChampionEntity{ Name = "test", Bio = "test", Icon = "test" } );
// context.SaveChanges();
// ChampionEntity champ = context.Find<ChampionEntity>("Akali");
// if( champ != null)
// {
// Console
// .WriteLine(champ.ToString());
// }
// else
// {
// Console.WriteLine("Not Found");
// }
// //Test BDD Skills
// ChampionEntity champSkill = new ChampionEntity { Name="nomSkill", Bio="bioSkill", Icon="iconSkill" };
// //SkillEntity s1 = new SkillEntity { Name = "Skill1", Description = "desc", Type = SkillType.Unknown };
// SkillEntity s2 = new SkillEntity { Name="Skill2", Description="desc2", Type=SkillType.Ultimate };
// SkillEntity s3 = new SkillEntity { Name = "Skill3", Description = "desc3", Type = SkillType.Passive };
// champSkill.AddSkill(new SkillEntity { Name = "Skill1", Description = "desc", Type = SkillType.Unknown });
// champSkill.AddSkill(s2);
// champSkill.AddSkill(s3);
// context.Add(champSkill);
// context.SaveChanges();
// //OneToMany
// Console.WriteLine("Champions : ");
// foreach (var champi in context.Champions.Include(a => a.skins))
// {
// Console.WriteLine($"\t{champi.Name} : {champi.Bio}");
// foreach (var s in champi.skins)
// {
// Console.WriteLine($"\t\t{s.Name}");
// }
// }
// Console.WriteLine();
// Console.WriteLine("Skin :");
// foreach (var s in context.Skins)
// {
// Console.WriteLine($"\t{s.Name}: {s.Description} (Champion : {s.Champion.Name})");
// }
Console.WriteLine("\nAjout d'un Champion et 6 Skins...\n");
ChampionEntity captainMarvel = new ChampionEntity { Name = "Captain Marvel", Bio = "Mais que fait un avenger ici ??", Icon = "Icon.png" };
SkinEntity[] skins = { new SkinEntity {Name = "La Fiesta", Champion = captainMarvel},
new SkinEntity { Name = "Five Hundred Miles High", Champion = captainMarvel },
new SkinEntity { Name = "Captain Marvel", Champion = captainMarvel },
new SkinEntity { Name = "Time's Lie", Champion = captainMarvel },
new SkinEntity { Name = "Lush Life", Champion = captainMarvel },
new SkinEntity { Name = "Day Waves", Champion = captainMarvel }
};
foreach (var s in skins)
{
captainMarvel.skins.Add(s);
}
context.Add(captainMarvel);
context.SaveChanges();
// //OneToMany
// Console.WriteLine("Champions : ");
// foreach (var champi in context.Champions.Include(a => a.skins))
// {
// Console.WriteLine($"\t{champi.Name} : {champi.Bio}");
// foreach (var s in champi.skins)
// {
// Console.WriteLine($"\t\t{s.Name}");
// }
// }
// Console.WriteLine();
//OnetoMany Skill
ChampionEntity Levram = new ChampionEntity { Name = "Captain Levram", Bio="bio", Icon="/img" };
SkillEntity[] morceaux = { new SkillEntity { Name = "La Fiesta", Description="SkillDesc", Type=EntityFramework.SkillType.Unknown, Champion= Levram },
new SkillEntity { Name = "berserk", Description="SkillDesc1", Type=EntityFramework.SkillType.Unknown, Champion= Levram },
new SkillEntity { Name = "taunt", Description = "SkillDesc2", Type = EntityFramework.SkillType.Unknown, Champion = Levram },
new SkillEntity { Name = "fear", Description = "SkillDesc3", Type = EntityFramework.SkillType.Unknown, Champion = Levram },
new SkillEntity { Name = "flashHeal", Description = "SkillDesc4", Type = EntityFramework.SkillType.Unknown, Champion = Levram },
new SkillEntity { Name = "bubbuletp", Description = "SkillDesc5", Type = EntityFramework.SkillType.Unknown, Champion = Levram }
};
foreach (var m in morceaux)
{
Levram.Skills.Add(m);
}
context.Add(Levram);
context.SaveChanges();
// Console.WriteLine("Skin :");
// foreach (var s in context.Skins)
// {
// Console.WriteLine($"\t{s.Name}: {s.Description} (Champion : {s.Champion.Name})");
// }
var r1 = new RuneEntity { Name = "Rune1", Description = "aaa", Family = EnumRuneFamily.Domination, Image = new LargeImage("base") };
@ -109,24 +146,4 @@ Console.WriteLine(champions.First().Name);
context.Champions.AddRange(new[] { corichard, pintrand });
context.RunePage.AddRange(new[] { rp1, rp2 });
context.SaveChanges();
}
// Console.WriteLine("\nAjout d'un Champion et 6 Skins...\n");
// ChampionEntity captainMarvel = new ChampionEntity { Name = "Captain Marvel", Bio="Mais que fait un avenger ici ??", Icon="Icon.png"};
// SkinEntity[] skins = { new SkinEntity {Name = "La Fiesta", Champion = captainMarvel},
// new SkinEntity { Name = "Five Hundred Miles High", Champion = captainMarvel },
// new SkinEntity { Name = "Captain Marvel", Champion = captainMarvel },
// new SkinEntity { Name = "Time's Lie", Champion = captainMarvel },
// new SkinEntity { Name = "Lush Life", Champion = captainMarvel },
// new SkinEntity { Name = "Day Waves", Champion = captainMarvel }
// };
// foreach (var s in skins)
// {
// captainMarvel.skins.Add(s);
// }
// context.Add(captainMarvel);
// context.SaveChanges();
//}
}

@ -20,5 +20,9 @@ namespace EntityFramework
public EnumRuneFamily Family;
public LargeImage Image;
//OtM
public RunePageEntity RunePage { get; set; }
}
}

@ -1,4 +1,5 @@
using System;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -16,7 +17,11 @@ namespace EntityFramework
public RuneEntity? Rune { get; set; }
//? voir si cela pause probleme
public Dictionary<EnumCategory, Rune> Dico = new Dictionary<EnumCategory, Rune>();
//public Dictionary<EnumCategory, Rune> Dico = new Dictionary<EnumCategory, Rune>();
// One to many pour l'instant, voir si on retransforme en dico :
public ICollection<RuneEntity> Runes { get; set; }
// Pour le many to many Champion *<---->* RunePage
public ICollection<ChampionEntity> Champion{ get; set; }

@ -49,5 +49,9 @@ namespace EntityFramework
// this.Description = Description;
// this.Type = Type;
//}
// One to many with champion :
public ChampionEntity Champion { get; set; }
}
}

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -8,7 +9,8 @@ namespace EntityFramework
{
public class SkinEntity //ONE TO MANY
{
[Key]
public string? Name { get; set; }
public string? Description { get; set; }

@ -42,10 +42,43 @@ namespace EntityFramework
new { Name = "ruby", ChampionEntityForeignKey = "Pintrand", Description = "So What", Icon = "/Icon.png", Price = 10.0f }
);
//Skills
modelBuilder.Entity<SkillEntity>().HasData(new { Name="Skill", Description="Desc", Type= SkillType.Basic, ChampionEntityToSkillForeignKey= "Corichard" },
new { Name = "Skill2", Description = "Desc", Type = SkillType.Basic, ChampionEntityToSkillForeignKey = "Corichard" },
new { Name = "Skill3", Description = "Desc", Type = SkillType.Passive, ChampionEntityToSkillForeignKey = "Corichard" },
new { Name = "Skill4", Description = "Desc", Type = SkillType.Unknown, ChampionEntityToSkillForeignKey = "Corichard" },
new { Name = "Skill5", Description = "Desc", Type = SkillType.Basic, ChampionEntityToSkillForeignKey = "Corichard" },
new { Name = "Skill6", Description = "Desc", Type = SkillType.Basic, ChampionEntityToSkillForeignKey = "Corichard" },
new { Name = "Skill10", Description = "Desc", Type = SkillType.Basic, ChampionEntityToSkillForeignKey = "Pintrand" },
new { Name = "Skill11", Description = "Desc", Type = SkillType.Unknown, ChampionEntityToSkillForeignKey = "Pintrand" },
new { Name = "Skill12", Description = "Desc", Type = SkillType.Passive, ChampionEntityToSkillForeignKey = "Pintrand" },
new { Name = "Skill13", Description = "Desc", Type = SkillType.Basic, ChampionEntityToSkillForeignKey = "Pintrand" },
new { Name = "Skill14", Description = "Desc", Type = SkillType.Basic, ChampionEntityToSkillForeignKey = "Pintrand" }
);
modelBuilder.Entity<RunePageEntity>().HasData(new { Name = "RP1", Rune = r1, Champion = corichard},
new { Name = "RP2", Rune = r2, Champion = pintrand}
);
RunePageEntity rp11 = new RunePageEntity { Name = "rp11"};
RunePageEntity rp21 = new RunePageEntity { Name = "rp21"};
modelBuilder.Entity<RunePageEntity>().HasData(rp11, rp21);
modelBuilder.Entity<RuneEntity>().HasData(new { Name = "Rune", Description = "Desc", Famille = EnumRuneFamily.Domination, RuneForeignKey = "rp11" },
new{Name = "Rune2", Description = "Desc",Famille = EnumRuneFamily.Domination,RuneForeignKey = "rp11"},
new { Name = "Rune3", Description = "Desc", Famille = EnumRuneFamily.Domination, RuneForeignKey = "rp21" },
new { Name = "Rune4", Description = "Desc", Famille = EnumRuneFamily.Domination, RuneForeignKey = "rp21" }
);
}
}
}

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HttpClient
{
public class ChampionCountResponse
{
public int Result { get; set; }
public int Id { get; set; }
public object Exception { get; set; }
public int Status { get; set; }
public bool IsCanceled { get; set; }
public bool IsCompleted { get; set; }
public bool IsCompletedSuccessfully { get; set; }
public int CreationOptions { get; set; }
public object AsyncState { get; set; }
public bool IsFaulted { get; set; }
}
}

@ -1,4 +1,6 @@
using Model;
using DTO;
using DTO.Mapper;
using Model;
using System;
using System.Collections.Generic;
using System.Linq;
@ -34,20 +36,23 @@ namespace HttpClient
public async Task<Champion?> AddItem(Champion? item) //return le champion ajouté, null sinon ?
{
if(item==null) throw new ArgumentNullException("item is null");
var response = await httpc.PostAsJsonAsync("/Champion?Name = " + item.Name, item);
var response = await httpc.PostAsJsonAsync("v1/Champions?Name = " + item.Name, item);
return response.IsSuccessStatusCode ? item : null;
}
public async Task<bool> DeleteItem(Champion? item)
{
HttpResponseMessage response = await httpc.DeleteAsync("/Champion?Name=" + item.Name);
HttpResponseMessage response = await httpc.DeleteAsync("v1/Champions?Name=" + item.Name);
_ = response.StatusCode;
return response.IsSuccessStatusCode;
}
public Task<IEnumerable<Champion?>> GetItems(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)
{
return httpc.GetFromJsonAsync<IEnumerable<Champion>>("/Champion?index="+index+"&size="+count);
IEnumerable<ChampionDTO> champdto = await httpc.GetFromJsonAsync<IEnumerable<ChampionDTO>>("v1/Champions?index="+index+"&size="+count);
return champdto.Select(c => c.ToChampion());
}
@ -66,28 +71,35 @@ namespace HttpClient
public Task<IEnumerable<Champion?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
return httpc.GetFromJsonAsync<IEnumerable<Champion>>("/Champion?name="+substring+"&index=" + index + "&size=" + count);
return httpc.GetFromJsonAsync<IEnumerable<Champion>>("v1/Champions?name=" + substring+"&index=" + index + "&size=" + count);
}
public Task<IEnumerable<Champion?>> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null, bool descending = false)
public async Task<int> GetNbItems()
{
throw new NotImplementedException();
//HttpResponseMessage response =
//Console.WriteLine(response.Content.ToString());
//return int.Parse(response.Content.ToString());
//return await httpc.GetFromJsonAsync<int>("v1/Champions/count");
var response = await httpc.GetFromJsonAsync<ChampionCountResponse>("v1/Champions/count");
return response.Result;
}
public Task<IEnumerable<Champion?>> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false)
public Task<IEnumerable<Champion?>> GetItemsByRunePage(RunePage? runePage, 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 Task<IEnumerable<Champion?>> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbItems()
public Task<IEnumerable<Champion?>> GetItemsBySkill(string skill, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbItemsByCharacteristic(string charName)
{
@ -119,9 +131,13 @@ namespace HttpClient
throw new NotImplementedException();
}
public Task<Champion?> UpdateItem(Champion? oldItem, Champion? newItem)
public async Task<Champion?> UpdateItem(Champion? oldItem, Champion? newItem)
{
throw new NotImplementedException();
HttpResponseMessage rep = await httpc.PutAsJsonAsync("v1/Champions?name=" + oldItem.Name, newItem.ToDTO());
if (rep.IsSuccessStatusCode) return newItem;
//else
return null;
}
}
}

@ -8,8 +8,6 @@ namespace HttpClient
public System.Net.Http.HttpClient httpC { get; set; } = new System.Net.Http.HttpClient();
public string BaseAddress;
public HttpClientManager() {
ChampionsMgr = new ChampionManager(this, httpC);

@ -26,7 +26,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Api_UT", "Api_UT\Api_UT.csp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EF_UT", "EF_UT\EF_UT.csproj", "{74F469C3-A94A-4507-9DC7-7DBADCD18173}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpClient", "HttpClient\HttpClient.csproj", "{DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpClient", "HttpClient\HttpClient.csproj", "{DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{6570AF99-3E74-4CAA-AEB0-EEFE4F79780F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApplication", "ConsoleApplication\ConsoleApplication.csproj", "{53A195F7-FB7C-44E8-AB82-4D775C7D9477}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -70,6 +74,10 @@ Global
{DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}.Release|Any CPU.Build.0 = Release|Any CPU
{53A195F7-FB7C-44E8-AB82-4D775C7D9477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53A195F7-FB7C-44E8-AB82-4D775C7D9477}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53A195F7-FB7C-44E8-AB82-4D775C7D9477}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53A195F7-FB7C-44E8-AB82-4D775C7D9477}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -78,6 +86,7 @@ Global
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {2C607793-B163-4731-A4D1-AFE8A7C4C170}
{20A1A7DC-1E93-4506-BD32-8597A5DADD7B} = {C76D0C23-1FFA-4963-93CD-E12BD643F030}
{74F469C3-A94A-4507-9DC7-7DBADCD18173} = {C76D0C23-1FFA-4963-93CD-E12BD643F030}
{53A195F7-FB7C-44E8-AB82-4D775C7D9477} = {6570AF99-3E74-4CAA-AEB0-EEFE4F79780F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {92F3083D-793F-4552-8A9A-0AD6534159C9}

@ -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,99 @@
<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="..\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,39 @@
using CommunityToolkit.Maui;
using LolApp.ViewModels;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
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();
}
}
}

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" data-testid="overview:roleicon" class="style__StyledSpecsIcon-sc-8gkpub-17-SvgAssassin ckFmqk"><path d="M56.59 73.71l1.67-2.88c5.75-9.34 5.51-16 3.83-20.59a39.78 39.78 0 01-9.1 16 2 2 0 01-1.43.48H48.2a2.17 2.17 0 01-1.67-.72 39.78 39.78 0 01-9.1-16c-1.68 4.55-1.68 11.26 3.83 20.59l1.68 2.88-3.36 5.75 10.06 17.72L59.7 79.22z"></path><path d="M73.11 38.74c-3.35-4.31-6-10-6-18.91 0-4.07-3.59-8.15-7.66-12-4.79-4.31-5.75-5.74-9.58-5.74s-4.79 1.43-9.34 5.74c-4.07 3.83-7.66 7.91-7.66 12 0 8.86-2.88 14.6-6 18.68L12.76 52.87 2.23 45.69v12.93S2.47 84 39.58 97.89c0 0-14.13-7.18-16.28-31.13-.24-1.67-.24-9.1-.24-10.29A119.77 119.77 0 0036.71 74c-.72-1.2-1.44-2.64-2.16-3.83-5-10.54-4.07-18.2-1.67-23.47a22.77 22.77 0 017.42-8.86l9.58 9.58 9.58-9.58a22.77 22.77 0 017.42 8.86c2.4 5.27 3.59 12.93-1.43 23.23-.72 1.38-1.45 2.58-2.16 4.07a119.77 119.77 0 0013.65-17.53c0 1.19 0 8.62-.24 10.29-2.39 23.95-16.28 31.13-16.28 31.13C97.53 84 97.77 58.62 97.77 58.62V45.69l-10.53 7.18z"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" data-testid="overview:roleicon" class="style__StyledSpecsIcon-sc-8gkpub-17-SvgFighter ggYKyo"><path d="M67.84 56.35v5.5c8.62-8.62 14.37 0 14.37 0C112.14 40.78 90.35 2 90.35 2s-.72 17.24-15.08 27.77v16.52c-.24 4.79-3.84 7.9-7.43 10.06M17.79 62.09s4.07-6.46 10.78-2.63L20.91 48.2l6.7-16c-17.24-10.54-18-29.93-18-29.93S-12.14 41 17.79 62.09M26.89 83.89l5.51-18.68-.24-.48L19.23 77.9A17.78 17.78 0 017.5 83.17H3l-1 2.39 12 11.5zM92.27 83.89a16.24 16.24 0 01-11.74-5.27L68.8 66.88l3.83 17.72L85.8 98l12-11.49-1-2.4zM55.87 42.7c0 .24-.24.48-.24.71h.72c5.75.48 7.66 2.64 9.1 7.67a9.35 9.35 0 002.39-1.92c1-1 1.68-1.67 1.68-2.63V28.09a2 2 0 00-1.68-1.92l-31.37-5.74H36a2.39 2.39 0 00-2.39 2.39v6.71l24.9 3.35z"></path><path d="M60.18 54c-1.2-5.27-1.44-4.55-5.75-4.79L40.78 48v-3.87h5.51A4.09 4.09 0 0050.36 41l1-3.35L32.4 35l-5 12.22 11.74 17-5.54 18.47L49.88 98l16.53-15.07s-6.23-28.5-6.23-29M49.88 2.23l-4.79 10.29 4.79 3.83 4.79-3.83zM62.1 9.41l1.43 6h6l2.87-11zM30.25 15.4h6l.24-.72 1.2-5.27-10.3-5z"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" data-testid="overview:roleicon" class="style__StyledSpecsIcon-sc-8gkpub-17-SvgMage VdIXV"><path d="M84.48 77.3h13.41l-3.83-12.93h-9.58a36.73 36.73 0 00-27.54 12.45L50 85l-6.94-8.14a36.73 36.73 0 00-27.54-12.49H5.94L2.11 77.3h13.41a36.73 36.73 0 0127.54 12.45l.71.72h-9.1v7.42h30.9v-7.42h-9.1l.71-.72a35.85 35.85 0 0127.3-12.45"></path><path d="M56.23 54.31L50 62.21l-6.23-7.9a5.42 5.42 0 01-.24-6.47L50 37.31l6.47 10.53a5.42 5.42 0 01-.24 6.47M42.58 28.93l-7.91 12.69a13.37 13.37 0 00.72 15.09L50 75.14l14.61-18.43a13 13 0 00.72-15.09L50 17l-.48.72a5.58 5.58 0 01-4.31 1.68c-4.07 0-7.18-8.62 4.55-17.24 0 0-28.74 5.5-14.85 30.41z"></path></svg>

After

Width:  |  Height:  |  Size: 706 B

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" data-testid="overview:roleicon" class="style__StyledSpecsIcon-sc-8gkpub-17-SvgMarksman hdOPMH"><path d="M28.69 27.25h6.94l1.92-6.94-13.41-7.91zM71.31 27.25l4.55-14.85-13.41 7.91 1.92 6.94zM71.31 35.39c-1.43 0-12.21-3.83-12.21-3.83L50 42.34l-9.1-10.78s-10.54 3.83-12.21 3.83c-7.67 0-4.79-7.18-4.79-7.18S4.26 48.32 2.11 64.13c0 0 5.74-8.86 24.42-13.17a26.22 26.22 0 0013.89 12.93c-.72-3.11-1.44-6.71-2.15-10.06a22.36 22.36 0 01-3.84-4.31c.72 0 7.19-.72 8.15-.72.71 2.64 4.55 28.74 4.55 28.74l-7 10.3v10L50 93.82l9.82 4.07V87.6l-7-10.3s3.84-26.1 4.55-28.74c.72 0 7.19.72 8.15.72a16.52 16.52 0 01-3.84 4.31 98.08 98.08 0 00-2.15 10.06 25.33 25.33 0 0013.94-12.93c18.68 4.55 24.42 13.17 24.42 13.17C95.74 48.32 76.1 28 76.1 28s2.88 7.42-4.79 7.42"></path><path d="M50 2.11l-7.66 21.31h.24L50 33.24l7.42-9.82h.24z"></path></svg>

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" data-testid="overview:roleicon" class="style__StyledSpecsIcon-sc-8gkpub-17-SvgSupport cHVWzU"><path d="M90.4 2.11c0 27.3-25.4 36.63-25.4 36.63L60.94 61a8.39 8.39 0 00-.48 2.39 6.95 6.95 0 0013.89 0 6.7 6.7 0 00-5.75-6.7c6.71-11.5 16.29-6 16.29-6 1.43-1.44 2.63-2.88 3.83-4.07l-7.19-2.88h9.34a38.5 38.5 0 005.75-11.25L87 28.69h10.3a33 33 0 00-6.9-26.58M35.32 38.74S9.93 29.41 9.93 2.11c0 0-9.82 10.77-7.42 26.1h10.3L3.23 32a41.09 41.09 0 004.07 8.9h11l-8.61 3.59a39.83 39.83 0 005.27 6s9.58-5.51 16.29 6a6.7 6.7 0 00-5.75 6.7 6.95 6.95 0 1013.41-2.39zM45.14 22.7l2.63-6.7h4.79l2.63 6.94-5 13.89zm-1-16l-7 16 10.15 25.38v23.71l-5 16 5 10H53l5-10-5-16V48.08L63.1 22.7l-7-16z"></path></svg>

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" data-testid="overview:roleicon" class="style__StyledSpecsIcon-sc-8gkpub-17-SvgTank hRKkgf"><path d="M85.92 63.89L55 90V67.48h7.42v-9.1H37.55v9.1H45v22.75L14.08 63.89 8.33 21l27.54-10.51a39.13 39.13 0 0128.26 0L91.67 21zM66.28 5a47.61 47.61 0 00-32.56 0L2.11 17.19l6.7 49.57L41.86 95A13 13 0 0050 97.89 12.5 12.5 0 0058.14 95l33.05-28.24 6.7-49.57z"></path><path d="M78.74 32.28L62 21.26v5.27H38v-5.27l-16.26 7.19a2.9 2.9 0 00-1.67 3.11l4.31 19.16a3.22 3.22 0 002.15 2.15l11.26 2.4V50h23.94v5.27l11.5-2.4a2.52 2.52 0 002.15-2.15l4.31-15.57a2.39 2.39 0 00-1-2.87M57.42 20.07H42.58L50 11.68z"></path></svg>

After

Width:  |  Height:  |  Size: 665 B

@ -0,0 +1,17 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories). Deployment of the asset to your application
is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
These files will be deployed with you package and will be accessible using Essentials:
async Task LoadMauiAsset()
{
using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
using var reader = new StreamReader(stream);
var contents = reader.ReadToEnd();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Color x:Key="Primary">#D2B977</Color>
<Color x:Key="Secondary">#F0E7B7</Color>
<Color x:Key="Tertiary">#2B0B98</Color>
<Color x:Key="White">White</Color>
<Color x:Key="Black">Black</Color>
<Color x:Key="Gray100">#E1E1E1</Color>
<Color x:Key="Gray200">#C8C8C8</Color>
<Color x:Key="Gray300">#ACACAC</Color>
<Color x:Key="Gray400">#919191</Color>
<Color x:Key="Gray500">#6E6E6E</Color>
<Color x:Key="Gray600">#404040</Color>
<Color x:Key="Gray900">#212121</Color>
<Color x:Key="Gray950">#141414</Color>
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"/>
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}"/>
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}"/>
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}"/>
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}"/>
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}"/>
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}"/>
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}"/>
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}"/>
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}"/>
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}"/>
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}"/>
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}"/>
<Color x:Key="Yellow100Accent">#F7B548</Color>
<Color x:Key="Yellow200Accent">#FFD590</Color>
<Color x:Key="Yellow300Accent">#FFE5B9</Color>
<Color x:Key="Cyan100Accent">#28C2D1</Color>
<Color x:Key="Cyan200Accent">#7BDDEF</Color>
<Color x:Key="Cyan300Accent">#C3F2F4</Color>
<Color x:Key="Blue100Accent">#3E8EED</Color>
<Color x:Key="Blue200Accent">#72ACF1</Color>
<Color x:Key="Blue300Accent">#A7CBF6</Color>
<Color x:Key="Transparent">Transparent</Color>
</ResourceDictionary>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<x:String x:Key="angle-left">&#xf104;</x:String>
<x:String x:Key="angle-right">&#xf105;</x:String>
<x:String x:Key="caret-left">&#xf0d9;</x:String>
<x:String x:Key="caret-down">&#xf0d7;</x:String>
<x:String x:Key="magnifying-glass">&#xf002;</x:String>
<x:String x:Key="plus">&#x2b;</x:String>
</ResourceDictionary>

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

Loading…
Cancel
Save