Compare commits

..

No commits in common. 'master' and 'EF2' have entirely different histories.
master ... EF2

@ -18,32 +18,6 @@ steps:
- dotnet build LeagueOfLegends.sln -c Release --no-restore - dotnet build LeagueOfLegends.sln -c Release --no-restore
- dotnet publish LeagueOfLegends.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release - dotnet publish LeagueOfLegends.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release
- name: docker-build-and-push
image: plugins/docker
settings:
dockerfile: Sources/apiLOL/Dockerfile
context: Sources/
registry: hub.codefirst.iut.uca.fr
repo: hub.codefirst.iut.uca.fr/bastien.ollier/lol
username:
from_secret: SECRET_REGISTRY_USERNAME
password:
from_secret: SECRET_REGISTRY_PASSWORD
- name: deploy-container
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
environment:
IMAGENAME: hub.codefirst.iut.uca.fr/bastien.ollier/lol:latest
CONTAINERNAME: container_lol
COMMAND: create
OVERWRITE: true
username:
from_secret: SECRET_REGISTRY_USERNAME
password:
from_secret: SECRET_REGISTRY_PASSWORD
- name: tests - name: tests
image: mcr.microsoft.com/dotnet/sdk:6.0 image: mcr.microsoft.com/dotnet/sdk:6.0
commands: commands:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

@ -1,85 +1,168 @@
# Projet d'Entity FrameWork et Consomation et Développement de services sur League Of Legends # prepaLoL
Ce projet est un travail universitaire réalisé durant la deuxième année de BUT à Clermont-Ferrand. Il correspond au travail demandé dans le cadre du cours regroupant Entity Framework et Consommation et Developpement de Services. ## Diagramme de classes du modèle
```mermaid
![League Of Legends](./Docs/imageCodeFirst/frontImageReadMe.jpg) classDiagram
class LargeImage{
Explique ce qu'on a fait et ce qu'on a pas fait et pourquoi on a priorisé ca plutot que d'autre +/Base64 : string
}
class Champion{
# :zap: Consommation et Développement de services +/Name : string
+/Bio : string
Voici l'état des différentes tâches liées à la consommation et au développement de services : +/Icon : string
+/Characteristics : Dictionary~string, int~
~ AddSkin(skin : Skin) bool
> * :white_check_mark: La mise en place de toutes les opérations CRUD est terminée. ~ RemoveSkin(skin: Skin) bool
> * :white_check_mark: Une API RESTful a été mise en place en respectant les règles de routage et en utilisant les bons codes de statut. + AddSkill(skill: Skill) bool
> * :white_check_mark: La version de l'API a été gérée de manière appropriée. + RemoveSkill(skill: Skill) bool
> * :white_check_mark: Les logs ont été implémentés. + AddCharacteristics(someCharacteristics : params Tuple~string, int~[])
> * :construction: Les tests unitaires sont en cours de réalisation. + RemoveCharacteristics(label : string) bool
> * :construction: La création du client MAUI et sa liaison avec l'API sont en cours de réalisation. + this~label : string~ : int?
> * :white_check_mark: La liaison avec la base de données est opérationnelle. }
> * :white_check_mark: Le filtrage et la pagination des données ont été implémentés. Champion --> "1" LargeImage : Image
> * :white_check_mark: Le code est de qualité grâce à l'utilisation de SonarQube. class ChampionClass{
> * :white_check_mark: L'API a été dockerisée et hébergée sur CodeFirst. <<enumeration>>
> * :construction: Sécurité Unknown,
Assassin,
`Note : Le client MAUI n'a pas été réalisé par manque de temps. Les tests unitaires et la sécurité sont réalisés au fur et à mesure de l'avancement du projet.` Fighter,
Mage,
Marksman,
--- Support,
Tank,
}
# :zap: Entity Framework : Champion --> "1" ChampionClass : Class
class Skin{
Voici l'état des différentes tâches liées à Entity Framework : +/Name : string
+/Description : string
> * :white_check_mark: **Exercice 1** : Une base de données a été créée avec une table pour les champions, et des requêtes CRUD ont été implémentées, ainsi que du filtrage et de la pagination. Le client console n'a pas été réalisé pour cet exercice par manque de temps. +/Icon : string
> * :white_check_mark: **Exercice 2** : Des tests unitaires ont été écrits et une base de données a été simulée à l'aide de SQLiteInMemory. +/Price : float
> * :white_check_mark: **Exercice 3** : Entity Framework a été déployé et les tests ont été effectués via Code#0. }
> * :white_check_mark: **Exercice 4**: Les tables pour les runes et les skins ont été implémentées (sans les relations). Skin --> "1" LargeImage : Image
> * :white_check_mark: **Exercice 5** : Une relation OneToMany a été établie entre les champions et les skins. Champion "1" -- "*" Skin
> * :white_check_mark: **Exercice 6** : Une relation ManyToMany a été établie entre les champions, les rune pages et les runes. class Skill{
> * :construction: **Exercice 7** : Le mapping entre le modèle et l'entité a été réalisé pour améliorer la qualité du code. +/Name : string
> * :construction: **Exercice 8** : La mise en place du pattern UnitOfWork n'a pas pu être implémentée par manque de temps. +/Description : string
--- }
class SkillType{
<<enumeration>>
### Diagramme d'architechture : Unknown,
Basic,
![Diagramme d'architechture](./Docs/imageCodeFirst/DiagrammeArchitecture.png) Passive,
Ultimate,
}
#### Partie Client : Skill --> "1" SkillType : Type
Champion --> "*" Skill
La partie client qui n'a pas pu être réalisé dans notre cas, est sensée être constituée du client MAUI et du client Console, qui affichent les ressources et testent l'architecture en utilisant le HTTPDataManager pour effectuer des requêtes à l'API et récupérer des données. class Rune{
+/Name : string
#### DataManager : +/Description : string
}
Le DataManager utilise l'une des extensions mapper pour convertir les objets DTO en Model, et peut être remplacé par EFDataManager ou StubLib. Rune --> "1" LargeImage : Image
class RuneFamily{
#### Partie API : <<enumeration>>
Unknown,
La partie API reçoit les requêtes et renvoie les objets en conséquence, en utilisant l'EFDataManager pour accéder aux données stockées en base de données. La fluent API permet de définir précisément les attributs de la base de données. Precision,
Domination
#### Entity Framework : }
L'EntityFramework est implémenté avec toutes les classes Entity dérivant du modèle, en utilisant OneToMany et ManyToMany de manière dérivée de celle prévue. Les méthodes CRUD sont implémentées grâce à l'utilisation de l'EFDataManager et le Mapper entre entity et model est requis. Rune --> "1" RuneFamily : Family
class Category{
#### Déploiement : <<enumeration>>
Le projet est déployé avec le projet en conteneur, mais le pattern UnitOfWork n'a pas été abordé. Major,
Minor1,
# :tada: Comment lancer le projet Minor2,
Minor3,
## 1 - Cloner le dépot OtherMinor1,
OtherMinor2
Cloner le dépôt Git en utilisant la commande suivante : }
class RunePage{
git clone https://codefirst.iut.uca.fr/git/bastien.ollier/LOL.git +/Name : string
+/this[category : Category] : Rune?
## 2 - Configurer le démarrage du projet - CheckRunes(newRuneCategory : Category)
- CheckFamilies(cat1 : Category, cat2 : Category) bool?
> Configurer le projet de démarrage en cliquant sur "Projet de démarrage" à gauche de la flèche verte, puis en sélectionnant l'option "apiLOL". - UpdateMajorFamily(minor : Category, expectedValue : bool)
}
## 3 - Lancement du projet RunePage --> "*" Rune : Dictionary~Category,Rune~
```
Le projet est maintenant prêt à être lancé. Vous pouvez commencer à faire des requêtes sur la base de données via l'API.
## Diagramme de classes des interfaces de gestion de l'accès aux données
```mermaid
classDiagram
direction LR;
class IGenericDataManager~T~{
<<interface>>
GetNbItems() Task~int~
GetItems(index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~T~~
GetNbItemsByName(substring : string)
GetItemsByName(substring : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~T~~
UpdateItem(oldItem : T, newItem : T) Task~T~~
AddItem(item : T) Task~T~
DeleteItem(item : T) Task~bool~
}
class IChampionsManager{
<<interface>>
GetNbItemsByCharacteristic(charName : string)
GetItemsByCharacteristic(charName : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
GetNbItemsByClass(championClass : ChampionClass)
GetItemsByClass(championClass : ChampionClass, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
GetNbItemsBySkill(skill : Skill?)
GetItemsBySkill(skill : Skill?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
GetNbItemsBySkill(skill : string)
GetItemsBySkill(skill : string, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
GetNbItemsByRunePage(runePage : RunePage?)
GetItemsByRunePage(runePage : RunePage?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Champion?~~
}
class ISkinsManager{
<<interface>>
GetNbItemsByChampion(champion : Champion?)
GetItemsByChampion(champion : Champion?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Skin?~~
}
class IRunesManager{
<<interface>>
GetNbItemsByFamily(family : RuneFamily)
GetItemsByFamily(family : RuneFamily, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~Rune?~~
}
class IRunePagesManager{
<<interface>>
GetNbItemsByRune(rune : Rune?)
GetItemsByRune(rune : Rune?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~RunePage?~~
GetNbItemsByChampion(champion : Champion?)
GetItemsByChampion(champion : Champion?, index : int, count : int, orderingPropertyName : string?, descending : bool) Task~IEnumerable~RunePage?~~
}
IGenericDataManager~Champion?~ <|.. IChampionsManager : T--Champion?
IGenericDataManager~Skin?~ <|.. ISkinsManager : T--Skin?
IGenericDataManager~Rune?~ <|.. IRunesManager : T--Rune?
IGenericDataManager~RunePage?~ <|.. IRunePagesManager : T--RunePage?
class IDataManager{
<<interface>>
}
IChampionsManager <-- IDataManager : ChampionsMgr
ISkinsManager <-- IDataManager : SkinsMgr
IRunesManager <-- IDataManager : RunesMgr
IRunePagesManager <-- IDataManager : RunePagesMgr
```
## Diagramme de classes simplifié du Stub
```mermaid
classDiagram
direction TB;
IDataManager <|.. StubData
ChampionsManager ..|> IChampionsManager
StubData --> ChampionsManager
RunesManager ..|> IRunesManager
StubData --> RunesManager
RunePagesManager ..|> IRunePagesManager
StubData --> RunePagesManager
SkinsManager ..|> ISkinsManager
StubData --> SkinsManager
StubData --> RunesManager
StubData --> "*" Champion
StubData --> "*" Rune
StubData --> "*" RunePages
StubData --> "*" Skins
```

@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore; using Model;
using Model;
namespace EFLol.DBDataManager namespace EFLol.DBDataManager
@ -19,21 +18,18 @@ namespace EFLol.DBDataManager
{ {
private MyDbContext _context; private MyDbContext _context;
public EFChampionManager()
{
_context = new MyDbContext();
}
public async Task<Champion?> AddItem(Champion? item) public async Task<Champion?> AddItem(Champion? item)
{ {
if (item == null) if (item == null)
{ {
throw new Exception("Item is null"); return null;
} }
var addItem = await _context.AddAsync(item);
await _context.SaveChangesAsync();
return addItem.Entity;
_context.Add(item.ChampionToEntity()); // Va chercher les info du context (Context.champions.get)(DbSet) et les map en champion model
_context.SaveChanges(); // Dans Program.cs de API rajouter un scope (AddScope <IDataManager, EFDataManager>) -> Ca va dire que a chaque fois que j'utilise un IDataManager, il va créer un EFDataManager
return item;
} }
@ -43,74 +39,49 @@ namespace EFLol.DBDataManager
{ {
return false; return false;
} }
var deletedItem = _context.Remove(item);
var champ = _context.Champions.Select(c => c == item.ChampionToEntity()); await _context.SaveChangesAsync();
if (champ.Count() < 1)
{
return false;
}
_context.Champions.Remove(item.ChampionToEntity());
_context.SaveChanges();
return true; return true;
} }
private Func<Champion, string, bool> filterByName = (champion, substring) =>
champion.Name.Contains(substring, StringComparison.InvariantCultureIgnoreCase);
public async Task<Champion?> UpdateItem(Champion? oldItem, Champion? newItem)
{ public Task<Champion?> UpdateItem(Champion? oldItem, Champion? newItem)
if (oldItem != null && newItem != null)
{
var champEntity = await _context.Champions.FirstOrDefaultAsync(c => c.Name == oldItem.Name);
if (champEntity == null)
{ {
throw new Exception("Champion not found in database"); throw new NotImplementedException();
}
champEntity.Bio = newItem.Bio;
_context.SaveChanges();
return champEntity.ChampionToPoco();
}
throw new Exception("Invalid input parameters");
} }
public Task<int> GetNbItems()
{
throw new NotImplementedException();
}
public async Task<int> GetNbItems() => _context.Champions.Count(); public async 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)
{ {
IEnumerable<Champion> champions = _context.Champions.Skip(index * count) IEnumerable<Champion> champions = _context.Champions.Skip(index * count).Take(count).OrderBy(champion => orderingPropertyName).Select(champion => champion.ChampionToPoco());
.Take(count)
.OrderBy(champions => orderingPropertyName)
.Select(champions => champions.ChampionToPoco());
return champions; return champions;
} }
private Func<Champion, string, bool> filterByName = (champion, substring) =>
champion.Name.IndexOf(substring, StringComparison.InvariantCultureIgnoreCase) >= 0;
public Task<IEnumerable<Champion?>> GetItemsByName(string substring, int index, int count,
string? orderingPropertyName = null, bool descending = false)
=> _context.Champions.Select(champion => champion.ChampionToPoco())
.GetItemsWithFilterAndOrdering(champ => filterByName(champ, substring), index, count,
orderingPropertyName, descending);
public Task<int> GetNbItemsByName(string substring) public Task<int> GetNbItemsByName(string substring)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<IEnumerable<Champion?>> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null,
bool @descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbItemsByCharacteristic(string charName) public Task<int> GetNbItemsByCharacteristic(string charName)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<IEnumerable<Champion?>> GetItemsByCharacteristic(string charName, int index, int count, public Task<IEnumerable<Champion?>> GetItemsByCharacteristic(string charName, int index, int count, string? orderingPropertyName = null,
string? orderingPropertyName = null,
bool @descending = false) bool @descending = false)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
@ -121,8 +92,7 @@ namespace EFLol.DBDataManager
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<IEnumerable<Champion?>> GetItemsByClass(ChampionClass championClass, int index, int count, public Task<IEnumerable<Champion?>> GetItemsByClass(ChampionClass championClass, int index, int count, string? orderingPropertyName = null,
string? orderingPropertyName = null,
bool @descending = false) bool @descending = false)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
@ -133,8 +103,7 @@ namespace EFLol.DBDataManager
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<IEnumerable<Champion?>> GetItemsBySkill(Skill? skill, int index, int count, public Task<IEnumerable<Champion?>> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool @descending = false)
string? orderingPropertyName = null, bool @descending = false)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -144,8 +113,7 @@ namespace EFLol.DBDataManager
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<IEnumerable<Champion?>> GetItemsByRunePage(RunePage? runePage, int index, int count, public Task<IEnumerable<Champion?>> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null,
string? orderingPropertyName = null,
bool @descending = false) bool @descending = false)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
@ -156,8 +124,7 @@ namespace EFLol.DBDataManager
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<IEnumerable<Champion?>> GetItemsBySkill(string skill, int index, int count, public Task<IEnumerable<Champion?>> GetItemsBySkill(string skill, int index, int count, string? orderingPropertyName = null, bool @descending = false)
string? orderingPropertyName = null, bool @descending = false)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFLol.DBDataManager
{
static class ExtensionsDataManager
{
internal static Task<IEnumerable<T?>> GetItemsWithFilterAndOrdering<T>(this IEnumerable<T> collection,
Func<T, bool> filter, int index, int count, string? orderingPropertyName = null, bool descending = false)
{
IEnumerable<T> temp = collection;
temp = temp.Where(item => filter(item));
if (orderingPropertyName != null)
{
var prop = typeof(T).GetProperty(orderingPropertyName!);
if (prop != null)
{
temp = descending
? temp.OrderByDescending(item => prop.GetValue(item))
: temp.OrderBy(item => prop.GetValue(item));
}
}
return Task.FromResult<IEnumerable<T?>>(temp.Skip(index * count).Take(count));
}
internal static Task<int> GetNbItemsWithFilter<T>(this IEnumerable<T> collection, Func<T, bool> filter)
{
return Task.FromResult(collection.Count(item => filter(item)));
}
internal static Task<T?> AddItem<T>(this IList<T> collection, T? item)
{
if (item == null || collection.Contains(item))
{
return Task.FromResult<T?>(default(T));
}
collection.Add(item);
return Task.FromResult<T?>(item);
}
internal static Task<bool> DeleteItem<T>(this IList<T> collection, T? item)
{
if (item == null)
{
return Task.FromResult(false);
}
bool result = collection.Remove(item!);
return Task.FromResult(result);
}
internal static Task<T?> UpdateItem<T>(this IList<T> collection, T? oldItem, T? newItem)
{
if (oldItem == null || newItem == null) return Task.FromResult<T?>(default(T));
if (!collection.Contains(oldItem))
{
return Task.FromResult<T?>(default(T));
}
collection.Remove(oldItem!);
collection.Add(newItem!);
return Task.FromResult<T?>(newItem);
}
}
}

@ -26,7 +26,7 @@ namespace EFLol
{ {
if (!optionsBuilder.IsConfigured) if (!optionsBuilder.IsConfigured)
{ {
optionsBuilder.UseSqlite("Data Source=../EFLol/loldb.db"); optionsBuilder.UseSqlite("Data Source=loldb.db");
} }
} }

@ -28,7 +28,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "apiLOL", "apiLOL\apiLOL.csp
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFLol", "EFLol\EFLol.csproj", "{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFLol", "EFLol\EFLol.csproj", "{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUnitaire", "TestUnitaire\TestUnitaire.csproj", "{5702F240-97BD-4757-918C-6E485C57D0EC}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUnitaire", "TestUnitaire\TestUnitaire.csproj", "{5702F240-97BD-4757-918C-6E485C57D0EC}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA} = {65B824B5-FADB-4C89-8B4B-D541B62B7DCA} {65B824B5-FADB-4C89-8B4B-D541B62B7DCA} = {65B824B5-FADB-4C89-8B4B-D541B62B7DCA}
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7} = {7AEE66D2-490B-4049-B9D3-C629D7F78DA7} {7AEE66D2-490B-4049-B9D3-C629D7F78DA7} = {7AEE66D2-490B-4049-B9D3-C629D7F78DA7}

@ -1,142 +0,0 @@
<?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>

@ -1,13 +0,0 @@
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);
}
}

@ -1,73 +0,0 @@
<?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>

@ -1,24 +0,0 @@
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);
}
}

@ -1,36 +0,0 @@
<?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>

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

@ -1,18 +0,0 @@
<?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>

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

@ -1,21 +0,0 @@
<?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>

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

@ -1,185 +0,0 @@
<?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>

@ -1,31 +0,0 @@
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});
}
}
}

@ -1,196 +0,0 @@
<?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>

@ -1,17 +0,0 @@
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;
}
}

@ -1,131 +0,0 @@
<?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>

@ -1,34 +0,0 @@
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);
}
}

@ -1,38 +0,0 @@
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);
}
}

@ -1,99 +0,0 @@
<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>

@ -1,37 +0,0 @@
<?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>

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

@ -1,39 +0,0 @@
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();
}
}

@ -1,7 +0,0 @@
<?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>

@ -1,11 +0,0 @@
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
{
}

@ -1,16 +0,0 @@
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();
}

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

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

@ -1,36 +0,0 @@
<?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>

@ -1,16 +0,0 @@
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));
}
}

@ -1,17 +0,0 @@
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);
}
}

@ -1,15 +0,0 @@
<?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>

@ -1,9 +0,0 @@
<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>

@ -1,25 +0,0 @@
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();
}

@ -1,47 +0,0 @@
<?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>

@ -1,16 +0,0 @@
<?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>

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

@ -1,38 +0,0 @@
<?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>

@ -1,16 +0,0 @@
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));
}
}

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

@ -1,8 +0,0 @@
<?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>

@ -1,34 +0,0 @@
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);
}
}
}

@ -1,42 +0,0 @@
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();
}
}
}

@ -1,28 +0,0 @@
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();
}
}
}

@ -1,28 +0,0 @@
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();
}
}
}

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.0 KiB

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 706 B

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 665 B

@ -1,17 +0,0 @@
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.

Before

Width:  |  Height:  |  Size: 228 KiB

@ -1,46 +0,0 @@
<?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>

@ -1,13 +0,0 @@
<?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>

@ -1,102 +0,0 @@
<?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"
xmlns:conv="clr-namespace:LolApp.Resources.Converters"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit">
<x:Double x:Key="imageRatio">0.59</x:Double>
<Style TargetType="Button" x:Key="iconButton">
<Setter Property="Margin" Value="4"/>
<Setter Property="Padding" Value="10"/>
</Style>
<Style TargetType="Label" x:Key="defaultLabel">
<Setter Property="HorizontalOptions" Value="Center"/>
<Setter Property="HorizontalTextAlignment" Value="Center"/>
<Setter Property="FontSize" Value="{OnPlatform Medium}"/>
<Setter Property="Margin" Value="10"/>
</Style>
<Style TargetType="Label" x:Key="title">
<Setter Property="HorizontalOptions" Value="Center"/>
<Setter Property="HorizontalTextAlignment" Value="Center"/>
<Setter Property="FontSize" Value="{OnPlatform Title}"/>
<Setter Property="TextColor" Value="{StaticResource Primary}"/>
<Setter Property="Margin" Value="0, 10, 0, 4"/>
<Setter Property="FontAttributes" Value="Bold"/>
</Style>
<Style TargetType="Label" x:Key="labelForEntry">
<Setter Property="HorizontalOptions" Value="End"/>
<Setter Property="VerticalOptions" Value="Center"/>
<Setter Property="HorizontalTextAlignment" Value="End"/>
<Setter Property="FontSize" Value="{OnPlatform Small}"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="TextColor" Value="{StaticResource Primary}"/>
</Style>
<Style TargetType="Entry" x:Key="defaultEntry">
<Setter Property="BackgroundColor" Value="{StaticResource Secondary}"/>
<Setter Property="VerticalOptions" Value="Center"/>
<Setter Property="HorizontalOptions" Value="FillAndExpand"/>
<Setter Property="PlaceholderColor" Value="{StaticResource Gray300}"/>
<Setter Property="Margin" Value="6"/>
<Setter Property="FontSize" Value="{OnPlatform Small}"/>
</Style>
<Style TargetType="Editor" x:Key="defaultEditor">
<Setter Property="BackgroundColor" Value="{StaticResource Secondary}"/>
<Setter Property="VerticalOptions" Value="FillAndExpand"/>
<Setter Property="HorizontalOptions" Value="FillAndExpand"/>
<Setter Property="PlaceholderColor" Value="{StaticResource Gray300}"/>
<Setter Property="Margin" Value="6"/>
<Setter Property="FontSize" Value="{OnPlatform Small}"/>
</Style>
<Style TargetType="Picker" x:Key="defaultPicker">
<Setter Property="BackgroundColor" Value="{StaticResource Secondary}"/>
<Setter Property="VerticalOptions" Value="Center"/>
<Setter Property="HorizontalOptions" Value="FillAndExpand"/>
<Setter Property="Margin" Value="6"/>
<Setter Property="FontSize" Value="{OnPlatform Small}"/>
</Style>
<Style x:Key="InvalidEntryStyle" TargetType="Entry" BasedOn="{StaticResource defaultEntry}">
<Setter Property="TextColor" Value="Red" />
</Style>
<conv:PlusOneConverter x:Key="plusOneConverter"/>
<conv:Base64ToImageSourceConverter x:Key="base64ToImageSourceConverter"/>
<conv:ImageRatioConverter x:Key="imageRatioConverter"/>
<conv:ChampionClassToIconConverter x:Key="championClassToIconConverter"/>
<toolkit:SelectedItemEventArgsConverter x:Key="SelectedItemEventArgsConverter" />
<toolkit:BoolToObjectConverter TrueObject="{StaticResource caret-down}"
FalseObject="{StaticResource caret-left}"
DefaultConvertReturnValue="{StaticResource caret-left}"
x:Key="isExpandedToCaretConverter"/>
<toolkit:IntToBoolConverter x:Key="intToBoolConverter"/>
<toolkit:IsStringNotNullOrWhiteSpaceConverter x:Key="isStringNotNullOrWhiteSpaceConverter"
DefaultConvertReturnValue="False"/>
<toolkit:IsStringNullOrWhiteSpaceConverter x:Key="isStringNullOrWhiteSpaceConverter"/>
<toolkit:MultiMathExpressionConverter x:Key="multiMathExpressionConverter" />
<toolkit:IsEqualConverter x:Key="isEqualConverter" />
<toolkit:MathExpressionConverter x:Key="mathExpressionConverter"/>
<toolkit:BoolToObjectConverter TrueObject="{StaticResource Primary}"
FalseObject="{StaticResource Transparent}"
x:Key="isSelectedToColorConverter"/>
<toolkit:MultiConverter x:Key="selectedIconToColorConverter">
<toolkit:IsEqualConverter />
<toolkit:BoolToObjectConverter FalseObject="{StaticResource Primary}"
TrueObject="{StaticResource Black}"/>
</toolkit:MultiConverter>
<toolkit:IsListNotNullOrEmptyConverter x:Key="isListNotNullOrEmptyConverter"/>
<toolkit:IsListNullOrEmptyConverter x:Key="isListNullOrEmptyConverter"/>
<toolkit:InvertedBoolConverter x:Key="invertedBoolConverter"/>
</ResourceDictionary>

@ -1,406 +0,0 @@
<?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">
<Style TargetType="ActivityIndicator">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="IndicatorView">
<Setter Property="IndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}"/>
<Setter Property="SelectedIndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray100}}"/>
</Style>
<Style TargetType="Border">
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="StrokeShape" Value="Rectangle"/>
<Setter Property="StrokeThickness" Value="1"/>
</Style>
<Style TargetType="BoxView">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Button">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Primary}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="CornerRadius" Value="8"/>
<Setter Property="Padding" Value="14,10"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="CheckBox">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="DatePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Editor">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Entry">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Frame">
<Setter Property="HasShadow" Value="False" />
<Setter Property="BorderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="CornerRadius" Value="8" />
</Style>
<Style TargetType="ImageButton">
<Setter Property="Opacity" Value="1" />
<Setter Property="BorderColor" Value="Transparent"/>
<Setter Property="BorderWidth" Value="0"/>
<Setter Property="CornerRadius" Value="0"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Opacity" Value="0.5" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ListView">
<Setter Property="SeparatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="RefreshControlColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Picker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ProgressBar">
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RadioButton">
<Setter Property="BackgroundColor" Value="Transparent"/>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RefreshView">
<Setter Property="RefreshColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="SearchBar">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="CancelButtonColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SearchHandler">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Shadow">
<Setter Property="Radius" Value="15" />
<Setter Property="Opacity" Value="0.5" />
<Setter Property="Brush" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
<Setter Property="Offset" Value="10,10" />
</Style>
<Style TargetType="Slider">
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SwipeItem">
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
</Style>
<Style TargetType="Switch">
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="ThumbColor" Value="{StaticResource White}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="On">
<VisualState.Setters>
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Secondary}, Dark={StaticResource Gray200}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Off">
<VisualState.Setters>
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="TimePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent"/>
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Page" ApplyToDerivedTypes="True">
<Setter Property="Padding" Value="0"/>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
</Style>
<Style TargetType="Shell" ApplyToDerivedTypes="True">
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource Gray950}}" />
<Setter Property="Shell.ForegroundColor" Value="{OnPlatform WinUI={StaticResource Primary}, Default={StaticResource White}}" />
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="Shell.UnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray200}}" />
<Setter Property="Shell.NavBarHasShadow" Value="False" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource Gray950}}" />
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
<Setter Property="IconColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="TabbedPage">
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray950}}" />
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="UnselectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="SelectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
</ResourceDictionary>

@ -1,46 +0,0 @@
<?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.SkinPage"
Title="SkinPage"
x:Name="root"
BackgroundColor="{StaticResource Black}">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Modifier" Command="{Binding AppVM.NavigateToEditSkinPageCommand, 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}"
ColumnDefinitions="*, Auto">
<Label Text="{Binding Name}" FontAttributes="Bold" TextColor="{StaticResource Primary}"
FontSize="Title"/>
<HorizontalStackLayout Grid.Column="1">
<Image Source="rp.png" HeightRequest="16" WidthRequest="16"/>
<Label Text="{Binding Price}" TextColor="{StaticResource Primary}"
FontSize="Small" VerticalOptions="Center" Margin="4, 0, 0, 0"/>
</HorizontalStackLayout>
</Grid>
<ScrollView VerticalScrollBarVisibility="Always" BackgroundColor="Black" >
<Label Text="{Binding Description}" TextColor="{StaticResource Primary}"
Margin="10" FontAttributes="Italic"/>
</ScrollView>
</VerticalStackLayout>
</ScrollView>
</ContentPage>

@ -1,18 +0,0 @@
using LolApp.ViewModels;
using ViewModels;
namespace LolApp;
public partial class SkinPage : ContentPage
{
public ApplicationVM AppVM { get; set; }
public SkinVM SkinVM { get; }
public SkinPage(SkinVM svm, ApplicationVM appVM)
{
BindingContext = SkinVM = svm;
AppVM = appVM;
InitializeComponent();
}
}

@ -1,80 +0,0 @@
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
//using Microsoft.Maui.Graphics.Platform;
using ViewModels;
namespace LolApp.ViewModels
{
[ObservableObject]
public partial class AddChampionPageVM
{
ChampionsMgrVM ChampionsMgrVM { get; }
public AddChampionPageVM(ChampionsMgrVM championsMgrVM, ChampionVM champion = null)
{
ChampionsMgrVM = championsMgrVM;
if(champion == null) return;
oldChampion = champion;
IsNew = false;
this.champion = new EditableChampionVM(oldChampion);
}
private ChampionVM oldChampion;
[ObservableProperty]
bool isNew = true;
[ObservableProperty]
EditableChampionVM champion = new ();
[RelayCommand]
public async void PickIcon() => Champion.IconBase64 = await PickIconsAndImagesUtils.PickPhoto(42);
[RelayCommand]
public async void PickLargeImage() => Champion.LargeImageBase64 = await PickIconsAndImagesUtils.PickPhoto(1000);
[RelayCommand]
async Task Cancel()
=> await App.Current.MainPage.Navigation.PopAsync();
[RelayCommand]
async Task AddChampion()
{
ChampionVM champVM = Champion.ToChampionVM();
await ChampionsMgrVM.AddChampion(champVM);
await App.Current.MainPage.Navigation.PopAsync();
}
[RelayCommand]
async Task EditChampion()
{
ChampionVM newChampion = Champion.ToChampionVM();
await ChampionsMgrVM.EditChampion(oldChampion, newChampion);
await App.Current.MainPage.Navigation.PopAsync();
}
[ObservableProperty]
string newCharacteristicDescription;
[ObservableProperty]
int newCharacteristicValue;
[RelayCommand]
void AddCharacteristic()
{
Champion?.AddCharacteristic(newCharacteristicDescription, newCharacteristicValue);
}
[RelayCommand]
void RemoveCharacteristic(KeyValuePair<string, int> characteristic)
=> Champion?.RemoveCharacteristic(characteristic);
[RelayCommand]
async Task AddSkill()
=> await App.Current.MainPage.Navigation.PushModalAsync(new AddSkill(Champion));
}
}

@ -1,64 +0,0 @@
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Model;
using ViewModels;
namespace LolApp.ViewModels
{
[ObservableObject]
public partial class AddOrEditSkinPageVM
{
SkinsMgrVM SkinsMgrVM { get; }
private SkinVM oldSkin;
[ObservableProperty]
bool isNew = true;
[ObservableProperty]
EditableSkinVM skin;
public AddOrEditSkinPageVM(SkinsMgrVM skinsMgrVM, SkinVM oldSkin)
{
SkinsMgrVM = skinsMgrVM;
this.oldSkin = oldSkin;
IsNew = false;
this.skin = new EditableSkinVM(oldSkin);
}
public AddOrEditSkinPageVM(SkinsMgrVM skinsMgrVM, ChampionVM champion)
{
SkinsMgrVM = skinsMgrVM;
skin = new EditableSkinVM(champion);
}
[RelayCommand]
public async void PickIcon() => Skin.IconBase64 = await PickIconsAndImagesUtils.PickPhoto(42);
[RelayCommand]
public async void PickLargeImage() => Skin.LargeImageBase64 = await PickIconsAndImagesUtils.PickPhoto(1000);
[RelayCommand]
async Task Cancel()
=> await App.Current.MainPage.Navigation.PopAsync();
[RelayCommand]
async Task AddSkin()
{
SkinVM skinVM = Skin.ToSkinVM();
await SkinsMgrVM.AddSkin(skinVM);
await App.Current.MainPage.Navigation.PopAsync();
}
[RelayCommand]
async Task EditSkin()
{
SkinVM newSkin = Skin.ToSkinVM();
await SkinsMgrVM.EditSkin(oldSkin, newSkin);
await App.Current.MainPage.Navigation.PopAsync();
}
}
}

@ -1,46 +0,0 @@
using System;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Model;
using ViewModels;
namespace LolApp.ViewModels
{
public partial class AddSkillVM : ObservableObject
{
public AddSkillVM(EditableChampionVM champion)
{
Champion = champion;
}
[ObservableProperty]
SkillType skillType;
[ObservableProperty]
string name;
[ObservableProperty]
string description;
[ObservableProperty]
EditableChampionVM champion;
[RelayCommand]
async void AddSkillToChampion()
{
champion.Skills.Add(new SkillVM(new Skill(name, skillType, description)));
await App.Current.MainPage.Navigation.PopModalAsync();
}
[RelayCommand]
async void Cancel()
{
await App.Current.MainPage.Navigation.PopModalAsync();
}
public IEnumerable<SkillType> AllSkills { get; }
= Enum.GetValues(typeof(SkillType)).Cast<SkillType>().Except(new SkillType[] {SkillType.Unknown}).ToList();
}
}

@ -1,58 +0,0 @@
using System;
using CommunityToolkit.Mvvm.Input;
using Model;
using ViewModels;
namespace LolApp.ViewModels
{
public partial class ApplicationVM
{
public ChampionsMgrVM ChampionsMgrVM { get; set; }
public SkinsMgrVM SkinsMgrVM { get; set; }
public ApplicationVM(ChampionsMgrVM championsMgrVM, SkinsMgrVM skinsMgrVM)
{
ChampionsMgrVM = championsMgrVM;
SkinsMgrVM = skinsMgrVM;
}
[RelayCommand]
async Task NavigateToChampionDetailsPage(ChampionVM cvm)
{
SkinsMgrVM.Champion = cvm;
SkinsMgrVM.Index = 0;
SkinsMgrVM.Count = 5;
await SkinsMgrVM.LoadSkinsCommand.ExecuteAsync(cvm);
await App.Current.MainPage.Navigation.PushAsync(new ChampionPage(cvm, this));
}
[RelayCommand]
async Task NavigateToAddNewChampionPage()
=> await App.Current.MainPage.Navigation.PushAsync(new AddChampionPage(ChampionsMgrVM));
[RelayCommand(CanExecute = nameof(CanNavigateToEditChampionPage))]
async Task NavigateToEditChampionPage(object champ)
=> await App.Current.MainPage.Navigation.PushAsync(new AddChampionPage(ChampionsMgrVM, champ as ChampionVM));
bool CanNavigateToEditChampionPage(object champ) => champ != null && champ is ChampionVM;
[RelayCommand]
async Task NavigateToSkinDetailsPage(object svm)
{
if (svm == null || svm is not SkinVM) return;
await App.Current.MainPage.Navigation.PushAsync(new SkinPage(svm as SkinVM, this));
}
[RelayCommand]
async Task NavigateToAddNewSkinPage(ChampionVM champion)
=> await App.Current.MainPage.Navigation.PushAsync(new AddOrEditSkinPage(SkinsMgrVM, champion));
[RelayCommand(CanExecute = nameof(CanNavigateToEditSkinPage))]
async Task NavigateToEditSkinPage(object skin)
=> await App.Current.MainPage.Navigation.PushAsync(new AddOrEditSkinPage(SkinsMgrVM, skin as SkinVM));
bool CanNavigateToEditSkinPage(object skin) => skin != null && skin is SkinVM;
}
}

@ -1,27 +0,0 @@
using System;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using Model;
namespace LolApp.ViewModels
{
[ObservableObject]
public partial class ChampionClassVM
{
[ObservableProperty]
private ChampionClass model;
[ObservableProperty]
private bool isSelected;
public ChampionClassVM(ChampionClass model)
{
Model = model;
}
public static IEnumerable<ChampionClassVM> Classes { get; }
= Enum.GetValues(typeof(ChampionClass)).Cast<ChampionClass>().Except(new ChampionClass[] {ChampionClass.Unknown})
.Select(cc => new ChampionClassVM(cc));
}
}

@ -1,111 +0,0 @@
using System;
using System.Reflection;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Model;
using ViewModels;
namespace LolApp.ViewModels
{
[ObservableObject]
public partial class ChampionsPageVM
{
public ChampionsMgrVM ChampionsMgrVM { get; set; }
public ChampionsPageVM(ChampionsMgrVM championsMgrVM)
{
ChampionsMgrVM = championsMgrVM;
PropertyChanged += ChampionsMgrVM_PropertyChanged;
}
[ObservableProperty]
private ChampionClassVM selectedClass;
[RelayCommand]
public async Task SelectedChampionClassChanged(ChampionClassVM champClass)
{
if(SelectedClass != null) SelectedClass.IsSelected = false;
if(champClass.Model == ChampionClass.Unknown
|| champClass.Model == SelectedClass?.Model)
{
SelectedClass = null;
return;
}
SelectedClass = champClass;
SelectedClass.IsSelected = true;
await ChampionsMgrVM.LoadChampionsByClass(SelectedClass.Model);//ChampionsMgrVM.SelectedClass);
}
[ObservableProperty]
private ChampionVM selectedChampion;
[ObservableProperty]
private string searchedName;
[ObservableProperty]
private string searchedSkill;
[ObservableProperty]
private string searchedCharacteristic;
private static string[] searchedStrings = { nameof(SearchedName), nameof(SearchedSkill), nameof(SearchedCharacteristic), nameof(SelectedClass) };
private async void ChampionsMgrVM_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if(searchedStrings.Any(s => e.PropertyName == s))
{
if(GetProperty(e.PropertyName).GetValue(this) != GetProperty(e.PropertyName).GetDefaultValue())
{
foreach(string s in searchedStrings.Except(new string[]{e.PropertyName }))
{
var prop = GetProperty(s);
prop.ResetPropertyValue(this);
}
return;
}
ChampionsMgrVM.Index=0;
if(searchedStrings.All(s => GetProperty(s).GetValue(this) == GetProperty(s).GetDefaultValue()))
{
await ChampionsMgrVM.LoadChampions();
}
}
}
private PropertyInfo? GetProperty(string propName)
=> typeof(ChampionsPageVM).GetProperty(propName);
}
public static class Extensions
{
public static void ResetPropertyValue(this PropertyInfo pi, ChampionsPageVM instance)
{
if(pi.PropertyType == typeof(ChampionClassVM))
{
var temp = pi.GetValue(instance);
if(temp != null)
(temp as ChampionClassVM).IsSelected = false;
return;
}
pi.SetValue(instance, pi.GetDefaultValue());
}
public static object GetDefaultValue(this Type t)
{
if (t.IsValueType)
return Activator.CreateInstance(t);
return null;
}
public static object GetDefaultValue(this PropertyInfo pi)
=> pi.PropertyType.GetDefaultValue();
}
}

@ -1,32 +0,0 @@
using System;
//using Microsoft.Maui.Graphics.Platform;
using Microsoft.Maui.Graphics.Skia;
namespace LolApp.ViewModels
{
public static class PickIconsAndImagesUtils
{
public async static Task<string> PickPhoto(float maxWidthAndHeight)
{
FileResult photo = await MediaPicker.Default.PickPhotoAsync();
return photo != null ? await ToBase64(photo, maxWidthAndHeight) : null;
}
public async static Task<string> ToBase64(FileResult photo, float maxWidthAndHeight)
{
using (var stream = await photo.OpenReadAsync())
using (var memoryStream = new MemoryStream())
{
var image = SkiaImage.FromStream(memoryStream);
//var image = PlatformImage.FromStream(stream);
if(image != null)
{
var newImage = image.Downsize(maxWidthAndHeight, true);
return newImage.AsBase64();
}
}
return null;
}
}
}

@ -1,5 +1,5 @@
using apiLOL;
using apiLOL.Controllers; using apiLOL.Controllers;
using apiLOL.DTO;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
@ -10,103 +10,50 @@ namespace TestUnitaire
public class TestAPILol public class TestAPILol
{ {
[Theory] [Theory]
[InlineData("Beatrice", "sdfsdfd", "icon.png")] [InlineData("Beatrice", "sdfsdfd")]
[InlineData("Maurice", "Ahri est un champion de League of Legends", "icon.png")] [InlineData("Maurice", "Ahri est un champion de League of Legends")]
[InlineData("Loupiotte", "Akali est un champion de League of Legends", "icon.png")] [InlineData("Loupiotte", "Akali est un champion de League of Legends")]
public async Task TestPostChampion(string name, string bio, string icon) public async Task TestPostChampion(string name, string bio)
{ {
// Arrange // Arrange
var data = new StubData(); var data = new StubData();
var logger = new NullLogger<ControllerChampions>(); var logger = new NullLogger<ControllerChampions>();
var controller = new ControllerChampions(data, logger); var controller = new ControllerChampions(data, logger);
var champDTO = new ChampionDTO(name, bio, icon); var champDTO = new ChampionDTO(name, bio);
// Act // Act
var nbInListBefore = data.ChampionsMgr.GetNbItems().Result; var nbInListBefore = data.ChampionsMgr.GetNbItems().Result;
var result = await controller.AddChampion(champDTO); var result = await controller.Post(champDTO);
var nbInListAfter = data.ChampionsMgr.GetNbItems().Result; var nbInListAfter = data.ChampionsMgr.GetNbItems().Result;
// Assert // Assert
// IS the champion added to the list, number of champions in the list + 1 // IS the champion added to the list, number of champions in the list + 1
Assert.Equal(nbInListBefore + 1, nbInListAfter); Assert.Equal(nbInListBefore + 1, nbInListAfter);
// Test le code de retour
} }
[Theory] [Theory]
[InlineData("Beatrice", "Aatrox est un champion de League of Legends", "icon.png")] [InlineData("Beatrice", "Aatrox est un champion de League of Legends")]
[InlineData("Maurice", "Ahri est un champion de League of Legends", "icon.png")] [InlineData("Maurice", "Ahri est un champion de League of Legends")]
[InlineData("Loupiotte", "Akali est un champion de League of Legends", "icon.png")] [InlineData("Loupiotte", "Akali est un champion de League of Legends")]
public async Task TestGetChampion(string name, string bio, string icon) public async Task TestGetChampion(string name, string bio)
{ {
// Arrange // Arrange
var data = new StubData(); var data = new StubData();
var logger = new NullLogger<ControllerChampions>(); var logger = new NullLogger<ControllerChampions>();
var controller = new ControllerChampions(data, logger); var controller = new ControllerChampions(data, logger);
var champDTO = new ChampionDTO(name, bio, icon); var champDTO = new ChampionDTO(name, bio);
// Act // Act
// Call method POST to add a champion // Call method POST to add a champion
var result = await controller.AddChampion(champDTO); var result = await controller.Post(champDTO);
// Call method GET to get the champion // Call method GET to get the champion
var resultGet = await controller.GetChampionByName(name); var resultGet = await controller.GetChampion(name);
// Assert // Assert
// IS the champion added to the list, number of champions in the list + 1
Assert.Equal(name, champDTO.Name); Assert.Equal(name, champDTO.Name);
Assert.Equal(bio, champDTO.Bio); Assert.Equal(bio, champDTO.Bio);
} }
[Theory]
[InlineData("Beatrice", "Nouvelle bio")]
[InlineData("Maurice", "Nouvelle bio")]
[InlineData("Loupiotte", "Nouvelle bio")]
public async Task TestPutChampion(string name, string bio)
{
// Method that change the bio of a champion. Make a test to check if the bio is changed
// Arrange
var data = new StubData();
var logger = new NullLogger<ControllerChampions>();
var controller = new ControllerChampions(data, logger);
// Act
// Add a champion
var champDTO = new ChampionDTO(name, "Ancienne bio", "icon.png");
var resultPost = await controller.AddChampion(champDTO);
// Call method PUT to change the bio of a champion
var resultPut = await controller.UpdateChampion(name, bio);
var champion = (await data.ChampionsMgr.GetItemsByName(name, 0, 1)).First();
var bioOfChampion = champion.Bio;
// Assert
// Does the bio of the champion is changed
Assert.Equal(bio, bioOfChampion);
}
[Theory]
[InlineData("Beatrice")]
[InlineData("Maurice")]
[InlineData("Loupiotte")]
public async Task TestDeleteChampion(string name)
{
// Method that delete a champion. Make a test to check if the champion is deleted
// Arrange
var data = new StubData();
var logger = new NullLogger<ControllerChampions>();
var controller = new ControllerChampions(data, logger);
// Act
// Add a champion
var champDTO = new ChampionDTO(name, "Ancienne bio", "icon.png");
var resultPost = await controller.AddChampion(champDTO);
// Call method DELETE to delete the champion
var resultDelete = await controller.DeleteChampion(name);
// Assert
// Does the type of the result is a OkObjectResult
Assert.IsType<OkObjectResult>(resultDelete);
}
} }
} }

@ -0,0 +1,37 @@
using apiLOL;
using apiLOL.Controllers;
using Microsoft.AspNetCore.Mvc;
using StubLib;
namespace TestUnitaire
{
public class TestAPILol
{
[Fact]
public void Test1()
{
}
[Fact]
public void TestPostChampion()
{
// Arrange
var data = new StubData();
var controller = new ControllerChampions(new StubData());
var champDTO = new ChampionDTO("Charles", "Charles est un champion de League of Legends");
// Act
var result = controller.Post(champDTO);
data.ChampionsMgr.AddItem(champDTO.ToModel());
var nbItem = data.ChampionsMgr.GetNbItems();
Task<int> nbItemTask = nbItem;
// Assert
Assert.IsType<OkResult>(result);
// Verify that the champions is added to the stub
Assert.Equal(7, nbItemTask.Result);
}
}
}

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestUnitaire
{
public class TestEFLol
{
public void TestAddIntoDB()
{
// Arrange
ChampionEntity Zeus = new ChampionEntity
{
Name = "Zeus",
Bio = "Zeus is the king of the gods."
};
// Act
using (var context = new ChampionContext())
{
Console.WriteLine("Adding Zeus to the database...");
context.Champions.Add(Zeus);
context.SaveChanges();
}
// Assert
using (var context = new ChampionContext())
{
var champion = context.Champions.FirstOrDefault(c => c.Name == "Zeus");
if (champion == null)
{
Assert.True(false, "Champion not found in database.");
}
Assert.NotNull(champion);
Assert.Equal("Zeus", champion.Name);
Assert.Equal("Zeus is the king of the gods.", champion.Bio);
}
}
public void TestDeleteFromDB()
{
// Act
}
}
}

@ -0,0 +1,34 @@
<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" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite" 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>
<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="..\apiLOL\apiLOL.csproj" />
</ItemGroup>
</Project>

@ -14,9 +14,6 @@
<ItemGroup> <ItemGroup>
<None Remove="Microsoft.Extensions.DependencyInjection" /> <None Remove="Microsoft.Extensions.DependencyInjection" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="ConsoleTests.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.2" />

@ -1,101 +0,0 @@
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using Model;
using Microsoft.Maui.Controls;
using System.Collections.ObjectModel;
namespace ViewModels
{
public partial class ChampionVM : ObservableObject
{
public Champion Model
{
get => model;
set
{
model = value;
OnPropertyChanged(nameof(Name));
OnPropertyChanged(nameof(Bio));
OnPropertyChanged(nameof(Class));
OnPropertyChanged(nameof(Icon));
OnPropertyChanged(nameof(Image));
OnPropertyChanged(nameof(Skills));
OnPropertyChanged(nameof(Characteristics));
}
}
private Champion model;
public ChampionVM(Champion model)
{
Model = model;
foreach(var skill in Model.Skills)
{
Skills.Add(new SkillVM(skill));
}
Skills.CollectionChanged += Skills_CollectionChanged;
}
private void Skills_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
SkillVM vm = e.NewItems?[0] as SkillVM;
switch(e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
Model.Skills.Add(new Skill(vm.Name, vm.Type, vm.Description));
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
Model.Skills.Remove(vm.Model);
break;
}
}
public string Name => Model.Name;
public ChampionClass Class
{
get => Model.Class;
set => SetProperty(Model.Class, value, newValue => Model.Class = newValue);
}
public string Bio
{
get => Model.Bio;
set => SetProperty(Model.Bio, value, newBio => Model.Bio = newBio);
}
public string Icon
{
get => Model.Icon;
set
{
SetProperty(Model.Icon, value, newIcon =>
{
Model.Icon = newIcon;
});
}
}
public string Image
{
get => Model.Image.Base64;
set
{
SetProperty(Model.Image.Base64, value, newImage =>
{
Model.Image.Base64 = newImage;
});
}
}
[ObservableProperty]
private ObservableCollection<SkillVM> skills = new ObservableCollection<SkillVM>();
public ReadOnlyDictionary<string, int> Characteristics
=> Model.Characteristics;
[ObservableProperty]
private ObservableCollection<SkinVM> skins = new ObservableCollection<SkinVM>();
}
}

@ -1,227 +0,0 @@
using System.Threading.Tasks;
using Model;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.Input;
using System.Data.SqlTypes;
using System.Reflection;
namespace ViewModels;
public partial class ChampionsMgrVM : ObservableObject
{
internal IDataManager DataMgr { get; set; }
public ChampionsMgrVM(IDataManager dataManager)
{
DataMgr = dataManager;
loadingMethods = new Dictionary<LoadingCriterium, Func<object, Task>>()
{
[LoadingCriterium.None] = async (o) => await LoadChampions(),
[LoadingCriterium.ByName] = async (o) =>
{
string substring = o as string;
if(substring == null) return;
await LoadChampionsByName(substring);
},
[LoadingCriterium.BySkill] = async (o) =>
{
string skillString = o as string;
if(skillString == null) return;
await LoadChampionsBySkill(skillString);
},
[LoadingCriterium.ByCharacteristic] = async (o) =>
{
string characString = o as string;
if(characString == null) return;
await LoadChampionsByCharacteristic(characString);
},
[LoadingCriterium.ByClass] = async (o) =>
{
if(!Enum.IsDefined(typeof(ChampionClass), o)) return;
ChampionClass champClass = (ChampionClass)o;
await LoadChampionsByClass(champClass);
},
};
}
private async Task LoadChampionsFunc(Func<Task<IEnumerable<Champion?>>> loader,
Func<Task<int>> nbReader,
LoadingCriterium criterium,
object parameter = null)
{
Champions.Clear();
var someChampions = (await loader()).Select(c => new ChampionVM(c)).ToList();
foreach (var cvm in someChampions)
{
Champions.Add(cvm);
}
NbChampions = await nbReader();
currentLoadingCriterium = criterium;
currentLoadingParameter = parameter;
}
[RelayCommand]
public async Task LoadChampions()
{
await LoadChampionsFunc(async () => await DataMgr.ChampionsMgr.GetItems(index, count, "Name"),
async () => await DataMgr.ChampionsMgr.GetNbItems(),
LoadingCriterium.None);
}
[RelayCommand(CanExecute =nameof(CanLoadChampionsByName))]
public async Task LoadChampionsByName(string substring)
{
await LoadChampionsFunc(async () => await DataMgr.ChampionsMgr.GetItemsByName(substring, index, count, "Name"),
async () => await DataMgr.ChampionsMgr.GetNbItemsByName(substring),
LoadingCriterium.ByName,
substring);
}
private bool CanLoadChampionsByName(string substring)
=> !string.IsNullOrWhiteSpace(substring);
[RelayCommand(CanExecute =nameof(CanLoadChampionsBySkill))]
public async Task LoadChampionsBySkill(string skill)
{
await LoadChampionsFunc(
async () => await DataMgr.ChampionsMgr.GetItemsBySkill(skill, index, count, "Name"),
async () => await DataMgr.ChampionsMgr.GetNbItemsBySkill(skill),
LoadingCriterium.BySkill,
skill);
}
private bool CanLoadChampionsBySkill(string substring) => !string.IsNullOrWhiteSpace(substring);
[RelayCommand(CanExecute = nameof(CanLoadChampionsByCharacteristic))]
public async Task LoadChampionsByCharacteristic(string characteristic)
{
await LoadChampionsFunc(
async () => await DataMgr.ChampionsMgr.GetItemsByCharacteristic(characteristic, index, count, "Name"),
async () => await DataMgr.ChampionsMgr.GetNbItemsByCharacteristic(characteristic),
LoadingCriterium.ByCharacteristic,
characteristic);
}
private bool CanLoadChampionsByCharacteristic(string characteristic)
=> !string.IsNullOrWhiteSpace(characteristic);
[RelayCommand]
public async Task LoadChampionsByClass(ChampionClass champClass)
{
if(champClass == ChampionClass.Unknown)
{
return;
}
await LoadChampionsFunc(
async () => await DataMgr.ChampionsMgr.GetItemsByClass(champClass, index, count, "Name"),
async () => await DataMgr.ChampionsMgr.GetNbItemsByClass(champClass),
LoadingCriterium.ByClass,
champClass);
}
[RelayCommand(CanExecute =nameof(CanDeleteChampion))]
public async Task<bool> DeleteChampion(object champVM)
{
ChampionVM cvm = champVM as ChampionVM;
if(cvm == null || !Champions.Contains(cvm)) return false;
bool result = await DataMgr.ChampionsMgr.DeleteItem(cvm.Model);
if(result)
{
Champions.Remove(cvm);
await LoadChampions();
}
return result;
}
bool CanDeleteChampion(object cvm)
=> cvm!= null && cvm is ChampionVM && Champions.Contains(cvm);
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(NextPageCommand))]
[NotifyCanExecuteChangedFor(nameof(PreviousPageCommand))]
private int index = 0;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(NbPages))]
[NotifyCanExecuteChangedFor(nameof(NextPageCommand))]
[NotifyCanExecuteChangedFor(nameof(PreviousPageCommand))]
private int count = 5;
public int NbPages
{
get
{
if(Count == 0 || NbChampions == 0)
{
return 0;
}
return (NbChampions-1) / Count + 1;
}
}
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(NbPages))]
[NotifyCanExecuteChangedFor(nameof(NextPageCommand))]
[NotifyCanExecuteChangedFor(nameof(PreviousPageCommand))]
private int nbChampions = 0;
[ObservableProperty]
private ObservableCollection<ChampionVM> champions = new ObservableCollection<ChampionVM>();
[RelayCommand(CanExecute =nameof(CanPreviousPage))]
async Task PreviousPage()
{
if(Index > 0)
{
Index--;
await loadingMethods[currentLoadingCriterium](currentLoadingParameter);
}
}
bool CanPreviousPage() => Index > 0;
[RelayCommand(CanExecute =nameof(CanNextPage))]
async Task NextPage()
{
if(Index < NbPages-1)
{
Index++;
await loadingMethods[currentLoadingCriterium](currentLoadingParameter);
}
}
bool CanNextPage() => Index < NbPages-1;
enum LoadingCriterium
{
None,
ByName,
BySkill,
ByCharacteristic,
ByClass
}
private LoadingCriterium currentLoadingCriterium = LoadingCriterium.None;
private object currentLoadingParameter = null;
private Dictionary<LoadingCriterium, Func<object, Task>> loadingMethods;
public async Task AddChampion(ChampionVM champVM)
{
var added = await DataMgr.ChampionsMgr.AddItem(champVM.Model);
if(added != null)
{
Champions.Add(champVM);
await LoadChampions();
}
}
public async Task EditChampion(ChampionVM oldChampion, ChampionVM newChampion)
{
var edited = await DataMgr.ChampionsMgr.UpdateItem(oldChampion.Model, newChampion.Model);
oldChampion.Model = newChampion.Model;
if(edited != null)
{
await LoadChampions();
}
}
}

@ -1,73 +0,0 @@
using System;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Model;
namespace ViewModels
{
[ObservableObject]
public partial class EditableChampionVM
{
public EditableChampionVM()
{ }
public EditableChampionVM(ChampionVM championVM)
{
Name = championVM.Name;
IconBase64 = championVM.Icon;
LargeImageBase64 = championVM.Image;
Bio = championVM.Bio;
ChampionClass = championVM.Class;
foreach(var ch in championVM.Characteristics)
{
AddCharacteristic(ch.Key, ch.Value);
}
foreach(var skill in championVM.Skills)
{
Skills.Add(skill);
}
}
[ObservableProperty]
string name;
[ObservableProperty]
string iconBase64;
[ObservableProperty]
string largeImageBase64;
[ObservableProperty]
string bio;
[ObservableProperty]
ChampionClass championClass;
[ObservableProperty]
ObservableCollection<KeyValuePair<string, int>> characteristics = new ();
public void AddCharacteristic(string description, int value)
=> Characteristics.Add(new KeyValuePair<string, int>(description, value));
public void RemoveCharacteristic(KeyValuePair<string, int> characteristic)
=> Characteristics.Remove(characteristic);
[ObservableProperty]
ObservableCollection<SkillVM> skills = new ObservableCollection<SkillVM>();
public ChampionVM ToChampionVM()
{
var champion = new Champion(name, championClass, iconBase64, largeImageBase64, bio);
champion.AddCharacteristics(characteristics.Select(kvp => Tuple.Create(kvp.Key, kvp.Value)).ToArray());
foreach(var skillVM in Skills)
{
champion.AddSkill(skillVM.Model);
}
return new ChampionVM(champion);
}
}
}

@ -1,51 +0,0 @@
using System;
using System.Reflection.PortableExecutable;
using System.Xml.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using Model;
namespace ViewModels
{
[ObservableObject]
public partial class EditableSkinVM
{
public EditableSkinVM(ChampionVM championVM)
{
champion = championVM.Model;
}
public EditableSkinVM(SkinVM skinVM)
{
Name = skinVM.Name;
IconBase64 = skinVM.Icon;
LargeImageBase64 = skinVM.Image;
Description = skinVM.Description;
Price = skinVM.Price;
champion = skinVM.Champion;
}
[ObservableProperty]
private string name;
[ObservableProperty]
private string iconBase64;
[ObservableProperty]
private string largeImageBase64;
[ObservableProperty]
private string description;
[ObservableProperty]
private float price;
private Champion champion;
public SkinVM ToSkinVM()
{
var skin = new Skin(name, champion, price, iconBase64, largeImageBase64, description);
return new SkinVM(skin);
}
}
}

@ -1,32 +0,0 @@
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using Model;
namespace ViewModels
{
[ObservableObject]
public partial class SkillVM
{
[ObservableProperty]
private Skill model;
public SkillVM(Skill model)
{
Model = model;
}
public string Name => Model.Name;
public SkillType Type => Model.Type;
public string Description
{
get => Model.Description;
set
{
SetProperty(Model.Description, value, newValue => Model.Description = newValue);
}
}
}
}

@ -1,65 +0,0 @@
using System;
using System.Reflection.PortableExecutable;
using System.Security.Claims;
using CommunityToolkit.Mvvm.ComponentModel;
using Model;
namespace ViewModels
{
[ObservableObject]
public partial class SkinVM
{
public Skin Model
{
get => model;
set
{
model = value;
OnPropertyChanged(nameof(Name));
OnPropertyChanged(nameof(Description));
OnPropertyChanged(nameof(Price));
OnPropertyChanged(nameof(Icon));
OnPropertyChanged(nameof(Image));
}
}
private Skin model;
public SkinVM(Skin model)
=> Model = model;
public string Name => Model.Name;
public string Description
{
get => Model.Description;
set => SetProperty(Model.Description, value, newValue => Model.Description = newValue);
}
public float Price
{
get => Model.Price;
set => SetProperty(Model.Price, value, newValue => Model.Price = newValue);
}
public string Icon
{
get => Model.Icon;
set
{
SetProperty(Model.Icon, value, newIcon => Model.Icon = newIcon);
}
}
public string Image
{
get => Model.Image.Base64;
set
{
SetProperty(Model.Image.Base64, value, newImage => Model.Image.Base64 = newImage);
}
}
public Champion Champion => Model.Champion;
}
}

@ -1,135 +0,0 @@
using System;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Model;
namespace ViewModels
{
[ObservableObject]
public partial class SkinsMgrVM
{
internal IDataManager DataMgr { get; set; }
[ObservableProperty]
private ChampionVM champion;
public SkinsMgrVM(IDataManager dataManager)
{
DataMgr = dataManager;
}
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(NextPageCommand))]
[NotifyCanExecuteChangedFor(nameof(PreviousPageCommand))]
private int index = 0;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(NbPages))]
[NotifyCanExecuteChangedFor(nameof(NextPageCommand))]
[NotifyCanExecuteChangedFor(nameof(PreviousPageCommand))]
private int count = 5;
public int NbPages
{
get
{
if(Count == 0 || NbSkins == 0)
{
return 0;
}
return (NbSkins-1) / Count + 1;
}
}
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(NbPages))]
[NotifyCanExecuteChangedFor(nameof(NextPageCommand))]
[NotifyCanExecuteChangedFor(nameof(PreviousPageCommand))]
private int nbSkins = 0;
[ObservableProperty]
private ObservableCollection<SkinVM> skins = new ObservableCollection<SkinVM>();
[RelayCommand]
async Task LoadSkins()
{
Skins.Clear();
IEnumerable<Skin?> skins;
if(Champion != null)
{
skins = await DataMgr.SkinsMgr.GetItemsByChampion(Champion.Model, Index, Count,"Name");
}
else
{
skins = await DataMgr.SkinsMgr.GetItems(Index, Count, "Name");
}
foreach(var skin in skins)
{
if(skin != null)
Skins.Add(new SkinVM(skin));
}
}
[RelayCommand(CanExecute =nameof(CanPreviousPage))]
async Task PreviousPage()
{
if(Index > 0)
{
Index--;
await LoadSkins();
}
}
bool CanPreviousPage() => Index > 0;
[RelayCommand(CanExecute =nameof(CanNextPage))]
async Task NextPage()
{
if(Index < NbPages-1)
{
Index++;
await LoadSkins();
}
}
bool CanNextPage() => Index < NbPages-1;
[RelayCommand(CanExecute =nameof(CanDeleteSkin))]
public async Task<bool> DeleteSkin(object skinVM)
{
SkinVM svm = skinVM as SkinVM;
if(svm == null || !Skins.Contains(svm)) return false;
bool result = await DataMgr.SkinsMgr.DeleteItem(svm.Model);
if(result)
{
Skins.Remove(svm);
await LoadSkins();
}
return result;
}
bool CanDeleteSkin(object svm)
=> svm!= null && svm is SkinVM && Skins.Contains(svm);
public async Task AddSkin(SkinVM skinVM)
{
var added = await DataMgr.SkinsMgr.AddItem(skinVM.Model);
if(added != null)
{
Skins.Add(skinVM);
await LoadSkins();
}
}
public async Task EditSkin(SkinVM oldSkin, SkinVM newSkin)
{
var edited = await DataMgr.SkinsMgr.UpdateItem(oldSkin.Model, newSkin.Model);
oldSkin.Model = newSkin.Model;
if(edited != null)
{
await LoadSkins();
}
}
}
}

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseMaui>true</UseMaui>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0" />
</ItemGroup>
</Project>

@ -0,0 +1,16 @@
namespace apiLOL
{
public class ChampionDTO
{
public ChampionDTO(string name, string bio)
{
Name = name;
Bio = bio;
}
public string Name { get; set; }
public string Bio { get; set; }
}
}

@ -1,18 +1,16 @@
using Model; using Model;
namespace apiLOL.DTO namespace apiLOL
{ {
public static class ChampionMapper public static class ChampionMapper
{ {
public static ChampionDTO ToDTO(this Champion champion) public static ChampionDTO ToDTO(this Champion champion) => new ChampionDTO(champion.Name, champion.Bio);
=> new ChampionDTO(champion.Name, champion.Bio, champion.Icon);
public static Champion ToModel(this ChampionDTO championDTO) public static Champion ToModel(this ChampionDTO championDTO)
{ {
Champion champ = new Champion(championDTO.Name); Champion champ = new Champion(championDTO.Name);
champ.Bio = championDTO.Bio; champ.Bio = championDTO.Bio;
champ.Icon = championDTO.Icon;
return champ; return champ;
} }

@ -0,0 +1,13 @@
namespace apiLOL
{
public class ChampionPageDTO
{
public IEnumerable<ChampionDTO> Data { get; set; }
public int Index { get; set; }
public int Count { get; set; }
public int TotalCount { get; set; }
}
}

@ -1,7 +1,7 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using apiLOL.DTO;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Model; using Model;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace apiLOL.Controllers namespace apiLOL.Controllers
{ {
@ -22,87 +22,72 @@ namespace apiLOL.Controllers
} }
// GET: api/<ControllerLol>
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(ChampionPageDTO), 200)] public async Task<IActionResult> Get([FromQuery]int index = 0, int count = 10)
public async Task<IActionResult> GetChampions([FromQuery] int index = 0, int count = 10, string? name = "")
{ {
//FromQuery permet de filtrer dans la collection de champions en fonction du nom
// Possible de faire une classe PageRequest pour gérer les paramètres index et count
_logger.LogInformation($"methode Get de ControllerChampions appelée"); _logger.LogInformation($"methode Get de ControllerChampions appelée");
int nbChampions = await _dataManager.GetNbItems(); int nbChampions = await _dataManager.GetNbItems();
_logger.LogInformation($"Nombre de champions : {nbChampions}"); _logger.LogInformation($"Nombre de champions : {nbChampions}");
var champs = (await _dataManager.GetItemsByName(name, index, int.MaxValue)) var champs = (await _dataManager.GetItems(index, count)).Select(Model => Model.ToDTO());
.Where(champ => string.IsNullOrEmpty(name) || champ.Name.Contains(name, StringComparison.InvariantCultureIgnoreCase))
.Take(count)
.Select(Model => Model.ToDTO());
var page = new ChampionPageDTO var page = new ChampionPageDTO
{ {
Data = champs, Data = champs,
Index = index, Index = index,
Count = champs.Count(), Count = count,
TotalCount = nbChampions TotalCount = nbChampions
}; };
return Ok(page); return Ok(page);
} }
// GET api/<ControllerLol>/Charle
[HttpGet] [HttpGet]
[Route("{name}")] [Route("{name}")]
[ProducesResponseType(typeof(ChampionDTO), 200)] public async Task<IActionResult> GetChampion(string name)
public async Task<IActionResult> GetChampionByName(string name)
{ {
_logger.LogInformation($"methode GetChampion de ControllerChampions appelée avec le paramètre {name}"); _logger.LogInformation($"methode GetChampion de ControllerChampions appelée avec le paramètre {name}");
try try
{ {
var champs = await _dataManager.GetItemsByName(name, 0, 1); var champs = (await _dataManager.GetItemsByName(name, 0, 1));
if (champs.Any())
{
return Ok(champs.First().ToDTO()); return Ok(champs.First().ToDTO());
} }
else catch
{
return NotFound();
}
}
catch (Exception ex)
{ {
_logger.LogError($"erreur methode Get de ControllerChampions: {ex}");
return BadRequest("erreur de nom de champion"); return BadRequest("erreur de nom de champion");
} }
} }
// POST api/<ControllerLol>
[HttpPost] [HttpPost]
public async Task<IActionResult> AddChampion(ChampionDTO champDTO) public async Task<IActionResult> Post(ChampionDTO champDTO)
{ {
_logger.LogInformation($"methode Post de ControllerChampions appelée avec le paramètre {champDTO.Name}"); _logger.LogInformation($"methode Post de ControllerChampions appelée avec le paramètre {champDTO.Name}");
try try
{ {
// Check if the champion already exists in the database
var champs = await _dataManager.GetItemsByName(champDTO.Name, 0, 1);
if (champs.Any())
{
return BadRequest("le champion existe deja");
}
Champion tmp = champDTO.ToModel(); Champion tmp = champDTO.ToModel();
Champion champion = await _dataManager.AddItem(tmp); Champion champion = await _dataManager.AddItem(tmp);
ChampionDTO dtoChamp = champion.ToDTO(); ChampionDTO dtoChamp = champion.ToDTO();
return CreatedAtAction(nameof(GetChampionByName), new { name = dtoChamp.Name }, dtoChamp); return CreatedAtAction(nameof(GetChampion), new { name = dtoChamp.Name }, dtoChamp);
} }
catch (Exception ex) catch
{ {
_logger.LogError($"erreur methode Post de ControllerChampions: {ex}"); return BadRequest("le champion existe deja");
return BadRequest("erreur lors de l'ajout du champion");
} }
} }
// PUT api/<ControllerLol>/5
[HttpPut("{name}")] [HttpPut("{name}")]
public async Task<IActionResult> UpdateChampion(string name, string bio) public async Task<IActionResult> Put(string name, string bio)
{ {
_logger.LogInformation( _logger.LogInformation($"methode Put de ControllerChampions appelée avec le paramètre name: {name} et bio: {bio}");
$"methode Put de ControllerChampions appelée avec le paramètre name: {name} et bio: {bio}");
try try
{ {
@ -110,67 +95,27 @@ namespace apiLOL.Controllers
champs.Bio = bio; champs.Bio = bio;
return Ok(champs.ToDTO()); return Ok(champs.ToDTO());
} }
catch (Exception ex) catch
{ {
_logger.LogError($"erreur methode Put de ControllerChampions: {ex}");
return BadRequest("erreur de nom de champion"); return BadRequest("erreur de nom de champion");
} }
} }
// DELETE api/<ControllerLol>/5
[HttpDelete("{name}")] [HttpDelete("{name}")]
public async Task<IActionResult> DeleteChampion(string name) public async Task<IActionResult> Delete(String name)
{ {
_logger.LogInformation($"methode Delete de ControllerChampions appelée avec le paramètre name: {name}");
try try
{ {
var champ = (await _dataManager.GetItemsByName(name, 0, 1)).First(); var champ = (await _dataManager.GetItemsByName(name, 0, 1)).First();
_dataManager.DeleteItem(champ); _dataManager.DeleteItem(champ);
return Ok(champ.ToDTO()); return Ok(champ.ToDTO());
} }
catch (Exception ex) catch
{ {
_logger.LogError($"erreur methode Delete de ControllerChampions: {ex}");
return BadRequest("erreur de nom de champion"); return BadRequest("erreur de nom de champion");
} }
} }
} }
[ApiController]
[Route("api/v2/[controller]")]
[ApiVersion("2.0")]
public class ControllerChampionsSecondVersion : Controller
{
private readonly ILogger _logger;
public ControllerChampionsSecondVersion(ILogger<ControllerChampions> log)
{
_logger = log;
}
[HttpGet()]
public string Get(int id)
{
return "Version 2 of GET";
}
[HttpPost]
public void Post([FromBody] string value)
{
}
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
} }

@ -1,64 +0,0 @@
using apiLOL.DTO;
using Microsoft.AspNetCore.Mvc;
using Model;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace apiLOL.Controllers
{
[Route("api/[controller]")]
[ApiController]
[ApiVersion("1.0")]
public class ControllerSkins : ControllerBase
{
private readonly IDataManager data;
// EFdata manager qui implémente l'interface IDataManager
// coté client : Refaire un APIdata manager qui implémente l'interface IDataManager
private readonly ILogger _logger;
public ControllerSkins(IDataManager manager, ILogger<ControllerChampions> log)
{
data = manager;
_logger = log;
}
// GET api/<ControllerSkins>/5
[HttpGet]
public async Task<IActionResult> Get([FromQuery] int index = 0, int count = 10, string? name = "")
{
_logger.LogInformation($"methode Get de ControllerSkins appelée index:{index}, count: {count} et name:{name}");
int nbSkins = await data.SkinsMgr.GetNbItems();
_logger.LogInformation($"Nombre de skins : {nbSkins}");
var skin = (await data.SkinsMgr.GetItems(index, await data.SkinsMgr.GetNbItems())).Select(Model => Model.ToDTO());//.Where(Model => Model.Name.Contains(name)).Skip(index * count).Take(count).Select(Model => Model.ToDTO());
var page = new SkinPageDTO
{
Data = (IEnumerable<SkinDTO>)skin,
Index = index,
Count = count,
TotalCount = nbSkins
};
return Ok(page);
}
// POST api/<ControllerSkins>
[HttpPost]
public void Post([FromBody] string value)
{
}
// PUT api/<ControllerSkins>/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/<ControllerSkins>/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}

@ -1,21 +0,0 @@
namespace apiLOL.DTO
{
public class ChampionDTO
{
public ChampionDTO(string name, string bio, string icon)
{
Name = name;
Bio = bio;
Icon = icon;
}
public string Name { get; set; }
public string Bio { get; set; }
public string Icon { get; set; }
public bool Equals(ChampionDTO other) => other.Name == this.Name && other.Bio == this.Bio && other.Icon == this.Icon;
public string toString() => $"ChampionDTO: {Name} {Bio} {Icon}";
}
}

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

Loading…
Cancel
Save