Merge branch 'linkDB_API'
continuous-integration/drone/push Build encountered an error Details

master
Nathan BOILEAU 2 years ago
commit b1752c3461

@ -17,6 +17,27 @@ steps:
- dotnet restore LeagueOfLegends.sln
- dotnet build LeagueOfLegends.sln -c Release --no-restore
- 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
- name: docker-build-and-push
image: plugins/docker
@ -52,7 +73,7 @@ steps:
- dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN}
secrets: [ SECRET_SONAR_LOGIN ]
settings:
# accessible en ligne de commande par ${PLUGIN_SONAR_HOST}
# accessible en ligne de commande par ${PLUGIN_SONAR_HOST}
sonar_host: https://codefirst.iut.uca.fr/sonar/
# accessible en ligne de commande par ${PLUGIN_SONAR_TOKEN}
sonar_token:

@ -11,13 +11,17 @@ namespace EFLol
public string Name { get; set; }
[MaxLength(256, ErrorMessage = "Bio cannot be longer than 256 characters.")]
public string Bio { get; set; }
//public ChampionClass Class { get; set; }
//public string Icon { get; set; }
//public LargeImage Image { get; set; }
//public ReadOnlyDictionary<string, int> Characteristics { get; private set; }
//private HashSet<Skill> skills = new HashSet<Skill>();
public ReadOnlyCollection<SkinEntity> Skins { get; set; }
}
public string Bio { get; set; }
//public ChampionClass Class { get; set; }
//public string Icon { get; set; }
//public LargeImage Image { get; set; }
//public ReadOnlyDictionary<string, int> Characteristics { get; private set; }
public HashSet<SkillEntity> skills = new HashSet<SkillEntity>();
public Collection<SkinEntity> Skins { get; set; }
public Collection<RunePageEntity> ListRunePages { get; set; }
}
}

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model;
namespace EFLol.DBDataManager
{
public static class DataConverter
{
public static Champion ChampionToPoco(this ChampionEntity champion)
{
return new Champion(champion.Name, champion.Bio);
}
public static ChampionEntity ChampionToEntity(this Champion champion)
{
return new ChampionEntity
{
Name = champion.Name,
Bio = champion.Bio
};
}
}
}

@ -0,0 +1,165 @@
using Microsoft.EntityFrameworkCore;
using Model;
namespace EFLol.DBDataManager
{
public class EFDataManager : IDataManager
{
public IChampionsManager ChampionsMgr => new EFChampionManager();
public ISkinsManager SkinsMgr => throw new NotImplementedException();
public IRunesManager RunesMgr => throw new NotImplementedException();
public IRunePagesManager RunePagesMgr => throw new NotImplementedException();
}
public class EFChampionManager : IChampionsManager
{
private MyDbContext _context;
public EFChampionManager()
{
_context = new MyDbContext();
}
public async Task<Champion?> AddItem(Champion? item)
{
if (item == null)
{
throw new Exception("Item is null");
}
_context.Add(item.ChampionToEntity());
_context.SaveChanges();
return item;
}
public async Task<bool> DeleteItem(Champion? item)
{
if (item == null)
{
return false;
}
var champ = _context.Champions.Select(c => c == item.ChampionToEntity());
if (champ.Count() < 1)
{
return false;
}
_context.Champions.Remove(item.ChampionToEntity());
_context.SaveChanges();
return true;
}
public async 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");
}
champEntity.Bio = newItem.Bio;
_context.SaveChanges();
return champEntity.ChampionToPoco();
}
throw new Exception("Invalid input parameters");
}
public async Task<int> GetNbItems() => _context.Champions.Count();
public async Task<IEnumerable<Champion?>> GetItems(int index, int count, string? orderingPropertyName = null,
bool descending = false)
{
IEnumerable<Champion> champions = _context.Champions.Skip(index * count)
.Take(count)
.OrderBy(champions => orderingPropertyName)
.Select(champions => champions.ChampionToPoco());
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)
{
throw new NotImplementedException();
}
public Task<int> GetNbItemsByCharacteristic(string charName)
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsByCharacteristic(string charName, int index, int count,
string? orderingPropertyName = null,
bool @descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbItemsByClass(ChampionClass championClass)
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsByClass(ChampionClass championClass, int index, int count,
string? orderingPropertyName = null,
bool @descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbItemsBySkill(Skill? skill)
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsBySkill(Skill? skill, int index, int count,
string? orderingPropertyName = null, bool @descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbItemsByRunePage(RunePage? runePage)
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsByRunePage(RunePage? runePage, int index, int count,
string? orderingPropertyName = null,
bool @descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbItemsBySkill(string skill)
{
throw new NotImplementedException();
}
public Task<IEnumerable<Champion?>> GetItemsBySkill(string skill, int index, int count,
string? orderingPropertyName = null, bool @descending = false)
{
throw new NotImplementedException();
}
}
}

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

@ -24,5 +24,10 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

@ -1,37 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace EFLol
{
public class MyDbContext : DbContext
{
public DbSet<ChampionEntity> Champions { get; set; }
public DbSet<SkinEntity> Skins { get; set; }
public MyDbContext()
{ }
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{ }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlite("Data Source=loldb.db");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ChampionEntity>().Property(c => c.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<SkinEntity>().Property(s => s.Id).ValueGeneratedOnAdd();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace EFLol
{
public class MyDbContext : DbContext
{
public DbSet<ChampionEntity> Champions { get; set; }
public DbSet<SkinEntity> Skins { get; set; }
public DbSet<SkillEntity> Skill { get; set; }
public DbSet<RunePageEntity> RunePages { get; set; }
public DbSet<RuneEntity> Runes { get; set; }
public MyDbContext()
{ }
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{ }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlite("Data Source=../EFLol/loldb.db");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ChampionEntity>().Property(c => c.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<SkinEntity>().Property(s => s.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<SkillEntity>().Property(s => s.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<ChampionEntity>().HasMany(p => p.skills).WithMany(p => p.champions).UsingEntity(j => j.ToTable("ChampionSkills"));
modelBuilder.Entity<RunePageEntity>().Property(s => s.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<RuneEntity>().Property(s => s.Id).ValueGeneratedOnAdd();
}
}
}

@ -1,67 +1,105 @@
using System.Collections.ObjectModel;
using EFLol;
using (var context = new MyDbContext())
{
// Clean the DB before starting
Console.WriteLine("Clean the DB before starting");
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
}
SkinEntity black = new SkinEntity { Name = "Black", Description = "Black skin", Icon = "black.png", Price = 0.99f };
SkinEntity white = new SkinEntity { Name = "White", Description = "White skin", Icon = "white.png", Price = 150.99f };
SkinEntity green = new SkinEntity { Name = "Green", Description = "Green skin", Icon = "green.png", Price = 4.99f };
ChampionEntity Zeus = new ChampionEntity
{
Name = "Zeus",
Bio = "Zeus is the god of the sky",
Skins = new ReadOnlyCollection<SkinEntity>(new List<SkinEntity> { black, white })
};
ChampionEntity Hera = new ChampionEntity
{
Name = "Hera",
Bio = "Hera is the goddess of marriage",
Skins = new ReadOnlyCollection<SkinEntity>(new List<SkinEntity> { green })
};
ChampionEntity Poseidon = new ChampionEntity { Name = "Poseidon", Bio = "Poseidon is the god of the sea" };
using (var context = new MyDbContext())
{
// Crée des champions et les insère dans la base
Console.WriteLine("Creates and inserts new Champions");
context.Add(Zeus);
context.Add(Hera);
context.Add(Poseidon);
context.SaveChanges();
}
using (var context = new MyDbContext())
{
foreach (var n in context.Champions)
{
// Use LINQ to display the skins for each champion
var skins = from s in context.Skins
where n.Id == s.Id
select s;
Console.WriteLine($"Champion n°{n.Id} - {n.Name}");
}
context.SaveChanges();
}
using (var context = new MyDbContext())
{
foreach (var n in context.Skins)
{
Console.WriteLine($"Skin n°{n.Id} - {n.Name}" + (n.Price != null ? $" - {n.Price}" : ""));
}
context.SaveChanges();
using System.Collections.Generic;
using System.Collections.ObjectModel;
using EFLol;
internal class Program
{
private static void Main(string[] args)
{
using (var context = new MyDbContext())
{
// Clean the DB before starting
Console.WriteLine("Clean the DB before starting");
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
}
SkinEntity black = new SkinEntity { Name = "Black", Description = "Black skin", Icon = "black.png", Price = 0.99f };
SkinEntity white = new SkinEntity { Name = "White", Description = "White skin", Icon = "white.png", Price = 150.99f };
SkinEntity green = new SkinEntity { Name = "Green", Description = "Green skin", Icon = "green.png", Price = 4.99f };
RuneEntity rune1 = new RuneEntity { Id = 1, Name = "rune1", Description = "super rune1" };
RuneEntity rune2 = new RuneEntity { Id = 2, Name = "rune2", Description = "super rune2" };
RuneEntity rune3 = new RuneEntity { Id = 3, Name = "rune3", Description = "super rune3" };
RunePageEntity runePage1 = new RunePageEntity { Id = 1, Name = "runepage1"/*, Runes = new Dictionary<Category, RuneEntity> { { Category.Major, rune1 } }*/ };
ChampionEntity Zeus = new ChampionEntity { Name = "Zeus", Bio = "Zeus is the god of the sky", Skins = new Collection<SkinEntity>(new List<SkinEntity> { black, white }) };
ChampionEntity Hera = new ChampionEntity { Name = "Hera", Bio = "Hera is the goddess of marriage", Skins = new Collection<SkinEntity>(new List<SkinEntity> { green }) };
ChampionEntity Poseidon = new ChampionEntity {
Name = "Poseidon", Bio = "Poseidon is the god of the sea",
ListRunePages = new Collection<RunePageEntity>(new List<RunePageEntity> { { runePage1 } })
};
SkillEntity skill1 = new SkillEntity
{
Id = 1,
Name = "skill1",
Description = "super skill",
SkillType = SkillTypeEntity.Basic,
champions = new HashSet<ChampionEntity> { Zeus, Hera }
};
SkillEntity skill2 = new SkillEntity
{
Id = 2,
Name = "skill2",
Description = "super skill",
SkillType = SkillTypeEntity.Basic,
champions = new HashSet<ChampionEntity> { Zeus}
};
Zeus.skills.Add(skill1);
Zeus.skills.Add(skill2);
Hera.skills.Add(skill1);
using (var context = new MyDbContext())
{
Console.WriteLine("Creates and inserts new Champions");
context.Add(Zeus);
context.Add(Hera);
context.Add(Poseidon);
context.Add(skill1);
context.Add(skill2);
context.SaveChanges();
}
using (var context = new MyDbContext())
{
foreach (var n in context.Champions)
{
// LINQ to select the skins of the current champion
var skins = context.Champions.Where(c => c.Id == n.Id).SelectMany(c => c.Skins);
var runePage = context.Champions.Where(c => c.Id == n.Id).SelectMany(c => c.ListRunePages);
// Display the champion and its skins
Console.WriteLine($"Champion n°{n.Id} - {n.Name} : {skins.Count()} skins, {runePage.Count()} runePage");
}
context.SaveChanges();
}
using (var context = new MyDbContext())
{
foreach (var n in context.Skins)
{
Console.WriteLine($"Skin n°{n.Id} - {n.Name}" + (n.Price != null ? $" - {n.Price}" : ""));
}
context.SaveChanges();
}
using (var context = new MyDbContext())
{
foreach (var n in context.RunePages)
{
Console.WriteLine($"runePage n°{n.Id} - {n.Name}");
}
context.SaveChanges();
}
}
}

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFLol
{
public class RuneEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public RuneFamilyEntity RuneFamily { get; set; }
public Collection<RunePageEntity> ListRunePages { get; set; }
}
public enum RuneFamilyEntity
{
Unknown,
Precision,
Domination
}
}

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFLol
{
public class RunePageEntity
{
public int Id { get; set; }
public String Name { get; set; }
//public Dictionary<Category, RuneEntity> Runes { get; set; }
}
public enum Category
{
Major,
Minor1,
Minor2,
Minor3,
OtherMinor1,
OtherMinor2
}
}

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFLol
{
public class SkillEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public SkillTypeEntity SkillType { get; set; }
public HashSet<ChampionEntity> champions { get; set; }
}
public enum SkillTypeEntity
{
Unknown,
Basic,
Passive,
Ultimate
}
}

@ -1,83 +1,83 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C76D0C23-1FFA-4963-93CD-E12BD643F030}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTests", "Tests\ConsoleTests\ConsoleTests.csproj", "{1889FA6E-B7C6-416E-8628-9449FB9070B9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{3B720C0C-53FE-4642-A2DB-87FD8634CD74}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stub", "Stub", "{2C607793-B163-4731-A4D1-AFE8A7C4C170}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubLib", "StubLib\StubLib.csproj", "{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}"
ProjectSection(ProjectDependencies) = postProject
{3B720C0C-53FE-4642-A2DB-87FD8634CD74} = {3B720C0C-53FE-4642-A2DB-87FD8634CD74}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "apiLOL", "apiLOL\apiLOL.csproj", "{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}"
ProjectSection(ProjectDependencies) = postProject
{1889FA6E-B7C6-416E-8628-9449FB9070B9} = {1889FA6E-B7C6-416E-8628-9449FB9070B9}
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9} = {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}
{3B720C0C-53FE-4642-A2DB-87FD8634CD74} = {3B720C0C-53FE-4642-A2DB-87FD8634CD74}
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFLol", "EFLol\EFLol.csproj", "{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUnitaire", "TestUnitaire\TestUnitaire.csproj", "{5702F240-97BD-4757-918C-6E485C57D0EC}"
ProjectSection(ProjectDependencies) = postProject
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA} = {65B824B5-FADB-4C89-8B4B-D541B62B7DCA}
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7} = {7AEE66D2-490B-4049-B9D3-C629D7F78DA7}
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.Build.0 = Release|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.Build.0 = Release|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.Build.0 = Release|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Release|Any CPU.Build.0 = Release|Any CPU
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}.Release|Any CPU.Build.0 = Release|Any CPU
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}.Release|Any CPU.Build.0 = Release|Any CPU
{5702F240-97BD-4757-918C-6E485C57D0EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5702F240-97BD-4757-918C-6E485C57D0EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5702F240-97BD-4757-918C-6E485C57D0EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5702F240-97BD-4757-918C-6E485C57D0EC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1889FA6E-B7C6-416E-8628-9449FB9070B9} = {C76D0C23-1FFA-4963-93CD-E12BD643F030}
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {2C607793-B163-4731-A4D1-AFE8A7C4C170}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {92F3083D-793F-4552-8A9A-0AD6534159C9}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C76D0C23-1FFA-4963-93CD-E12BD643F030}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTests", "Tests\ConsoleTests\ConsoleTests.csproj", "{1889FA6E-B7C6-416E-8628-9449FB9070B9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{3B720C0C-53FE-4642-A2DB-87FD8634CD74}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stub", "Stub", "{2C607793-B163-4731-A4D1-AFE8A7C4C170}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubLib", "StubLib\StubLib.csproj", "{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}"
ProjectSection(ProjectDependencies) = postProject
{3B720C0C-53FE-4642-A2DB-87FD8634CD74} = {3B720C0C-53FE-4642-A2DB-87FD8634CD74}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "apiLOL", "apiLOL\apiLOL.csproj", "{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}"
ProjectSection(ProjectDependencies) = postProject
{1889FA6E-B7C6-416E-8628-9449FB9070B9} = {1889FA6E-B7C6-416E-8628-9449FB9070B9}
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9} = {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}
{3B720C0C-53FE-4642-A2DB-87FD8634CD74} = {3B720C0C-53FE-4642-A2DB-87FD8634CD74}
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFLol", "EFLol\EFLol.csproj", "{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUnitaire", "TestUnitaire\TestUnitaire.csproj", "{5702F240-97BD-4757-918C-6E485C57D0EC}"
ProjectSection(ProjectDependencies) = postProject
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA} = {65B824B5-FADB-4C89-8B4B-D541B62B7DCA}
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7} = {7AEE66D2-490B-4049-B9D3-C629D7F78DA7}
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.Build.0 = Release|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.Build.0 = Release|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.Build.0 = Release|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB}.Release|Any CPU.Build.0 = Release|Any CPU
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65B824B5-FADB-4C89-8B4B-D541B62B7DCA}.Release|Any CPU.Build.0 = Release|Any CPU
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7AEE66D2-490B-4049-B9D3-C629D7F78DA7}.Release|Any CPU.Build.0 = Release|Any CPU
{5702F240-97BD-4757-918C-6E485C57D0EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5702F240-97BD-4757-918C-6E485C57D0EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5702F240-97BD-4757-918C-6E485C57D0EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5702F240-97BD-4757-918C-6E485C57D0EC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1889FA6E-B7C6-416E-8628-9449FB9070B9} = {C76D0C23-1FFA-4963-93CD-E12BD643F030}
{B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {2C607793-B163-4731-A4D1-AFE8A7C4C170}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {92F3083D-793F-4552-8A9A-0AD6534159C9}
EndGlobalSection
EndGlobal

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

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

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

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

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

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

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

After

Width:  |  Height:  |  Size: 1.0 KiB

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

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

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

After

Width:  |  Height:  |  Size: 706 B

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

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

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

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

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

After

Width:  |  Height:  |  Size: 665 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -53,7 +53,13 @@ public class Champion : IEquatable<Champion>
Skins = new ReadOnlyCollection<Skin>(skins);
}
public ReadOnlyCollection<Skin> Skins { get; private set; }
public Champion(string name, string bio)
{
this.name = name;
this.bio = bio;
}
public ReadOnlyCollection<Skin> Skins { get; private set; }
private List<Skin> skins = new ();
public ReadOnlyDictionary<string, int> Characteristics { get; private set; }

@ -1,5 +1,5 @@
using apiLOL;
using apiLOL.Controllers;
using apiLOL.DTO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -10,50 +10,103 @@ namespace TestUnitaire
public class TestAPILol
{
[Theory]
[InlineData("Beatrice", "sdfsdfd")]
[InlineData("Maurice", "Ahri est un champion de League of Legends")]
[InlineData("Loupiotte", "Akali est un champion de League of Legends")]
public async Task TestPostChampion(string name, string bio)
[InlineData("Beatrice", "sdfsdfd", "icon.png")]
[InlineData("Maurice", "Ahri est un champion de League of Legends", "icon.png")]
[InlineData("Loupiotte", "Akali est un champion de League of Legends", "icon.png")]
public async Task TestPostChampion(string name, string bio, string icon)
{
// Arrange
var data = new StubData();
var logger = new NullLogger<ControllerChampions>();
var controller = new ControllerChampions(data, logger);
var champDTO = new ChampionDTO(name, bio);
var champDTO = new ChampionDTO(name, bio, icon);
// Act
var nbInListBefore = data.ChampionsMgr.GetNbItems().Result;
var result = await controller.Post(champDTO);
var result = await controller.AddChampion(champDTO);
var nbInListAfter = data.ChampionsMgr.GetNbItems().Result;
// Assert
// IS the champion added to the list, number of champions in the list + 1
Assert.Equal(nbInListBefore + 1, nbInListAfter);
// Test le code de retour
}
[Theory]
[InlineData("Beatrice", "Aatrox est un champion de League of Legends")]
[InlineData("Maurice", "Ahri est un champion de League of Legends")]
[InlineData("Loupiotte", "Akali est un champion de League of Legends")]
public async Task TestGetChampion(string name, string bio)
[InlineData("Beatrice", "Aatrox est un champion de League of Legends", "icon.png")]
[InlineData("Maurice", "Ahri est un champion de League of Legends", "icon.png")]
[InlineData("Loupiotte", "Akali est un champion de League of Legends", "icon.png")]
public async Task TestGetChampion(string name, string bio, string icon)
{
// Arrange
var data = new StubData();
var logger = new NullLogger<ControllerChampions>();
var controller = new ControllerChampions(data, logger);
var champDTO = new ChampionDTO(name, bio);
var champDTO = new ChampionDTO(name, bio, icon);
// Act
// Call method POST to add a champion
var result = await controller.Post(champDTO);
var result = await controller.AddChampion(champDTO);
// Call method GET to get the champion
var resultGet = await controller.GetChampion(name);
var resultGet = await controller.GetChampionByName(name);
// Assert
// IS the champion added to the list, number of champions in the list + 1
Assert.Equal(name, champDTO.Name);
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);
}
}
}

@ -1,6 +1,7 @@
using EFLol;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System.Collections.ObjectModel;
namespace TestUnitaire
{
@ -9,14 +10,14 @@ namespace TestUnitaire
[Theory]
[InlineData("Zeus", "Dieu de la foudre", true)]
[InlineData("Hades", "Dieu des enfers", true)]
[InlineData("Aphrodite", "Déesse de l'amour", true)]
[InlineData("AresAresAresAresAresAresAresAresAresAres",
[InlineData(0,"Zeus", "Dieu de la foudre", true)]
[InlineData(10,"Hades", "Dieu des enfers", true)]
[InlineData(1,"Aphrodite", "Déesse de l'amour", true)]
[InlineData(10,"AresAresAresAresAresAresAresAresAresAres",
"Dieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerre" +
"Dieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerre" +
"Dieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerreDieu de la guerre", false)]
public async Task TestAddInMemory(String name, String bio, bool expected)
public async Task TestAddChampionInMemory(int id, String name, String bio, bool expected)
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
@ -28,11 +29,20 @@ namespace TestUnitaire
using (var context = new MyDbContext(options))
{
await context.Database.EnsureCreatedAsync();
var Dieu = new ChampionEntity
SkinEntity black = new SkinEntity { Name = "Black", Description = "Black skin", Icon = "black.png", Price = 0.99f };
SkinEntity white = new SkinEntity { Name = "White", Description = "White skin", Icon = "white.png", Price = 150.99f };
SkinEntity green = new SkinEntity { Name = "Green", Description = "Green skin", Icon = "green.png", Price = 4.99f };
RunePageEntity runePage1 = new RunePageEntity { Id = 1, Name = "runepage1"};
var Dieu = new ChampionEntity
{
Id = id,
Name = name,
Bio = bio
};
Bio = bio,
Skins = new Collection<SkinEntity>(new List<SkinEntity> { black, white, green }),
ListRunePages = new Collection<RunePageEntity>(new List<RunePageEntity> { { runePage1 } })
};
ChampionEntity found = await context.Champions.SingleOrDefaultAsync(c => c.Name == "Zeus");
Assert.Null(found);
@ -45,24 +55,26 @@ namespace TestUnitaire
Assert.Equal(1, await context.Champions.CountAsync());
Assert.Equal(name, found.Name);
Assert.Equal(3,found.Skins.Count);
Assert.Equal(1, found.ListRunePages.Count);
// Test if the max length of the name is respected (30) and the max length of the bio is respected (256)
if (expected)
// Test if the max length of the name is respected (30) and the max length of the bio is respected (256)
if (expected)
{
Assert.True(found.Name.Length <= 30);
Assert.True(found.Bio.Length <= 256);
}
else
{
Assert.False(found.Bio.Length <= 256);
Assert.False(found.Name.Length <= 30);
Assert.False(found.Bio.Length <= 256);
}
}
}
[Fact]
public void ModifyTestInMemory()
public void TestModifyChampionInMemory()
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
@ -79,7 +91,7 @@ namespace TestUnitaire
ChampionEntity chewie = new ChampionEntity { Name = "Chewbacca", Bio = "Zeus is the king of the gods." };
ChampionEntity yoda = new ChampionEntity { Name = "Yoda", Bio = "Zeus is the king of the gods." };
ChampionEntity ewok = new ChampionEntity { Name = "Ewok", Bio = "Zeus is the king of the gods." };
ChampionEntity ewok = new ChampionEntity {Name = "Ewok", Bio = "Zeus is the king of the gods." };
context.Champions.Add(chewie);
@ -113,5 +125,54 @@ namespace TestUnitaire
Assert.Equal(1, context.Champions.Where(n => n.Name.ToLower().Contains(nameToFind)).Count());
}
}
}
[Theory]
[InlineData(0,"black", "super Skin", "icon1.png",190000000.2f,true)]
[InlineData(1,"White", "skin1", "icon1", 19, true)]
[InlineData(2,"Green", "skin", "icon1.jpg", -1, false)]
public async Task TestAddSkinToChampionInMemory(int id,String name, String description, String icon,float price,bool expected)
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
var options = new DbContextOptionsBuilder<MyDbContext>()
.UseSqlite(connection)
.Options;
using (var context = new MyDbContext(options))
{
await context.Database.EnsureCreatedAsync();
var Dieu = new ChampionEntity
{
Id = 0,
Name = "Zeus",
Bio = "Dieu de la foudre",
Skins = new Collection<SkinEntity>()
};
SkinEntity item = new SkinEntity
{
Id = id,
Name = name,
Description = description,
Icon = icon,
Price = price
};
Dieu.Skins.Add(item);
ChampionEntity found = await context.Champions.SingleOrDefaultAsync(c => c.Name == "Zeus");
Assert.Null(found);
await context.Champions.AddAsync(Dieu);
await context.SaveChangesAsync();
found = await context.Champions.SingleOrDefaultAsync(c => c.Name == name);
}
}
}
}

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

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

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

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

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

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

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

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

@ -1,16 +0,0 @@
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,13 +0,0 @@
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,4 +1,5 @@
using System.Security.Cryptography;
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
@ -11,110 +12,165 @@ namespace apiLOL.Controllers
public class ControllerChampions : Controller
{
private readonly IDataManager data;
//private readonly IDataManager data;
private IChampionsManager _dataManager;
private readonly ILogger _logger;
public ControllerChampions(IDataManager manager, ILogger<ControllerChampions> log)
{
data = manager;
_dataManager = manager.ChampionsMgr;
_logger = log;
}
// GET: api/<ControllerLol>
[HttpGet]
public async Task<IActionResult> Get([FromQuery]int index = 0, int count = 10)
[ProducesResponseType(typeof(ChampionPageDTO), 200)]
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");
int nbChampions = await data.ChampionsMgr.GetNbItems();
int nbChampions = await _dataManager.GetNbItems();
_logger.LogInformation($"Nombre de champions : {nbChampions}");
var champs = (await data.ChampionsMgr.GetItems(index, count)).Select(Model => Model.ToDTO());
var champs = (await _dataManager.GetItemsByName(name, index, int.MaxValue))
.Where(champ => string.IsNullOrEmpty(name) || champ.Name.Contains(name, StringComparison.InvariantCultureIgnoreCase))
.Take(count)
.Select(Model => Model.ToDTO());
var page = new ChampionPageDTO
{
Data = champs,
Index = index,
Count = count,
Count = champs.Count(),
TotalCount = nbChampions
};
return Ok(page);
}
// GET api/<ControllerLol>/Charle
[HttpGet]
[Route("{name}")]
public async Task<IActionResult> GetChampion(string name)
[ProducesResponseType(typeof(ChampionDTO), 200)]
public async Task<IActionResult> GetChampionByName(string name)
{
_logger.LogInformation($"methode GetChampion de ControllerChampions appelée avec le paramètre {name}");
try
{
var champs = (await data.ChampionsMgr.GetItemsByName(name, 0, 1));
return Ok(champs.First().ToDTO());
var champs = await _dataManager.GetItemsByName(name, 0, 1);
if (champs.Any())
{
return Ok(champs.First().ToDTO());
}
else
{
return NotFound();
}
}
catch
{
catch (Exception ex)
{
_logger.LogError($"erreur methode Get de ControllerChampions: {ex}");
return BadRequest("erreur de nom de champion");
}
}
// POST api/<ControllerLol>
[HttpPost]
public async Task<IActionResult> Post(ChampionDTO champDTO)
public async Task<IActionResult> AddChampion(ChampionDTO champDTO)
{
_logger.LogInformation($"methode Post de ControllerChampions appelée avec le paramètre {champDTO.Name}");
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 champion = await data.ChampionsMgr.AddItem(tmp);
Champion champion = await _dataManager.AddItem(tmp);
ChampionDTO dtoChamp = champion.ToDTO();
return CreatedAtAction(nameof(GetChampion), new { name = dtoChamp.Name }, dtoChamp);
return CreatedAtAction(nameof(GetChampionByName), new { name = dtoChamp.Name }, dtoChamp);
}
catch
catch (Exception ex)
{
return BadRequest("le champion existe deja");
_logger.LogError($"erreur methode Post de ControllerChampions: {ex}");
return BadRequest("erreur lors de l'ajout du champion");
}
}
// PUT api/<ControllerLol>/5
[HttpPut("{name}")]
public async Task<IActionResult> Put(string name, string bio)
public async Task<IActionResult> UpdateChampion(string name, string bio)
{
_logger.LogInformation($"methode Put de ControllerChampions appelée avec le paramètre name: {name} et bio: {bio}");
_logger.LogInformation(
$"methode Put de ControllerChampions appelée avec le paramètre name: {name} et bio: {bio}");
try
{
var champs = (await data.ChampionsMgr.GetItemsByName(name, 0, 1)).First();
var champs = (await _dataManager.GetItemsByName(name, 0, 1)).First();
champs.Bio = bio;
return Ok(champs.ToDTO());
}
catch
catch (Exception ex)
{
_logger.LogError($"erreur methode Put de ControllerChampions: {ex}");
return BadRequest("erreur de nom de champion");
}
}
// DELETE api/<ControllerLol>/5
[HttpDelete("{name}")]
public async Task<IActionResult> Delete(String name)
public async Task<IActionResult> DeleteChampion(string name)
{
_logger.LogInformation($"methode Delete de ControllerChampions appelée avec le paramètre name: {name}");
try
{
var champ = (await data.ChampionsMgr.GetItemsByName(name, 0, 1)).First();
data.ChampionsMgr.DeleteItem(champ);
var champ = (await _dataManager.GetItemsByName(name, 0, 1)).First();
_dataManager.DeleteItem(champ);
return Ok(champ.ToDTO());
}
catch
catch (Exception ex)
{
_logger.LogError($"erreur methode Delete de ControllerChampions: {ex}");
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)
{
}
}
}

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

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