commit 9b3cb65815b94746fdf73e0e153a2bb0bc27ef0b Author: Ano-sys Date: Thu Apr 17 14:05:16 2025 +0200 Inital Push diff --git a/LOLRLCG/.idea/.idea.LOLRLCG/.idea/.gitignore b/LOLRLCG/.idea/.idea.LOLRLCG/.idea/.gitignore new file mode 100644 index 0000000..cfa4e0c --- /dev/null +++ b/LOLRLCG/.idea/.idea.LOLRLCG/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.LOLRLCG.iml +/modules.xml +/projectSettingsUpdater.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/LOLRLCG/App.axaml b/LOLRLCG/App.axaml new file mode 100644 index 0000000..758eba6 --- /dev/null +++ b/LOLRLCG/App.axaml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/LOLRLCG/App.axaml.cs b/LOLRLCG/App.axaml.cs new file mode 100644 index 0000000..431d314 --- /dev/null +++ b/LOLRLCG/App.axaml.cs @@ -0,0 +1,33 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Data.Core; +using Avalonia.Data.Core.Plugins; +using Avalonia.Markup.Xaml; +using LOLRLCG.ViewModels; +using LOLRLCG.Views; + +namespace LOLRLCG; + +public partial class App : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + // Line below is needed to remove Avalonia data validation. + // Without this line you will get duplicate validations from both Avalonia and CT + BindingPlugins.DataValidators.RemoveAt(0); + desktop.MainWindow = new MainWindow + { + DataContext = new MainWindowViewModel(), + }; + } + + base.OnFrameworkInitializationCompleted(); + } +} \ No newline at end of file diff --git a/LOLRLCG/Assets/avalonia-logo.ico b/LOLRLCG/Assets/avalonia-logo.ico new file mode 100644 index 0000000..da8d49f Binary files /dev/null and b/LOLRLCG/Assets/avalonia-logo.ico differ diff --git a/LOLRLCG/LOLRLCG.csproj b/LOLRLCG/LOLRLCG.csproj new file mode 100644 index 0000000..6132e6b --- /dev/null +++ b/LOLRLCG/LOLRLCG.csproj @@ -0,0 +1,32 @@ + + + WinExe + net9.0 + enable + true + app.manifest + true + + + + + + + + + + + + + + + + + + + + + Always + + + diff --git a/LOLRLCG/LOLRLCG.sln b/LOLRLCG/LOLRLCG.sln new file mode 100644 index 0000000..a819fb6 --- /dev/null +++ b/LOLRLCG/LOLRLCG.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LOLRLCG", "LOLRLCG.csproj", "{59FCC5C4-5827-4EAA-BC9C-2078CC0C6113}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {59FCC5C4-5827-4EAA-BC9C-2078CC0C6113}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59FCC5C4-5827-4EAA-BC9C-2078CC0C6113}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59FCC5C4-5827-4EAA-BC9C-2078CC0C6113}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59FCC5C4-5827-4EAA-BC9C-2078CC0C6113}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/LOLRLCG/Program.cs b/LOLRLCG/Program.cs new file mode 100644 index 0000000..244e5aa --- /dev/null +++ b/LOLRLCG/Program.cs @@ -0,0 +1,21 @@ +using Avalonia; +using System; + +namespace LOLRLCG; + +sealed class Program +{ + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); +} \ No newline at end of file diff --git a/LOLRLCG/Resources/background.png b/LOLRLCG/Resources/background.png new file mode 100644 index 0000000..fd9a7f6 Binary files /dev/null and b/LOLRLCG/Resources/background.png differ diff --git a/LOLRLCG/ViewLocator.cs b/LOLRLCG/ViewLocator.cs new file mode 100644 index 0000000..4975a07 --- /dev/null +++ b/LOLRLCG/ViewLocator.cs @@ -0,0 +1,32 @@ +using System; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using LOLRLCG.ViewModels; + +namespace LOLRLCG; + +public class ViewLocator : IDataTemplate +{ + public Control? Build(object? data) + { + if (data is null) + return null; + + var name = data.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal); + var type = Type.GetType(name); + + if (type != null) + { + var control = (Control)Activator.CreateInstance(type)!; + control.DataContext = data; + return control; + } + + return new TextBlock { Text = "Not Found: " + name }; + } + + public bool Match(object? data) + { + return data is ViewModelBase; + } +} \ No newline at end of file diff --git a/LOLRLCG/ViewModels/MainWindowViewModel.cs b/LOLRLCG/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..ef19a88 --- /dev/null +++ b/LOLRLCG/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Controls.Shapes; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +namespace LOLRLCG.ViewModels; + +public class ChampionWrapper +{ + public Dictionary Data { get; set; } +} + +public class ImageInfo +{ + public string Full { get; set; } +} + +public class Champion : ObservableObject +{ + public string Id { get; init; } + private string _name; + public string Title { get; init; } + public List Tags { get; init; } + public ImageInfo Image { get; set; } + private string? _uri; + + public string Name + { + get => _name; + set => SetProperty(ref _name, value); + } + + public string? Uri + { + get => _uri; + set => SetProperty(ref _uri, value); + } + + public Champion(string id, string name, string title, List tags, ImageInfo image, string? uri = null) + { + this.Id = id; + this.Name = name; + this.Title = title; + this.Tags = tags; + this.Image = image; + this.Uri = uri; + } +} + +public partial class MainWindowViewModel : ViewModelBase +{ + private HttpClient httpClient = new HttpClient(); + private List Lanes = new List(["Top", "Mid", "Bot", "Sup", "Jgl"]); + + private List? _championList = new List(); + private Champion? _selectedChampion; + + private string? _lane; + private Bitmap? _laneImage; + + private string? _leagueClientVersion; + + public RelayCommand getRandomChampionLaneComboCommand { get; private set; } + + public Champion? SelectedChampion + { + get => _selectedChampion; + set => SetProperty(ref _selectedChampion, value); + } + + public string Lane + { + get => _lane; + set => SetProperty(ref _lane, value); + } + + public Bitmap? LaneImage + { + get => _laneImage; + set => SetProperty(ref _laneImage, value); + } + + public string? LeagueClientVersion + { + get => _leagueClientVersion; + set => SetProperty(ref _leagueClientVersion, value); + } + + private async Task LoadAndSetChampionImageAsync(Champion champ) + { + champ.Uri = $"http://ddragon.leagueoflegends.com/cdn/{LeagueClientVersion}/img/champion/{champ.Image.Full}"; + // champ.Uri = await LoadChampionImageAsync(champ); + } + + private async Task LoadChampionImageAsync(Champion? champ) + { + if(champ == null) return null; + var imageUrl = $"http://ddragon.leagueoflegends.com/cdn/{LeagueClientVersion}/img/champion/{champ.Image.Full}"; + try + { + await using var stream = await httpClient.GetStreamAsync(imageUrl); + return new Bitmap(stream); + } + catch + { + return null; + } + } + + private async Task getClientVersion() + { + try + { + var versionStr = await httpClient.GetStringAsync("https://ddragon.leagueoflegends.com/api/versions.json"); + var versions = JsonSerializer.Deserialize>(versionStr); + return versions?[0] ?? "Unavailable"; + } + catch + { + return "Unavailable"; + } + } + + private async Task getChampions() + { + if (httpClient == null) httpClient = new HttpClient(); + + LeagueClientVersion = await getClientVersion(); + if (LeagueClientVersion == "Unavailable") return; + + try + { + var url = $"http://ddragon.leagueoflegends.com/cdn/{LeagueClientVersion}/data/de_DE/champion.json"; + var json = await httpClient.GetStringAsync(url); + var options = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + IgnoreReadOnlyProperties = true, + AllowTrailingCommas = true, + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull + }; + + var wrapper = JsonSerializer.Deserialize(json, options); + + _championList = wrapper?.Data?.Values.ToList() ?? new List(); + + } + catch (Exception ex) + { + Console.WriteLine("Fehler beim Laden der Champion-Daten: " + ex.Message); + } + } + + private async void getRandomChampionLaneComboCommandExecute() + { + var champ = _championList?[Random.Shared.Next(_championList.Count)]; + if (champ != null) + { + await LoadAndSetChampionImageAsync(champ); + // champ.ImageBitmap = await LoadChampionImageAsync(champ); + SelectedChampion = champ; + } + Lane = Lanes[Random.Shared.Next(Lanes.Count)]; + } + + public async Task InitAsync() + { + await getClientVersion(); + await getChampions(); + } + + public MainWindowViewModel() + { + getRandomChampionLaneComboCommand = new RelayCommand(getRandomChampionLaneComboCommandExecute); + _ = InitAsync(); + } +} \ No newline at end of file diff --git a/LOLRLCG/ViewModels/ViewModelBase.cs b/LOLRLCG/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..cf90a94 --- /dev/null +++ b/LOLRLCG/ViewModels/ViewModelBase.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace LOLRLCG.ViewModels; + +public class ViewModelBase : ObservableObject +{ +} \ No newline at end of file diff --git a/LOLRLCG/Views/MainWindow.axaml b/LOLRLCG/Views/MainWindow.axaml new file mode 100644 index 0000000..c1dfb0e --- /dev/null +++ b/LOLRLCG/Views/MainWindow.axaml @@ -0,0 +1,47 @@ + + + + 1280 + 720 + + + + + + + + + + + + + + + + + + + + + + + +