diff --git a/src/Gml.Client b/src/Gml.Client index 03c0179..3f2f87e 160000 --- a/src/Gml.Client +++ b/src/Gml.Client @@ -1 +1 @@ -Subproject commit 03c0179a5492e8e00177d00ba908a2a6b396c731 +Subproject commit 3f2f87ef88e281cf0dfd7b5a9d0c32de76d9ed32 diff --git a/src/Gml.Launcher/App.axaml b/src/Gml.Launcher/App.axaml index 863037e..b28e453 100644 --- a/src/Gml.Launcher/App.axaml +++ b/src/Gml.Launcher/App.axaml @@ -6,7 +6,7 @@ - + avares://Gml.Launcher/Assets/Fonts#Manrope @@ -32,7 +32,7 @@ - + diff --git a/src/Gml.Launcher/App.axaml.cs b/src/Gml.Launcher/App.axaml.cs index e85de60..fad59ec 100644 --- a/src/Gml.Launcher/App.axaml.cs +++ b/src/Gml.Launcher/App.axaml.cs @@ -1,15 +1,12 @@ -using System.Globalization; -using System.Threading.Tasks; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Gml.Launcher.ViewModels; using Gml.Launcher.Views; -using Gml.Launcher.Views.SplashScreen; namespace Gml.Launcher; -public partial class App : Application +public class App : Application { public override void Initialize() { @@ -20,11 +17,10 @@ public override async void OnFrameworkInitializationCompleted() { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - #if DEBUG desktop.MainWindow = new MainWindow { - DataContext = new MainWindowViewModel(), + DataContext = new MainWindowViewModel() }; #else var splashViewModel = new SplashScreenViewModel(); diff --git a/src/Gml.Launcher/Assets/Images/app.svg b/src/Gml.Launcher/Assets/Images/app.svg index 11116f7..c49c6f7 100644 --- a/src/Gml.Launcher/Assets/Images/app.svg +++ b/src/Gml.Launcher/Assets/Images/app.svg @@ -1,4 +1,8 @@ - - + + diff --git a/src/Gml.Launcher/Assets/Images/back.svg b/src/Gml.Launcher/Assets/Images/back.svg index fd187f2..9d38e3b 100644 --- a/src/Gml.Launcher/Assets/Images/back.svg +++ b/src/Gml.Launcher/Assets/Images/back.svg @@ -1,4 +1,8 @@ - - + + diff --git a/src/Gml.Launcher/Assets/Images/document.svg b/src/Gml.Launcher/Assets/Images/document.svg index e29421c..80302f3 100644 --- a/src/Gml.Launcher/Assets/Images/document.svg +++ b/src/Gml.Launcher/Assets/Images/document.svg @@ -1,4 +1,8 @@ - - + + diff --git a/src/Gml.Launcher/Assets/Images/download.svg b/src/Gml.Launcher/Assets/Images/download.svg index 8721030..616335b 100644 --- a/src/Gml.Launcher/Assets/Images/download.svg +++ b/src/Gml.Launcher/Assets/Images/download.svg @@ -1,12 +1,14 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/src/Gml.Launcher/Assets/Images/folder.svg b/src/Gml.Launcher/Assets/Images/folder.svg new file mode 100644 index 0000000..3848212 --- /dev/null +++ b/src/Gml.Launcher/Assets/Images/folder.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/src/Gml.Launcher/Assets/Images/home.svg b/src/Gml.Launcher/Assets/Images/home.svg index ba40e6d..38aa181 100644 --- a/src/Gml.Launcher/Assets/Images/home.svg +++ b/src/Gml.Launcher/Assets/Images/home.svg @@ -1,3 +1,5 @@ - + diff --git a/src/Gml.Launcher/Assets/Images/lang-ru.svg b/src/Gml.Launcher/Assets/Images/lang-ru.svg index d76f4a2..a5d77d7 100644 --- a/src/Gml.Launcher/Assets/Images/lang-ru.svg +++ b/src/Gml.Launcher/Assets/Images/lang-ru.svg @@ -1,30 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Gml.Launcher/Assets/Images/lang-us.svg b/src/Gml.Launcher/Assets/Images/lang-us.svg index 71f15b1..9f76438 100644 --- a/src/Gml.Launcher/Assets/Images/lang-us.svg +++ b/src/Gml.Launcher/Assets/Images/lang-us.svg @@ -1,31 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Gml.Launcher/Assets/Images/login.svg b/src/Gml.Launcher/Assets/Images/login.svg index 152bd47..2a03f69 100644 --- a/src/Gml.Launcher/Assets/Images/login.svg +++ b/src/Gml.Launcher/Assets/Images/login.svg @@ -1,4 +1,8 @@ - - + + diff --git a/src/Gml.Launcher/Assets/Images/logo.svg b/src/Gml.Launcher/Assets/Images/logo.svg index 0cf4e23..abfb506 100644 --- a/src/Gml.Launcher/Assets/Images/logo.svg +++ b/src/Gml.Launcher/Assets/Images/logo.svg @@ -1,3 +1,5 @@ - + diff --git a/src/Gml.Launcher/Assets/Images/logout.svg b/src/Gml.Launcher/Assets/Images/logout.svg index f9d85d1..2cd4861 100644 --- a/src/Gml.Launcher/Assets/Images/logout.svg +++ b/src/Gml.Launcher/Assets/Images/logout.svg @@ -1,3 +1,5 @@ - + diff --git a/src/Gml.Launcher/Assets/Images/profile.svg b/src/Gml.Launcher/Assets/Images/profile.svg index 7a6dd68..53ef4a9 100644 --- a/src/Gml.Launcher/Assets/Images/profile.svg +++ b/src/Gml.Launcher/Assets/Images/profile.svg @@ -1,6 +1,10 @@ - - - - + + + + diff --git a/src/Gml.Launcher/Assets/Images/ram.svg b/src/Gml.Launcher/Assets/Images/ram.svg index 9a55e6b..3e23976 100644 --- a/src/Gml.Launcher/Assets/Images/ram.svg +++ b/src/Gml.Launcher/Assets/Images/ram.svg @@ -1,7 +1,17 @@ - - - - - + + + + + diff --git a/src/Gml.Launcher/Assets/Images/settings.svg b/src/Gml.Launcher/Assets/Images/settings.svg index f53fdc1..b88bf8c 100644 --- a/src/Gml.Launcher/Assets/Images/settings.svg +++ b/src/Gml.Launcher/Assets/Images/settings.svg @@ -1,8 +1,12 @@ - - - - - - + + + + + + diff --git a/src/Gml.Launcher/Assets/Images/users.svg b/src/Gml.Launcher/Assets/Images/users.svg index b8970a1..1590120 100644 --- a/src/Gml.Launcher/Assets/Images/users.svg +++ b/src/Gml.Launcher/Assets/Images/users.svg @@ -1,8 +1,20 @@ - - - - - - + + + + + + diff --git a/src/Gml.Launcher/Assets/Images/vk.svg b/src/Gml.Launcher/Assets/Images/vk.svg index a05a4d0..340e9ea 100644 --- a/src/Gml.Launcher/Assets/Images/vk.svg +++ b/src/Gml.Launcher/Assets/Images/vk.svg @@ -1,3 +1,5 @@ - + diff --git a/src/Gml.Launcher/Assets/Images/window.svg b/src/Gml.Launcher/Assets/Images/window.svg index a905304..598d1e1 100644 --- a/src/Gml.Launcher/Assets/Images/window.svg +++ b/src/Gml.Launcher/Assets/Images/window.svg @@ -1,4 +1,6 @@ - - + + diff --git a/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.Template.cs b/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.Template.cs index 6295512..7c45c1e 100644 --- a/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.Template.cs +++ b/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.Template.cs @@ -7,6 +7,8 @@ public static class ResourceKeysDictionary public const string Error = "Error"; public const string NotSetting = "NotSetting"; public const string Updating = "Updating"; + public const string Stay = "Stay"; + public const string Files = "Files"; public const string DefaultDRpcText = "DefaultDRpcText"; public const string PlayDRpcText = "PlayDRpcText"; public const string Launching = "Launching"; diff --git a/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.cs b/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.cs index 9b77891..e10bcee 100644 --- a/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.cs +++ b/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.cs @@ -5,8 +5,11 @@ public static class ResourceKeysDictionary public const string MainPageTitle = "DefaultPageTitle"; public const string DefaultPageTitle = "DefaultPageTitle"; public const string Error = "Error"; + public const string InvalidFolder = "InvalidFolder"; public const string NotSetting = "NotSetting"; public const string Updating = "Updating"; + public const string Stay = "Stay"; + public const string Files = "Files"; public const string DefaultDRpcText = "DefaultDRpcText"; public const string PlayDRpcText = "PlayDRpcText"; public const string Launching = "Launching"; @@ -20,9 +23,10 @@ public static class ResourceKeysDictionary public const string CheckUpdates = "CheckUpdates"; public const string InstallingUpdates = "InstallingUpdates"; public const string FailedOs = "FailedOs"; + public const string JavaNotFound = "JavaNotFound"; - // public const string Host = "http://192.168.31.199:5000"; - public const string Host = "https://gmlb.recloud.tech"; - // public const string Host = "https://gmlb-test.recloud.tech"; + + // public const string Host = "https://gmlb.recloud.tech"; + public const string Host = "https://gmlb-test.recloud.tech"; public const string FolderName = "GamerVIILacunerhV2"; } diff --git a/src/Gml.Launcher/Assets/Resources/Resources.Designer.cs b/src/Gml.Launcher/Assets/Resources/Resources.Designer.cs index ef35d1a..649e671 100644 --- a/src/Gml.Launcher/Assets/Resources/Resources.Designer.cs +++ b/src/Gml.Launcher/Assets/Resources/Resources.Designer.cs @@ -218,5 +218,45 @@ public static string PlayersShort { return ResourceManager.GetString("PlayersShort", resourceCulture); } } + /// + /// Ищет локализованную строку, похожую на ProfileNotConfigured. + /// + public static string InstallationDirectory { + get { + return ResourceManager.GetString("InstallationDirectory", resourceCulture); + } + } + /// + /// Ищет локализованную строку, похожую на ProfileNotConfigured. + /// + public static string Edit { + get { + return ResourceManager.GetString("Edit", resourceCulture); + } + } + /// + /// Ищет локализованную строку, похожую на ProfileNotConfigured. + /// + public static string Stay { + get { + return ResourceManager.GetString("Stay", resourceCulture); + } + } + /// + /// Ищет локализованную строку, похожую на ProfileNotConfigured. + /// + public static string Files { + get { + return ResourceManager.GetString("Files", resourceCulture); + } + } + /// + /// Ищет локализованную строку, похожую на ProfileNotConfigured. + /// + public static string InvalidFolder { + get { + return ResourceManager.GetString("InvalidFolder", resourceCulture); + } + } } } diff --git a/src/Gml.Launcher/Assets/Resources/Resources.en.resx b/src/Gml.Launcher/Assets/Resources/Resources.en.resx index e4546a5..3441c25 100644 --- a/src/Gml.Launcher/Assets/Resources/Resources.en.resx +++ b/src/Gml.Launcher/Assets/Resources/Resources.en.resx @@ -6,10 +6,14 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Sign in @@ -116,4 +120,19 @@ Unable to detect a loaded Java for your operating system, please contact support or the project administrator. + + Install folder + + + Change + + + Stay + + + files + + + Failed to change the installation folder or an error occurred while changing the folder. + diff --git a/src/Gml.Launcher/Assets/Resources/Resources.resx b/src/Gml.Launcher/Assets/Resources/Resources.resx index a69dbe2..32ad5b3 100644 --- a/src/Gml.Launcher/Assets/Resources/Resources.resx +++ b/src/Gml.Launcher/Assets/Resources/Resources.resx @@ -1,7 +1,8 @@  - + @@ -13,10 +14,14 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + Sign in @@ -123,4 +128,19 @@ Unable to detect a loaded Java for your operating system, please contact support or the project administrator. + + Install folder + + + Change + + + Stay + + + files + + + Failed to change the installation folder or an error occurred while changing the folder. + diff --git a/src/Gml.Launcher/Assets/Resources/Resources.ru.resx b/src/Gml.Launcher/Assets/Resources/Resources.ru.resx index b051bee..b1a4814 100644 --- a/src/Gml.Launcher/Assets/Resources/Resources.ru.resx +++ b/src/Gml.Launcher/Assets/Resources/Resources.ru.resx @@ -6,10 +6,14 @@ 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + АВТОРИЗОВАТЬСЯ @@ -116,4 +120,19 @@ Не удалось обнаружить загруженную Java для Вашей операционной системы, обратитесь в поддержку или к администратору проекта - \ No newline at end of file + + Папка установки + + + Изменить + + + Осталось + + + файлов + + + Не получилось сменить папку установки или произошла ошибка при смене папки + + diff --git a/src/Gml.Launcher/Assets/Styles/Classes.axaml b/src/Gml.Launcher/Assets/Styles/Classes.axaml index 25e29a7..73385c9 100644 --- a/src/Gml.Launcher/Assets/Styles/Classes.axaml +++ b/src/Gml.Launcher/Assets/Styles/Classes.axaml @@ -4,105 +4,104 @@ - + - diff --git a/src/Gml.Launcher/Assets/Styles/Colors.axaml b/src/Gml.Launcher/Assets/Styles/Colors.axaml index 22aef54..e279c8c 100644 --- a/src/Gml.Launcher/Assets/Styles/Colors.axaml +++ b/src/Gml.Launcher/Assets/Styles/Colors.axaml @@ -48,4 +48,3 @@ - diff --git a/src/Gml.Launcher/Core/Converters/AsyncSkinRenderLoader.cs b/src/Gml.Launcher/Core/Converters/AsyncSkinRenderLoader.cs index 24b03a3..107c8c9 100644 --- a/src/Gml.Launcher/Core/Converters/AsyncSkinRenderLoader.cs +++ b/src/Gml.Launcher/Core/Converters/AsyncSkinRenderLoader.cs @@ -17,10 +17,10 @@ public class AsyncSkinRenderLoader public static readonly AttachedProperty SourceProperty = AvaloniaProperty.RegisterAttached("Source"); - public static readonly AttachedProperty IsLoadingProperty = + private static readonly AttachedProperty IsLoadingProperty = AvaloniaProperty.RegisterAttached("IsLoading"); - private static ConcurrentDictionary _pendingOperations = new(); + private static readonly ConcurrentDictionary PendingOperations = new(); static AsyncSkinRenderLoader() { @@ -32,10 +32,10 @@ private static async void OnSourceChanged(Image sender, AvaloniaPropertyChangedE try { SetIsLoading(sender, true); - CancellationTokenSource cts = _pendingOperations.AddOrUpdate( + var cts = PendingOperations.AddOrUpdate( sender, new CancellationTokenSource(), - (x, y) => + (_, y) => { y.Cancel(); return new CancellationTokenSource(); @@ -45,7 +45,7 @@ private static async void OnSourceChanged(Image sender, AvaloniaPropertyChangedE if (string.IsNullOrEmpty(url)) { - _pendingOperations.Remove(sender, out _); + PendingOperations.Remove(sender, out _); sender.Source = null; return; } @@ -61,10 +61,7 @@ private static async void OnSourceChanged(Image sender, AvaloniaPropertyChangedE var bitmap = new Bitmap(new MemoryStream(SkinViewer.GetFront(stream, 128))); - if (!cts.Token.IsCancellationRequested) - { - sender.Source = bitmap; - } + if (!cts.Token.IsCancellationRequested) sender.Source = bitmap; } catch (Exception e) { @@ -72,7 +69,7 @@ private static async void OnSourceChanged(Image sender, AvaloniaPropertyChangedE } finally { - _pendingOperations.Remove(sender, out _); + PendingOperations.Remove(sender, out _); SetIsLoading(sender, false); } } @@ -83,9 +80,23 @@ private static bool ValidateUrl(string url) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); } - public static void SetSource(Image obj, string value) => obj.SetValue(SourceProperty, value); - public static string GetSource(Image obj) => obj.GetValue(SourceProperty); + public static void SetSource(Image obj, string value) + { + obj.SetValue(SourceProperty, value); + } + + public static string GetSource(Image obj) + { + return obj.GetValue(SourceProperty); + } + + private static void SetIsLoading(Image obj, bool value) + { + obj.SetValue(IsLoadingProperty, value); + } - private static void SetIsLoading(Image obj, bool value) => obj.SetValue(IsLoadingProperty, value); - public static bool GetIsLoading(Image obj) => obj.GetValue(IsLoadingProperty); + public static bool GetIsLoading(Image obj) + { + return obj.GetValue(IsLoadingProperty); + } } diff --git a/src/Gml.Launcher/Core/Converters/AsyncStreamToImageLoader.cs b/src/Gml.Launcher/Core/Converters/AsyncStreamToImageLoader.cs index bac3861..760ca6c 100644 --- a/src/Gml.Launcher/Core/Converters/AsyncStreamToImageLoader.cs +++ b/src/Gml.Launcher/Core/Converters/AsyncStreamToImageLoader.cs @@ -22,7 +22,7 @@ static AsyncStreamToImageLoader() TempPath = Path.GetTempPath(); } - public static string TempPath { get; set; } + private static string TempPath { get; } private static async void OnSourceChanged(BackgroundComponent sender, AvaloniaPropertyChangedEventArgs args) { @@ -66,7 +66,6 @@ private static async void OnSourceChanged(BackgroundComponent sender, AvaloniaPr sender.Classes.Add("Image"); sender.Source = new Bitmap(fileStream); } - } catch (Exception exception) { @@ -78,15 +77,10 @@ private static async Task ConvertStreamToFile(Stream input, string filePath) { var fileInfo = new FileInfo(filePath); - if (!fileInfo.Directory!.Exists) - { - fileInfo.Directory.Create(); - } + if (!fileInfo.Directory!.Exists) fileInfo.Directory.Create(); - using (var fileStream = File.Create(filePath)) - { - await input.CopyToAsync(fileStream); - } + await using var fileStream = File.Create(filePath); + await input.CopyToAsync(fileStream); } private static bool ValidateUrl(string url) @@ -96,6 +90,13 @@ private static bool ValidateUrl(string url) && Path.GetFileName(url) is { } fileName && Guid.TryParse(fileName, out _); } - public static void SetSource(BackgroundComponent obj, string value) => obj.SetValue(SourceProperty, value); - public static string GetSource(BackgroundComponent obj) => obj.GetValue(SourceProperty); -} \ No newline at end of file + public static void SetSource(BackgroundComponent obj, string value) + { + obj.SetValue(SourceProperty, value); + } + + public static string GetSource(BackgroundComponent obj) + { + return obj.GetValue(SourceProperty); + } +} diff --git a/src/Gml.Launcher/Core/Converters/Base64ToBitmapConverter.cs b/src/Gml.Launcher/Core/Converters/Base64ToBitmapConverter.cs index 164f551..9de0a23 100644 --- a/src/Gml.Launcher/Core/Converters/Base64ToBitmapConverter.cs +++ b/src/Gml.Launcher/Core/Converters/Base64ToBitmapConverter.cs @@ -12,18 +12,18 @@ public class Base64ToBitmapConverter : MarkupExtension, IValueConverter { public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - if (value is string base64) + if (value is not string base64) + return AvaloniaProperty.UnsetValue; + + try + { + var bytes = System.Convert.FromBase64String(base64); + using var ms = new MemoryStream(bytes); + return new Bitmap(ms); + } + catch { - try - { - var bytes = System.Convert.FromBase64String(base64); - using var ms = new MemoryStream(bytes); - return new Bitmap(ms); - } - catch - { - // ignored - } + // ignored } return AvaloniaProperty.UnsetValue; @@ -34,5 +34,8 @@ public object ConvertBack(object? value, Type targetType, object? parameter, Cul throw new NotImplementedException(); } - public override object ProvideValue(IServiceProvider serviceProvider) => this; + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; + } } diff --git a/src/Gml.Launcher/Core/Converters/BoolReverseConverter.cs b/src/Gml.Launcher/Core/Converters/BoolReverseConverter.cs index f2e6c42..11c1e9d 100644 --- a/src/Gml.Launcher/Core/Converters/BoolReverseConverter.cs +++ b/src/Gml.Launcher/Core/Converters/BoolReverseConverter.cs @@ -7,20 +7,20 @@ namespace Gml.Launcher.Core.Converters; public class BoolReverseConverter : MarkupExtension, IValueConverter { - public override object ProvideValue(IServiceProvider serviceProvider) => this; - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - if (bool.TryParse(value?.ToString(), out bool boolValue)) - { - return !boolValue; - } + if (bool.TryParse(value?.ToString(), out var boolValue)) return !boolValue; return null; } public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { - throw new NotImplementedException(); + return null; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; } } diff --git a/src/Gml.Launcher/Core/Converters/FirstElementConverter.cs b/src/Gml.Launcher/Core/Converters/FirstElementConverter.cs index 7f43c0b..117233f 100644 --- a/src/Gml.Launcher/Core/Converters/FirstElementConverter.cs +++ b/src/Gml.Launcher/Core/Converters/FirstElementConverter.cs @@ -9,20 +9,20 @@ namespace Gml.Launcher.Core.Converters; public class FirstElementConverter : MarkupExtension, IValueConverter { - public override object ProvideValue(IServiceProvider serviceProvider) => this; - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - if (value is IEnumerable enumerable) - { - return enumerable.FirstOrDefault(); - } + if (value is IEnumerable enumerable) return enumerable.FirstOrDefault(); return null; } public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { - throw new NotImplementedException(); + return null; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; } } diff --git a/src/Gml.Launcher/Core/Converters/HasElementsConverter.cs b/src/Gml.Launcher/Core/Converters/HasElementsConverter.cs index 61ca604..f7a8f89 100644 --- a/src/Gml.Launcher/Core/Converters/HasElementsConverter.cs +++ b/src/Gml.Launcher/Core/Converters/HasElementsConverter.cs @@ -9,20 +9,20 @@ namespace Gml.Launcher.Core.Converters; public class HasElementsConverter : MarkupExtension, IValueConverter { - public override object ProvideValue(IServiceProvider serviceProvider) => this; - - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - if (value is IEnumerable enumerable) - { - return enumerable.Any(); - } + if (value is IEnumerable enumerable) return enumerable.Any(); return false; } public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { - throw new NotImplementedException(); + return null; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; } } diff --git a/src/Gml.Launcher/Core/Converters/NoiseStringAddConverter.cs b/src/Gml.Launcher/Core/Converters/NoiseStringAddConverter.cs index a278a23..0ca83ce 100644 --- a/src/Gml.Launcher/Core/Converters/NoiseStringAddConverter.cs +++ b/src/Gml.Launcher/Core/Converters/NoiseStringAddConverter.cs @@ -7,20 +7,20 @@ namespace Gml.Launcher.Core.Converters; public class NoiseStringAddConverter : MarkupExtension, IValueConverter { - public override object ProvideValue(IServiceProvider serviceProvider) => this; - - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - if (value is not null && value.ToString()!.Contains('?')) - { - return value; - } + if (value is not null && value.ToString()!.Contains('?')) return value; return $"{value}?{DateTime.Now:mm-ss-fff}"; } public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { - throw new NotImplementedException(); + return null; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; } } diff --git a/src/Gml.Launcher/Core/Converters/SumServersOnlineConverter.cs b/src/Gml.Launcher/Core/Converters/SumServersOnlineConverter.cs index d32a61e..2c84c78 100644 --- a/src/Gml.Launcher/Core/Converters/SumServersOnlineConverter.cs +++ b/src/Gml.Launcher/Core/Converters/SumServersOnlineConverter.cs @@ -10,23 +10,24 @@ namespace Gml.Launcher.Core.Converters; public class SumServersOnlineConverter : MarkupExtension, IValueConverter { - public override object ProvideValue(IServiceProvider serviceProvider) => this; - - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is List server) - { return server .Where(c => c.IsOnline) .Sum(c => c.Online)? .ToString() ?? "0"; - } return "0"; } - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { return "0"; } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; + } } diff --git a/src/Gml.Launcher/Core/Converters/UrlRedirectProperty.cs b/src/Gml.Launcher/Core/Converters/UrlRedirectProperty.cs index 54cdad5..a93a88c 100644 --- a/src/Gml.Launcher/Core/Converters/UrlRedirectProperty.cs +++ b/src/Gml.Launcher/Core/Converters/UrlRedirectProperty.cs @@ -6,17 +6,24 @@ namespace Gml.Launcher.Core.Converters; public class UrlRedirectProperty { - public static readonly AttachedProperty RedirectUrlProperty = + private static readonly AttachedProperty RedirectUrlProperty = AvaloniaProperty.RegisterAttached("RedirectUrl"); - public static void SetRedirectUrl(Control obj, string value) => obj.SetValue(RedirectUrlProperty, value); - public static string GetRedirectUrl(Control obj) => obj.GetValue(RedirectUrlProperty); - public UrlRedirectProperty() { RedirectUrlProperty.Changed.AddClassHandler(OnSourceChanged); } + public static void SetRedirectUrl(Control obj, string value) + { + obj.SetValue(RedirectUrlProperty, value); + } + + public static string GetRedirectUrl(Control obj) + { + return obj.GetValue(RedirectUrlProperty); + } + private void OnSourceChanged(Control control, AvaloniaPropertyChangedEventArgs args) { var url = args.GetNewValue(); diff --git a/src/Gml.Launcher/Core/Exceptions/ServiceNotFoundException.cs b/src/Gml.Launcher/Core/Exceptions/ServiceNotFoundException.cs index 211e181..6ff1ba2 100644 --- a/src/Gml.Launcher/Core/Exceptions/ServiceNotFoundException.cs +++ b/src/Gml.Launcher/Core/Exceptions/ServiceNotFoundException.cs @@ -2,12 +2,7 @@ namespace Gml.Launcher.Core.Exceptions; -public class ServiceNotFoundException : Exception +public class ServiceNotFoundException(Type eType) : Exception { - public Type NotFoundedService { get;} - - public ServiceNotFoundException(Type eType) - { - NotFoundedService = eType; - } + public Type NotFoundedService { get; } = eType; } diff --git a/src/Gml.Launcher/Core/Extensions/ServiceLocator.cs b/src/Gml.Launcher/Core/Extensions/ServiceLocator.cs index a0987dd..ed9b035 100644 --- a/src/Gml.Launcher/Core/Extensions/ServiceLocator.cs +++ b/src/Gml.Launcher/Core/Extensions/ServiceLocator.cs @@ -1,5 +1,4 @@ using System; -using System.Configuration; using System.Globalization; using System.IO; using System.Linq; @@ -20,41 +19,33 @@ public static AppBuilder RegisterServices(this AppBuilder builder) { var systemService = new SystemService(); - var configurationManager = ConfigurationManager.OpenMachineConfiguration(); - var installationDirectory = Path.Combine(systemService.GetApplicationFolder(), ResourceKeysDictionary.FolderName); - Locator.CurrentMutable.RegisterConstant(new ResourceLocalizationService(), typeof(ILocalizationService)); - Locator.CurrentMutable.RegisterConstant(systemService, typeof(ISystemService)); - Locator.CurrentMutable.RegisterConstant( - new GmlClientManager(installationDirectory, ResourceKeysDictionary.Host, ResourceKeysDictionary.FolderName, - systemService.GetOsType()), typeof(IGmlClientManager)); - - var storageService = new LocalStorageService(); - Locator.CurrentMutable.RegisterConstant(storageService, typeof(IStorageService)); - - var data = storageService.GetAsync(StorageConstants.Settings).Result; + RegisterLocalizationService(); + RegisterSystemService(systemService); + var manager = RegisterGmlManager(systemService, installationDirectory); + var storageService = RegisterStorage(); - if (data != null && !string.IsNullOrEmpty(data.LanguageCode)) - { - Thread.CurrentThread.CurrentCulture = systemService - .GetAvailableLanguages() - .FirstOrDefault(c => c.Culture.Name == data.LanguageCode)? - .Culture ?? new CultureInfo("ru-RU");; - } + CheckAndChangeInstallationFolder(storageService, manager); + CheckAndChangeLanguage(storageService, systemService); + InitializeSentry(); - AppDomain.CurrentDomain.UnhandledException += (sender, args) => + AppDomain.CurrentDomain.UnhandledException += (_, args) => { SentrySdk.CaptureException((Exception)args.ExceptionObject); }; + return builder; + } + + private static void InitializeSentry() + { var sentryUrl = GmlClientManager.GetSentryLink(ResourceKeysDictionary.Host).Result; try { if (!string.IsNullOrEmpty(sentryUrl)) - { SentrySdk.Init(options => { options.Dsn = sentryUrl; @@ -65,13 +56,58 @@ public static AppBuilder RegisterServices(this AppBuilder builder) options.SendDefaultPii = true; options.MaxAttachmentSize = 10 * 1024 * 1024; }); - } } catch (Exception exception) { Console.WriteLine(exception); } + } - return builder; + private static void CheckAndChangeLanguage(LocalStorageService storageService, SystemService systemService) + { + var data = storageService.GetAsync(StorageConstants.Settings).Result; + + if (data != null && !string.IsNullOrEmpty(data.LanguageCode)) + Thread.CurrentThread.CurrentCulture = systemService + .GetAvailableLanguages() + .FirstOrDefault(c => c.Culture.Name == data.LanguageCode)? + .Culture ?? new CultureInfo("ru-RU"); + } + + private static LocalStorageService RegisterStorage() + { + var storageService = new LocalStorageService(); + Locator.CurrentMutable.RegisterConstant(storageService, typeof(IStorageService)); + + return storageService; + } + + private static void CheckAndChangeInstallationFolder(LocalStorageService storageService, GmlClientManager manager) + { + var installationDirectory = storageService.GetAsync(StorageConstants.InstallationDirectory).Result; + + if (!string.IsNullOrEmpty(installationDirectory)) manager.ChangeInstallationFolder(installationDirectory); + } + + private static GmlClientManager RegisterGmlManager(SystemService systemService, string installationDirectory) + { + var manager = new GmlClientManager(installationDirectory, ResourceKeysDictionary.Host, + ResourceKeysDictionary.FolderName, + systemService.GetOsType()); + + Locator.CurrentMutable.RegisterConstant(manager, typeof(IGmlClientManager)); + + return manager; + } + + private static void RegisterSystemService(SystemService systemService) + { + Locator.CurrentMutable.RegisterConstant(systemService, typeof(ISystemService)); + } + + private static void RegisterLocalizationService() + { + var service = new ResourceLocalizationService(); + Locator.CurrentMutable.RegisterConstant(service, typeof(ILocalizationService)); } } diff --git a/src/Gml.Launcher/Core/Helpers/AppViewLocator.cs b/src/Gml.Launcher/Core/Helpers/AppViewLocator.cs index 59661a6..e50f6cb 100644 --- a/src/Gml.Launcher/Core/Helpers/AppViewLocator.cs +++ b/src/Gml.Launcher/Core/Helpers/AppViewLocator.cs @@ -7,13 +7,16 @@ namespace Gml.Launcher.Core.Helpers; public class AppViewLocator : IViewLocator { - public IViewFor ResolveView(T? viewModel, string? contract = null) => viewModel switch + public IViewFor ResolveView(T? viewModel, string? contract = null) { - OverviewPageViewModel context => new OverviewPageView { DataContext = context }, - ProfilePageViewModel context => new ProfilePageView { DataContext = context }, - SettingsPageViewModel context => new SettingsPageView { DataContext = context }, - LoginPageViewModel context => new LoginPageView { DataContext = context }, + return viewModel switch + { + OverviewPageViewModel context => new OverviewPageView { DataContext = context }, + ProfilePageViewModel context => new ProfilePageView { DataContext = context }, + SettingsPageViewModel context => new SettingsPageView { DataContext = context }, + LoginPageViewModel context => new LoginPageView { DataContext = context }, - _ => throw new ArgumentOutOfRangeException(nameof(viewModel)) - }; + _ => throw new ArgumentOutOfRangeException(nameof(viewModel)) + }; + } } diff --git a/src/Gml.Launcher/Core/Services/ILocalizationService.cs b/src/Gml.Launcher/Core/Services/ILocalizationService.cs index 7f83090..6c621e3 100644 --- a/src/Gml.Launcher/Core/Services/ILocalizationService.cs +++ b/src/Gml.Launcher/Core/Services/ILocalizationService.cs @@ -1,6 +1,14 @@ namespace Gml.Launcher.Core.Services; +/// +/// Represents the interface for localization services. +/// public interface ILocalizationService { + /// + /// Retrieves a localized string for the specified key. + /// + /// The key of the localized string. + /// The localized string. string GetString(string key); } diff --git a/src/Gml.Launcher/Core/Services/IStorageService.cs b/src/Gml.Launcher/Core/Services/IStorageService.cs index 1ae41a5..0fcb976 100644 --- a/src/Gml.Launcher/Core/Services/IStorageService.cs +++ b/src/Gml.Launcher/Core/Services/IStorageService.cs @@ -1,17 +1,15 @@ -using System.Collections.Generic; -using System.Threading; +using System.Threading; using System.Threading.Tasks; -using Gml.Launcher.Models; namespace Gml.Launcher.Core.Services; /// -/// Represents a storage service interface used for saving and retrieving data. +/// Represents a storage service interface used for saving and retrieving data. /// public interface IStorageService { /// - /// Stores the provided value with the specified key asynchronously. + /// Stores the provided value with the specified key asynchronously. /// /// The type of the value to store. /// The key for the value. @@ -21,23 +19,28 @@ public interface IStorageService Task SetAsync(string key, T value, CancellationToken? token = default); /// - /// Retrieves the value associated with the specified key asynchronously. + /// Retrieves the value associated with the specified key asynchronously. /// /// The type of the value. /// The key of the value to retrieve. /// - /// A task representing the asynchronous operation. The task result contains the retrieved value, - /// or null if the key does not exist in the storage. + /// A task representing the asynchronous operation. The task result contains the retrieved value, + /// or null if the key does not exist in the storage. /// Task GetAsync(string key); /// - /// Saves a record of type T to the storage service. + /// Saves a record of type T to the storage service. /// /// The type of the record to save. /// The record to save. /// A task representing the asynchronous save operation. Task SaveRecord(T value); + /// + /// Retrieves the logs from the storage service asynchronously. + /// + /// The maximum number of logs to retrieve. Default value is 100. + /// A task representing the asynchronous operation. The task result contains the logs as a concatenated string. Task GetLogsAsync(int rowCount); } diff --git a/src/Gml.Launcher/Core/Services/ISystemService.cs b/src/Gml.Launcher/Core/Services/ISystemService.cs index 22177d8..3f15683 100644 --- a/src/Gml.Launcher/Core/Services/ISystemService.cs +++ b/src/Gml.Launcher/Core/Services/ISystemService.cs @@ -5,13 +5,51 @@ namespace Gml.Launcher.Core.Services; +/// +/// Represents a system service that provides various system-related information and functionalities. +/// public interface ISystemService { + /// + /// Retrieves the application folder path based on the current operating system. + /// + /// The path to the application folder. string GetApplicationFolder(); + + /// Retrieves the game folder path. + /// @param additionalPath The additional path within the game folder. Can be null or empty. + /// @param needCreate Specify whether the folder should be created if it does not exist. + /// @return The full path to the game folder, including the additional path if provided. + /// / string GetGameFolder(string additionalPath, bool needCreate); + + /// + /// Gets the maximum amount of RAM available in the system in megabytes. + /// + /// The maximum amount of RAM available in the system in megabytes. ulong GetMaxRam(); + + /// + /// Gets the operating system type. + /// + /// The operating system type. Possible values are: Undefined, Linux, OsX, Windows. OsType GetOsType(); + + /// + /// Gets the available languages. + /// + /// An enumerable of Language objects representing the available languages. IEnumerable GetAvailableLanguages(); + + /// + /// Gets the hardware identification (HWID) of the system. + /// + /// The HWID of the system. string GetHwid(); + + /// + /// Asynchronously loads system data such as drive list, motherboard list, and CPU list. + /// + /// A task representing the asynchronous operation. Task LoadSystemData(); } diff --git a/src/Gml.Launcher/Core/Services/LocalStorageService.cs b/src/Gml.Launcher/Core/Services/LocalStorageService.cs index 40d088d..a1dbda9 100644 --- a/src/Gml.Launcher/Core/Services/LocalStorageService.cs +++ b/src/Gml.Launcher/Core/Services/LocalStorageService.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.IO; +using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -13,31 +14,25 @@ public class LocalStorageService : IStorageService { private const string DatabaseFileName = "data.db"; private readonly SQLiteAsyncConnection _database; - private readonly IGmlClientManager _gmlClient; - private readonly ISystemService _systemService; public LocalStorageService(ISystemService? systemService = null, IGmlClientManager? gmlClient = null) { - _gmlClient = gmlClient - ?? Locator.Current.GetService() - ?? throw new ServiceNotFoundException(typeof(IGmlClientManager)); + var gmlClientManager = gmlClient + ?? Locator.Current.GetService() + ?? throw new ServiceNotFoundException(typeof(IGmlClientManager)); - _systemService ??= Locator.Current.GetService() - ?? throw new ServiceNotFoundException(typeof(ISystemService)); + var systemServiceDependency = systemService + ?? Locator.Current.GetService() + ?? throw new ServiceNotFoundException(typeof(ISystemService)); - var databasePath = System.IO.Path.Combine(_systemService.GetGameFolder(_gmlClient.ProjectName ,true), DatabaseFileName); + var databasePath = Path.Combine(systemServiceDependency.GetGameFolder(gmlClientManager.ProjectName, true), + DatabaseFileName); _database = new SQLiteAsyncConnection(databasePath); InitializeTables(); } - private void InitializeTables() - { - _database.CreateTableAsync().Wait(); - _database.CreateTableAsync().Wait(); - } - public async Task SetAsync(string key, T value, CancellationToken? token = default) { var serializedValue = JsonSerializer.Serialize(value); @@ -57,10 +52,7 @@ public async Task SetAsync(string key, T value, CancellationToken? token = de .Where(si => si.Key == key) .FirstOrDefaultAsync(); - if (storageItem != null) - { - return JsonSerializer.Deserialize(storageItem.Value); - } + if (storageItem != null) return JsonSerializer.Deserialize(storageItem.Value); return default; } @@ -77,19 +69,25 @@ public async Task GetLogsAsync(int rowCount = 100) return string.Join("\n", logs.Select(c => c.Message)); } + private void InitializeTables() + { + _database.CreateTableAsync().Wait(); + _database.CreateTableAsync().Wait(); + } + [Table("StorageItems")] private class StorageItem { - [PrimaryKey] public string Key { get; set; } = null!; + [PrimaryKey] public string Key { get; init; } = null!; public string? TypeName { get; set; } - public string Value { get; set; } = null!; + public string Value { get; init; } = null!; } [Table("Logs")] private class LogsItem { [PrimaryKey] public string Date { get; set; } = null!; - public string? Message { get; set; } + public string? Message { get; } public string StackTrace { get; set; } = null!; } } diff --git a/src/Gml.Launcher/Core/Services/ResourceLocalizationService.cs b/src/Gml.Launcher/Core/Services/ResourceLocalizationService.cs index 803990f..3bb2590 100644 --- a/src/Gml.Launcher/Core/Services/ResourceLocalizationService.cs +++ b/src/Gml.Launcher/Core/Services/ResourceLocalizationService.cs @@ -8,10 +8,7 @@ public class ResourceLocalizationService : ILocalizationService { public string GetString(string key) { - if (Application.Current == null) - { - throw new ArgumentException($"Key '{key}' not found in resources"); - } + if (Application.Current == null) throw new ArgumentException($"Key '{key}' not found in resources"); return TryGetLocalizedString(key) ?? throw new Exception($"Resource \"{key}\" not found"); } diff --git a/src/Gml.Launcher/Core/Services/SkinService.cs b/src/Gml.Launcher/Core/Services/SkinService.cs index 8d227a4..2982797 100644 --- a/src/Gml.Launcher/Core/Services/SkinService.cs +++ b/src/Gml.Launcher/Core/Services/SkinService.cs @@ -44,7 +44,7 @@ public static byte[] GetCloak(string cloakPath, int size) public static byte[] GetFront(Stream skinStream, int size) { - using Image inputImage = Image.Load(skinStream); + using var inputImage = Image.Load(skinStream); var scaleFactor = inputImage.Width / 64; diff --git a/src/Gml.Launcher/Core/Services/StorageConstants.cs b/src/Gml.Launcher/Core/Services/StorageConstants.cs index fe5d8e7..c7ac41a 100644 --- a/src/Gml.Launcher/Core/Services/StorageConstants.cs +++ b/src/Gml.Launcher/Core/Services/StorageConstants.cs @@ -5,4 +5,5 @@ public static class StorageConstants public const string User = "UserInfo"; public const string Settings = "Settings"; public const string LastSelectedProfileName = "LastSelectedProfile"; + public const string InstallationDirectory = "InstallationDirectory"; } diff --git a/src/Gml.Launcher/Core/Services/SystemService.cs b/src/Gml.Launcher/Core/Services/SystemService.cs index 2211d92..00e96d9 100644 --- a/src/Gml.Launcher/Core/Services/SystemService.cs +++ b/src/Gml.Launcher/Core/Services/SystemService.cs @@ -13,20 +13,12 @@ namespace Gml.Launcher.Core.Services; public class SystemService : ISystemService { - private readonly HardwareInfo _hardwareInfo; private const string NotSupportedMessage = "The operating system is not supported."; - - public SystemService() - { - _hardwareInfo = new HardwareInfo(); - } + private readonly HardwareInfo _hardwareInfo = new(); public ulong GetMaxRam() { - if (!(IsWindows() || IsLinux() || IsMacOS())) - { - throw new NotSupportedException(NotSupportedMessage); - } + if (!(IsWindows() || IsLinux() || IsMacOS())) throw new NotSupportedException(NotSupportedMessage); _hardwareInfo.RefreshMemoryStatus(); @@ -35,15 +27,9 @@ public ulong GetMaxRam() public string GetApplicationFolder() { - if (IsWindows()) - { - return GetFolderPath(Environment.SpecialFolder.ApplicationData); - } + if (IsWindows()) return GetFolderPath(Environment.SpecialFolder.ApplicationData); - if (IsLinux() || IsMacOS()) - { - return GetFolderPath(Environment.SpecialFolder.UserProfile); - } + if (IsLinux() || IsMacOS()) return GetFolderPath(Environment.SpecialFolder.UserProfile); throw new NotSupportedException(NotSupportedMessage); } @@ -77,27 +63,13 @@ public async Task LoadSystemData() await Task.WhenAll(refreshDriveListTask, refreshMotherboardListTask, refreshCpuListTask); } - private static string GetFolderPath(Environment.SpecialFolder folder) - { - return Environment.GetFolderPath(folder); - } - public OsType GetOsType() { - if (IsWindows()) - { - return OsType.Windows; - } + if (IsWindows()) return OsType.Windows; - if (IsLinux()) - { - return OsType.Linux; - } + if (IsLinux()) return OsType.Linux; - if (IsMacOS()) - { - return OsType.OsX; - } + if (IsMacOS()) return OsType.OsX; return OsType.Undefined; } @@ -107,7 +79,12 @@ public IEnumerable GetAvailableLanguages() return new List { new() { IconPath = "/Assets/Images/lang-ru.svg", Name = "Русский", Culture = new CultureInfo("ru-RU") }, - new() { IconPath = "/Assets/Images/lang-us.svg", Name = "English", Culture = new CultureInfo("en-US") }, + new() { IconPath = "/Assets/Images/lang-us.svg", Name = "English", Culture = new CultureInfo("en-US") } }; } + + private static string GetFolderPath(Environment.SpecialFolder folder) + { + return Environment.GetFolderPath(folder); + } } diff --git a/src/Gml.Launcher/Gml.Launcher.csproj b/src/Gml.Launcher/Gml.Launcher.csproj index b162cbb..dbb153e 100644 --- a/src/Gml.Launcher/Gml.Launcher.csproj +++ b/src/Gml.Launcher/Gml.Launcher.csproj @@ -1,95 +1,95 @@  - - WinExe - net8.0 - enable - true - app.manifest - true - Assets\Images\logo.ico - 2.1.0.0 - 2.1.0.0 - + + WinExe + net8.0 + enable + true + app.manifest + true + Assets\Images\logo.ico + 2.1.0.0 + 2.1.0.0 + - - - + + + - - - - PublicResXFileCodeGenerator - Resources.Designer.cs - - + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - ILocalizationService.cs - - - ISystemService.cs - - - True - True - Resources.resx - - - IStorageService.cs - - - + + + ILocalizationService.cs + + + ISystemService.cs + + + True + True + Resources.resx + + + IStorageService.cs + + + - - - - - - + + + + + + - - - True - True - Resource.resx - - - PublicResXFileCodeGenerator - Resource.Designer.cs - - - PublicResXFileCodeGenerator - - - PublicResXFileCodeGenerator - Resources.Designer.cs - - - PublicResXFileCodeGenerator - - + + + True + True + Resource.resx + + + PublicResXFileCodeGenerator + Resource.Designer.cs + + + PublicResXFileCodeGenerator + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + PublicResXFileCodeGenerator + + diff --git a/src/Gml.Launcher/Models/Language.cs b/src/Gml.Launcher/Models/Language.cs index fce1644..1cd0906 100644 --- a/src/Gml.Launcher/Models/Language.cs +++ b/src/Gml.Launcher/Models/Language.cs @@ -4,7 +4,7 @@ namespace Gml.Launcher.Models; public class Language { - public required string IconPath { get; set; } - public required string Name { get; set; } - public required CultureInfo Culture { get; set; } + public required string IconPath { get; init; } + public required string Name { get; init; } + public required CultureInfo Culture { get; init; } } diff --git a/src/Gml.Launcher/Models/ProfileInfoItem.cs b/src/Gml.Launcher/Models/ProfileInfoItem.cs index 62b3c29..37d70ea 100644 --- a/src/Gml.Launcher/Models/ProfileInfoItem.cs +++ b/src/Gml.Launcher/Models/ProfileInfoItem.cs @@ -1,13 +1,7 @@ namespace Gml.Launcher.Models; -public class ProfileInfoItem +public class ProfileInfoItem(string key, string value) { - public ProfileInfoItem(string key, string value) - { - Value = value; - Key = key; - } - - public string Key { get; set; } = null!; - public string Value { get; set; } = null!; + public string Key { get; set; } = key; + public string Value { get; set; } = value; } diff --git a/src/Gml.Launcher/Models/SettingsInfo.cs b/src/Gml.Launcher/Models/SettingsInfo.cs index 2c40f16..9ac09a3 100644 --- a/src/Gml.Launcher/Models/SettingsInfo.cs +++ b/src/Gml.Launcher/Models/SettingsInfo.cs @@ -1,7 +1,12 @@ namespace Gml.Launcher.Models; -public record SettingsInfo(int GameWidth, int GameHeight, bool FullScreen, bool IsDynamicRam, double RamValue, string? LanguageCode) +public record SettingsInfo( + int GameWidth, + int GameHeight, + bool FullScreen, + bool IsDynamicRam, + double RamValue, + string? LanguageCode) { - public static SettingsInfo Default - => new SettingsInfo(900, 600, false, true, 0, "ru-RU"); + public static SettingsInfo Default => new(900, 600, false, true, 0, "ru-RU"); } diff --git a/src/Gml.Launcher/Program.cs b/src/Gml.Launcher/Program.cs index c66ef67..ff89e66 100644 --- a/src/Gml.Launcher/Program.cs +++ b/src/Gml.Launcher/Program.cs @@ -1,14 +1,14 @@ -using Avalonia; -using Avalonia.ReactiveUI; -using System; +using System; using System.Reactive; +using Avalonia; +using Avalonia.ReactiveUI; using Gml.Launcher.Core.Extensions; using ReactiveUI; using Sentry; namespace Gml.Launcher; -class Program +internal class Program { [STAThread] public static void Main(string[] args) @@ -18,7 +18,6 @@ public static void Main(string[] args) RxApp.DefaultExceptionHandler = Observer.Create(GlobalExceptionHandler); BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); - } catch (Exception e) { @@ -32,10 +31,12 @@ private static void GlobalExceptionHandler(Exception exception) } public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() + { + return AppBuilder.Configure() .UsePlatformDetect() .WithInterFont() .RegisterServices() .LogToTrace() .UseReactiveUI(); + } } diff --git a/src/Gml.Launcher/ViewModels/Base/PageViewModelBase.cs b/src/Gml.Launcher/ViewModels/Base/PageViewModelBase.cs index 9a012a0..11d19be 100644 --- a/src/Gml.Launcher/ViewModels/Base/PageViewModelBase.cs +++ b/src/Gml.Launcher/ViewModels/Base/PageViewModelBase.cs @@ -3,10 +3,6 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Input; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Layout; -using Avalonia.Media; using Avalonia.Threading; using GamerVII.Notification.Avalonia; using Gml.Launcher.Assets; @@ -19,14 +15,7 @@ namespace Gml.Launcher.ViewModels.Base; public class PageViewModelBase : ViewModelBase, IRoutableViewModel { - public IScreen HostScreen { get; } - public string? UrlPathSegment { get; } = Guid.NewGuid().ToString().Substring(0, 5); - protected readonly ILocalizationService LocalizationService; - - public string Title => LocalizationService.GetString(ResourceKeysDictionary.DefaultPageTitle); - - public ICommand OpenLinkCommand { get; } - public ICommand GoBackCommand { get; set; } + internal readonly ILocalizationService LocalizationService; protected PageViewModelBase(IScreen screen, ILocalizationService? localizationService = null) { @@ -40,6 +29,13 @@ protected PageViewModelBase(IScreen screen, ILocalizationService? localizationSe HostScreen = screen; } + public string Title => LocalizationService.GetString(ResourceKeysDictionary.DefaultPageTitle); + + public ICommand OpenLinkCommand { get; } + public ICommand GoBackCommand { get; set; } + public IScreen HostScreen { get; } + public string? UrlPathSegment { get; } = Guid.NewGuid().ToString().Substring(0, 5); + private void OpenLink(string url) { Process.Start(new ProcessStartInfo @@ -52,7 +48,6 @@ private void OpenLink(string url) protected void ShowError(string title, string content) { if (HostScreen is MainWindowViewModel mainViewModel) - { Dispatcher.UIThread.Invoke(() => { mainViewModel.Manager @@ -63,7 +58,6 @@ protected void ShowError(string title, string content) .WithDelay(TimeSpan.FromSeconds(3)) .Queue(); }); - } } protected Task ExecuteFromNewThread(Func func) diff --git a/src/Gml.Launcher/ViewModels/Base/ViewModelBase.cs b/src/Gml.Launcher/ViewModels/Base/ViewModelBase.cs index d60f8d9..e256bca 100644 --- a/src/Gml.Launcher/ViewModels/Base/ViewModelBase.cs +++ b/src/Gml.Launcher/ViewModels/Base/ViewModelBase.cs @@ -1,10 +1,9 @@ -using System; -using System.Reactive.Subjects; +using System.Reactive.Subjects; using ReactiveUI; namespace Gml.Launcher.ViewModels.Base; public class ViewModelBase : ReactiveObject { - protected internal Subject OnClosed = new(); + protected internal readonly Subject OnClosed = new(); } diff --git a/src/Gml.Launcher/ViewModels/Base/WindowViewModelBase.cs b/src/Gml.Launcher/ViewModels/Base/WindowViewModelBase.cs index 72d054f..d99f19e 100644 --- a/src/Gml.Launcher/ViewModels/Base/WindowViewModelBase.cs +++ b/src/Gml.Launcher/ViewModels/Base/WindowViewModelBase.cs @@ -2,5 +2,4 @@ public class WindowViewModelBase : ViewModelBase { - } diff --git a/src/Gml.Launcher/ViewModels/Components/ListViewModel.cs b/src/Gml.Launcher/ViewModels/Components/ListViewModel.cs index 8efc3b9..038acd4 100644 --- a/src/Gml.Launcher/ViewModels/Components/ListViewModel.cs +++ b/src/Gml.Launcher/ViewModels/Components/ListViewModel.cs @@ -11,6 +11,10 @@ public class ListViewModel : ViewModelBase { internal readonly Subject ProfileChanged = new(); + + private ObservableCollection? _profiles; + private ProfileReadDto? _selectedProfile; + public ObservableCollection? Profiles { get => _profiles; @@ -38,9 +42,4 @@ public ProfileReadDto? SelectedProfile public bool IsNotLoaded => _profiles == null; public bool HasItems => _profiles != null && _profiles.Any(); public bool HasSelectedItem => _selectedProfile != null; - - - private ObservableCollection? _profiles; - private ProfileReadDto? _selectedProfile; - } diff --git a/src/Gml.Launcher/ViewModels/MainWindowViewModel.cs b/src/Gml.Launcher/ViewModels/MainWindowViewModel.cs index 6efdc49..f244667 100644 --- a/src/Gml.Launcher/ViewModels/MainWindowViewModel.cs +++ b/src/Gml.Launcher/ViewModels/MainWindowViewModel.cs @@ -1,5 +1,4 @@ using System; -using System.Reactive; using System.Reactive.Subjects; using GamerVII.Notification.Avalonia; using Gml.Launcher.ViewModels.Base; @@ -10,16 +9,14 @@ namespace Gml.Launcher.ViewModels; public class MainWindowViewModel : WindowViewModelBase, IScreen { - public RoutingState Router { get; } = new(); - - public ReactiveCommand GoBackCommand => Router.NavigateBack!; - - public INotificationMessageManager Manager { get; } = new NotificationMessageManager(); - protected internal Subject gameLaunched = new(); - protected internal IObservable GameLaunched => gameLaunched; + protected internal readonly Subject _gameLaunched = new(); public MainWindowViewModel() { Router.Navigate.Execute(new LoginPageViewModel(this, OnClosed)); } + + public INotificationMessageManager Manager { get; } = new NotificationMessageManager(); + protected internal IObservable GameLaunched => _gameLaunched; + public RoutingState Router { get; } = new(); } diff --git a/src/Gml.Launcher/ViewModels/Pages/LoginPageViewModel.cs b/src/Gml.Launcher/ViewModels/Pages/LoginPageViewModel.cs index acd9def..740f2d1 100644 --- a/src/Gml.Launcher/ViewModels/Pages/LoginPageViewModel.cs +++ b/src/Gml.Launcher/ViewModels/Pages/LoginPageViewModel.cs @@ -19,14 +19,45 @@ namespace Gml.Launcher.ViewModels.Pages; public class LoginPageViewModel : PageViewModelBase { - private string _login = string.Empty; - private bool _isProcessing = false; - private string _password = string.Empty; - private readonly MainWindowViewModel _screen; + private readonly IGmlClientManager _gmlClientManager; private readonly IObservable _onClosed; + private readonly MainWindowViewModel _screen; private readonly IStorageService _storageService; - private readonly IGmlClientManager _gmlClientManager; private readonly ISystemService _systemService; + private ObservableCollection _errorList = new(); + private bool _isProcessing; + private string _login = string.Empty; + private string _password = string.Empty; + + + internal LoginPageViewModel(IScreen screen, + IObservable onClosed, + IGmlClientManager? gmlClientManager = null, + IStorageService? storageService = null, + ISystemService? systemService = null, + ILocalizationService? localizationService = null) : base(screen, localizationService) + { + _screen = (MainWindowViewModel)screen; + _onClosed = onClosed; + + _storageService = storageService + ?? Locator.Current.GetService() + ?? throw new ServiceNotFoundException(typeof(IStorageService)); + + _systemService = systemService + ?? Locator.Current.GetService() + ?? throw new ServiceNotFoundException(typeof(IStorageService)); + + _gmlClientManager = gmlClientManager + ?? Locator.Current.GetService() + ?? throw new ServiceNotFoundException(typeof(IGmlClientManager)); + + _screen.OnClosed.Subscribe(DisposeConnections); + + LoginCommand = ReactiveCommand.CreateFromTask(OnAuth); + + RxApp.MainThreadScheduler.Schedule(CheckAuth); + } public string Login { @@ -53,45 +84,14 @@ public bool IsProcessing public ObservableCollection Errors { - get => _errors; - set => this.RaiseAndSetIfChanged(ref _errors, value); + get => _errorList; + set => this.RaiseAndSetIfChanged(ref _errorList, value); } public bool IsNotProcessing => !_isProcessing; - public ObservableCollection _errors = new(); public ICommand LoginCommand { get; set; } - - internal LoginPageViewModel(IScreen screen, - IObservable onClosed, - IGmlClientManager? gmlClientManager = null, - IStorageService? storageService = null, - ISystemService? systemService = null, - ILocalizationService? localizationService = null) : base(screen, localizationService) - { - _screen = (MainWindowViewModel)screen; - _onClosed = onClosed; - - _storageService = storageService - ?? Locator.Current.GetService() - ?? throw new ServiceNotFoundException(typeof(IStorageService)); - - _systemService = systemService - ?? Locator.Current.GetService() - ?? throw new ServiceNotFoundException(typeof(IStorageService)); - - _gmlClientManager = gmlClientManager - ?? Locator.Current.GetService() - ?? throw new ServiceNotFoundException(typeof(IGmlClientManager)); - - _screen.OnClosed.Subscribe(DisposeConnections); - - LoginCommand = ReactiveCommand.CreateFromTask(OnAuth); - - RxApp.MainThreadScheduler.Schedule(CheckAuth); - } - private void DisposeConnections(bool isClosed) { _gmlClientManager.Dispose(); @@ -134,16 +134,12 @@ private async Task OnAuth(CancellationToken arg) } if (authInfo.Item1.Has2Fa) - { //ToDo: Next versions - return; - } - if (_screen is MainWindowViewModel mainView) + if (_screen is { } mainView) { if (!authInfo.Details.Any()) - { mainView.Manager .CreateMessage(true, "#D03E3E", LocalizationService.GetString(ResourceKeysDictionary.InvalidAuthData), @@ -151,7 +147,6 @@ private async Task OnAuth(CancellationToken arg) .Dismiss() .WithDelay(TimeSpan.FromSeconds(3)) .Queue(); - } Errors = new ObservableCollection(authInfo.Details); } diff --git a/src/Gml.Launcher/ViewModels/Pages/OverviewPageViewModel.cs b/src/Gml.Launcher/ViewModels/Pages/OverviewPageViewModel.cs index 1c72c39..007ea90 100644 --- a/src/Gml.Launcher/ViewModels/Pages/OverviewPageViewModel.cs +++ b/src/Gml.Launcher/ViewModels/Pages/OverviewPageViewModel.cs @@ -32,32 +32,16 @@ namespace Gml.Launcher.ViewModels.Pages; public class OverviewPageViewModel : PageViewModelBase { - private readonly IStorageService _storageService; + private readonly IDisposable? _closeEvent; private readonly IGmlClientManager _gmlManager; - private readonly IUser _user; + private readonly IDisposable? _loadedLoaded; + private readonly MainWindowViewModel _mainViewModel; + private readonly IDisposable? _maxCountLoaded; private readonly IObservable _onClosed; - private readonly ISystemService _systemService; - private readonly IDisposable? _closeEvent; private readonly IDisposable _profileNameChanged; + private readonly IStorageService _storageService; + private readonly ISystemService _systemService; private Process? _gameProcess; - private readonly MainWindowViewModel _mainViewModel; - public new string Title => LocalizationService.GetString(ResourceKeysDictionary.MainPageTitle); - - public ICommand GoProfileCommand { get; set; } - public ICommand LogoutCommand { get; set; } - public ICommand PlayCommand { get; set; } - public ICommand GoSettingsCommand { get; set; } - public ICommand HomeCommand { get; set; } - public ListViewModel ListViewModel { get; } = new(); - public IUser User => _user; - - [Reactive] public int? LoadingPercentage { get; set; } - - [Reactive] public string? Headline { get; set; } - - [Reactive] public string? Description { get; set; } - - [Reactive] public bool IsProcessing { get; set; } internal OverviewPageViewModel(IScreen screen, IUser user, @@ -67,7 +51,7 @@ internal OverviewPageViewModel(IScreen screen, IStorageService? storageService = null) : base(screen) { _mainViewModel = screen as MainWindowViewModel ?? throw new Exception("Not valid screen"); - _user = user; + User = user; _onClosed = onClosed; _systemService = systemService ?? Locator.Current.GetService() @@ -78,11 +62,11 @@ internal OverviewPageViewModel(IScreen screen, ?? throw new ServiceNotFoundException(typeof(IStorageService)); _gmlManager = gmlManager - ?? Locator.Current.GetService() - ?? throw new ServiceNotFoundException(typeof(IGmlClientManager)); + ?? Locator.Current.GetService() + ?? throw new ServiceNotFoundException(typeof(IGmlClientManager)); GoProfileCommand = ReactiveCommand.CreateFromObservable( - () => screen.Router.Navigate.Execute(new ProfilePageViewModel(screen, _user, gmlManager)) + () => screen.Router.Navigate.Execute(new ProfilePageViewModel(screen, User)) ); GoSettingsCommand = ReactiveCommand.CreateFromObservable( @@ -91,10 +75,11 @@ internal OverviewPageViewModel(IScreen screen, LocalizationService, _storageService, _systemService, + _gmlManager, ListViewModel.SelectedProfile!)) ); - HomeCommand = ReactiveCommand.Create(() => ListViewModel.SelectedProfile = null); + HomeCommand = ReactiveCommand.Create(async () => await LoadProfiles()); _gmlManager.ProgressChanged.Subscribe(percentage => { @@ -102,8 +87,12 @@ internal OverviewPageViewModel(IScreen screen, LoadingPercentage = percentage; }); + _gmlManager.ProfilesChanges.Subscribe(LoadProfilesAsync); + _closeEvent ??= onClosed.Subscribe(_ => _gameProcess?.Kill()); _profileNameChanged ??= ListViewModel.ProfileChanged.Subscribe(SaveSelectedServer); + _maxCountLoaded ??= _gmlManager.MaxFileCount.Subscribe(count => MaxCount = count); + _loadedLoaded ??= _gmlManager.LoadedFilesCount.Subscribe(ChangeLoadProcessDescription); LogoutCommand = ReactiveCommand.CreateFromTask(OnLogout); @@ -112,6 +101,41 @@ internal OverviewPageViewModel(IScreen screen, RxApp.MainThreadScheduler.Schedule(LoadData); } + public new string Title => LocalizationService.GetString(ResourceKeysDictionary.MainPageTitle); + + public ICommand GoProfileCommand { get; set; } + public ICommand LogoutCommand { get; set; } + public ICommand PlayCommand { get; set; } + public ICommand GoSettingsCommand { get; set; } + public ICommand HomeCommand { get; set; } + public ListViewModel ListViewModel { get; } = new(); + public IUser User { get; } + + [Reactive] public int? LoadingPercentage { get; set; } + [Reactive] public int? MaxCount { get; set; } + [Reactive] public int? LoadedCount { get; set; } + + [Reactive] public string? Headline { get; set; } + + [Reactive] public string? Description { get; set; } + + [Reactive] public bool IsProcessing { get; set; } + + private async void LoadProfilesAsync(bool eventInfo) + { + await LoadProfiles(); + } + + private void ChangeLoadProcessDescription(int count) + { + LoadedCount = count; + + Description = + $"{LocalizationService.GetString(ResourceKeysDictionary.Stay)}: " + + $"{MaxCount - LoadedCount} " + + $"{LocalizationService.GetString(ResourceKeysDictionary.Files)}"; + } + private async void SaveSelectedServer(ProfileReadDto? profile) { if (profile != null) @@ -126,7 +150,6 @@ private async Task OnLogout(CancellationToken arg) private async Task StartGame(CancellationToken cancellationToken) { - await ExecuteFromNewThread(async () => { try @@ -139,7 +162,7 @@ await ExecuteFromNewThread(async () => _gameProcess = await GenerateProcess(cancellationToken, profileInfo); _gameProcess.Start(); await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken); - Dispatcher.UIThread.Invoke(() => _mainViewModel.gameLaunched.OnNext(true)); + Dispatcher.UIThread.Invoke(() => _mainViewModel._gameLaunched.OnNext(true)); UpdateProgress(string.Empty, string.Empty, false); await _gameProcess.WaitForExitAsync(cancellationToken); } @@ -150,7 +173,8 @@ await ExecuteFromNewThread(async () => } catch (FileNotFoundException exception) { - ShowError(ResourceKeysDictionary.Error, LocalizationService.GetString(ResourceKeysDictionary.JavaNotFound)); + ShowError(ResourceKeysDictionary.Error, + LocalizationService.GetString(ResourceKeysDictionary.JavaNotFound)); Console.WriteLine(exception); } @@ -162,17 +186,16 @@ await ExecuteFromNewThread(async () => } finally { - Dispatcher.UIThread.Invoke(() => _mainViewModel.gameLaunched.OnNext(false)); + Dispatcher.UIThread.Invoke(() => _mainViewModel._gameLaunched.OnNext(false)); UpdateProgress(string.Empty, string.Empty, false); - await _gmlManager.UpdateDiscordRpcState(LocalizationService.GetString(ResourceKeysDictionary.DefaultDRpcText)); + await _gmlManager.UpdateDiscordRpcState( + LocalizationService.GetString(ResourceKeysDictionary.DefaultDRpcText)); } }); - - - } - private async Task GenerateProcess(CancellationToken cancellationToken, ResponseMessage profileInfo) + private async Task GenerateProcess(CancellationToken cancellationToken, + ResponseMessage profileInfo) { UpdateProgress( LocalizationService.GetString(ResourceKeysDictionary.Updating), @@ -180,9 +203,7 @@ private async Task GenerateProcess(CancellationToken cancellationToken, true); if (profileInfo.Data is null) - { throw new Exception(LocalizationService.GetString(ResourceKeysDictionary.ProfileNotConfigured)); - } await _gmlManager.DownloadNotInstalledFiles(profileInfo.Data, cancellationToken); @@ -205,7 +226,8 @@ private async Task GenerateProcess(CancellationToken cancellationToken, LocalizationService.GetString(ResourceKeysDictionary.UpdatingDescription), true); - await _gmlManager.UpdateDiscordRpcState($"{LocalizationService.GetString(ResourceKeysDictionary.PlayDRpcText)} \"{ListViewModel.SelectedProfile!.Name}\""); + await _gmlManager.UpdateDiscordRpcState( + $"{LocalizationService.GetString(ResourceKeysDictionary.PlayDRpcText)} \"{ListViewModel.SelectedProfile!.Name}\""); var settings = await _storageService.GetAsync(StorageConstants.Settings) ?? SettingsInfo.Default; @@ -239,25 +261,11 @@ private async void LoadData() { try { - await _gmlManager.LoadDiscordRpc(); - await _gmlManager.UpdateDiscordRpcState(LocalizationService.GetString(ResourceKeysDictionary.DefaultDRpcText)); - - var profilesData = await _gmlManager.GetProfiles(); - - ListViewModel.Profiles = new ObservableCollection(profilesData.Data ?? []); - - var lastSelectedProfileName = await _storageService.GetAsync(StorageConstants.LastSelectedProfileName); + await LoadProfiles(); - if (!string.IsNullOrEmpty(lastSelectedProfileName) && ListViewModel.Profiles.Any()) - { - ListViewModel.SelectedProfile = - ListViewModel.Profiles.FirstOrDefault(c => c.Name == lastSelectedProfileName); - } - - if (string.IsNullOrEmpty(lastSelectedProfileName)) - { - ListViewModel.SelectedProfile = ListViewModel.Profiles.FirstOrDefault(); - } + await _gmlManager.LoadDiscordRpc(); + await _gmlManager.UpdateDiscordRpcState( + LocalizationService.GetString(ResourceKeysDictionary.DefaultDRpcText)); } catch (TaskCanceledException exception) { @@ -276,6 +284,21 @@ private async void LoadData() } } + private async Task LoadProfiles() + { + var profilesData = await _gmlManager.GetProfiles(); + + ListViewModel.Profiles = new ObservableCollection(profilesData.Data ?? []); + + var lastSelectedProfileName = await _storageService.GetAsync(StorageConstants.LastSelectedProfileName); + + if (!string.IsNullOrEmpty(lastSelectedProfileName) && + ListViewModel.Profiles.FirstOrDefault(c => c.Name == lastSelectedProfileName) is { } profile) + ListViewModel.SelectedProfile = profile; + + ListViewModel.SelectedProfile ??= ListViewModel.Profiles.FirstOrDefault(); + } + private async Task Reconnect() { _mainViewModel.Manager diff --git a/src/Gml.Launcher/ViewModels/Pages/ProfilePageViewModel.cs b/src/Gml.Launcher/ViewModels/Pages/ProfilePageViewModel.cs index b9802ff..47483e7 100644 --- a/src/Gml.Launcher/ViewModels/Pages/ProfilePageViewModel.cs +++ b/src/Gml.Launcher/ViewModels/Pages/ProfilePageViewModel.cs @@ -1,52 +1,36 @@ -using System.Reactive.Concurrency; -using Gml.Client; +using System; +using System.Reactive.Concurrency; using Gml.Client.Models; using Gml.Launcher.Assets; -using Gml.Launcher.Core.Exceptions; using Gml.Launcher.Core.Services; using Gml.Launcher.ViewModels.Base; using ReactiveUI; -using Sentry; -using Splat; namespace Gml.Launcher.ViewModels.Pages; public class ProfilePageViewModel : PageViewModelBase { private IUser _user; - private readonly IGmlClientManager _clientManager; - private readonly IStorageService _storageService; - public new string Title => LocalizationService.GetString(ResourceKeysDictionary.MainPageTitle); - - public IUser User - { - get => _user; - private init => this.RaiseAndSetIfChanged(ref _user, value); - } - - internal ProfilePageViewModel(IScreen screen, IUser user, - IGmlClientManager? clientManager = null, - IStorageService? storageService = null, ILocalizationService? localizationService = null) : base(screen, localizationService) { - User = user; - _clientManager = clientManager - ?? Locator.Current.GetService() - ?? throw new ServiceNotFoundException(typeof(IGmlClientManager)); - - _storageService = storageService - ?? Locator.Current.GetService() - ?? throw new ServiceNotFoundException(typeof(IStorageService)); + _user = user ?? throw new ArgumentNullException(nameof(user)); RxApp.MainThreadScheduler.Schedule(LoadData); + } + + public new string Title => LocalizationService.GetString(ResourceKeysDictionary.MainPageTitle); + public IUser User + { + get => _user; + set => this.RaiseAndSetIfChanged(ref _user, value); } - private async void LoadData() + private void LoadData() { // string logs = await _storageService.GetLogsAsync(1500); // diff --git a/src/Gml.Launcher/ViewModels/Pages/SettingsPageViewModel.cs b/src/Gml.Launcher/ViewModels/Pages/SettingsPageViewModel.cs index 23aba3f..b7ce5e9 100644 --- a/src/Gml.Launcher/ViewModels/Pages/SettingsPageViewModel.cs +++ b/src/Gml.Launcher/ViewModels/Pages/SettingsPageViewModel.cs @@ -5,6 +5,8 @@ using System.Reactive.Concurrency; using System.Reactive.Linq; using System.Threading; +using System.Windows.Input; +using Gml.Client; using Gml.Launcher.Core.Services; using Gml.Launcher.Models; using Gml.Launcher.ViewModels.Base; @@ -16,19 +18,72 @@ namespace Gml.Launcher.ViewModels.Pages; public class SettingsPageViewModel : PageViewModelBase { + private readonly MainWindowViewModel _mainViewModel; + private readonly IGmlClientManager _gmlManager; private readonly IStorageService _storageService; + private double _ramValue; + private int _windowHeight; - [Reactive] - public bool DynamicRamValue { get; set; } + private int _windowWidth; - [Reactive] - public bool FullScreen { get; set; } + public SettingsPageViewModel( + IScreen screen, + ILocalizationService? localizationService, + IStorageService storageService, + ISystemService systemService, + IGmlClientManager gmlManager, + ProfileReadDto selectedProfile) : base(screen, localizationService) + { + _mainViewModel = (MainWindowViewModel)screen; + _storageService = storageService; + _gmlManager = gmlManager; - [Reactive] - public ulong MaxRamValue { get; set; } + this.WhenAnyValue( + x => x.RamValue, + x => x.WindowWidth, + x => x.WindowHeight, + x => x.FullScreen, + x => x.DynamicRamValue, + x => x.SelectedLanguage + ) + .Throttle(TimeSpan.FromMilliseconds(400)) + .ObserveOn(RxApp.MainThreadScheduler) + .Subscribe(SaveSettings); - [Reactive] - public Language? SelectedLanguage { get; set; } + this.WhenAnyValue(x => x.SelectedLanguage) + .Skip(2) + .Subscribe(language => + { + if (language == null) return; + + Thread.CurrentThread.CurrentCulture = language.Culture; + Thread.CurrentThread.CurrentCulture.ClearCachedData(); + + GoBackCommand.Execute(Unit.Default); + }); + + ChangeInstallationDirectory = ReactiveCommand.Create(ChangeFolder); + + AvailableLanguages = new ObservableCollection(systemService.GetAvailableLanguages()); + + MaxRamValue = systemService.GetMaxRam(); + + InstallationFolder = _gmlManager.InstallationDirectory; + + RxApp.MainThreadScheduler.Schedule(LoadSettings); + } + + [Reactive] public bool DynamicRamValue { get; set; } + + [Reactive] public bool FullScreen { get; set; } + + [Reactive] public ulong MaxRamValue { get; set; } + + [Reactive] public Language? SelectedLanguage { get; set; } + + [Reactive] public string? InstallationFolder { get; set; } + + public ICommand ChangeInstallationDirectory { get; } public double RamValue @@ -48,15 +103,11 @@ public string WindowWidth get => _windowWidth.ToString(); set { - var isNumeric = int.TryParse(string.Concat(value.Where(char.IsDigit)), out int numericValue); + var isNumeric = int.TryParse(string.Concat(value.Where(char.IsDigit)), out var numericValue); if (isNumeric) - { this.RaiseAndSetIfChanged(ref _windowWidth, numericValue); - } else - { this.RaiseAndSetIfChanged(ref _windowWidth, default); - } } } @@ -65,63 +116,23 @@ public string WindowHeight get => _windowHeight.ToString(); set { - var isNumeric = int.TryParse(string.Concat(value.Where(char.IsDigit)), out int numericValue); + var isNumeric = int.TryParse(string.Concat(value.Where(char.IsDigit)), out var numericValue); if (isNumeric) - { this.RaiseAndSetIfChanged(ref _windowHeight, numericValue); - } else - { this.RaiseAndSetIfChanged(ref _windowWidth, default); - } } } public ObservableCollection AvailableLanguages { get; } + public MainWindowViewModel MainViewModel => _mainViewModel; - private int _windowWidth; - private int _windowHeight; - private double _ramValue; - - public SettingsPageViewModel( - IScreen screen, - ILocalizationService? localizationService, - IStorageService storageService, - ISystemService systemService, - ProfileReadDto selectedProfile) : base(screen, localizationService) + internal void ChangeFolder() { - _storageService = storageService; - - this.WhenAnyValue( - x => x.RamValue, - x => x.WindowWidth, - x => x.WindowHeight, - x => x.FullScreen, - x => x.DynamicRamValue, - x => x.SelectedLanguage - ) - .Throttle(TimeSpan.FromMilliseconds(400)) - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(SaveSettings); - - this.WhenAnyValue(x => x.SelectedLanguage) - .Skip(2) - .Subscribe(language => - { - if (language == null) return; - - Thread.CurrentThread.CurrentCulture = language.Culture; - Thread.CurrentThread.CurrentCulture.ClearCachedData(); - - GoBackCommand.Execute(Unit.Default); - }); - - - AvailableLanguages = new ObservableCollection(systemService.GetAvailableLanguages()); - - MaxRamValue = systemService.GetMaxRam(); + if (InstallationFolder != null) + _gmlManager.ChangeInstallationFolder(InstallationFolder); - RxApp.MainThreadScheduler.Schedule(LoadSettings); + _storageService.SetAsync(StorageConstants.InstallationDirectory, InstallationFolder); } private double RoundToNearest(double value, double step) @@ -138,14 +149,9 @@ private async void LoadSettings() if (data == null) return; - if (!string.IsNullOrEmpty(data.LanguageCode)) - { - SelectedLanguage = AvailableLanguages.FirstOrDefault(c => c.Culture.Name == data.LanguageCode); - } - else - { - SelectedLanguage = AvailableLanguages.FirstOrDefault(); - } + SelectedLanguage = !string.IsNullOrEmpty(data.LanguageCode) + ? AvailableLanguages.FirstOrDefault(c => c.Culture.Name == data.LanguageCode) + : AvailableLanguages.FirstOrDefault(); WindowWidth = data.GameWidth == 0 ? "900" : data.GameWidth.ToString(); WindowHeight = data.GameHeight == 0 ? "600" : data.GameHeight.ToString(); @@ -155,7 +161,8 @@ private async void LoadSettings() } private void SaveSettings( - (double ramValue, string width, string height, bool isFullScreen, bool isDynamicRam, Language? selectedLanguage) update) + (double ramValue, string width, string height, bool isFullScreen, bool isDynamicRam, Language? selectedLanguage) + update) { _storageService.SetAsync( StorageConstants.Settings, diff --git a/src/Gml.Launcher/ViewModels/SplashScreenViewModel.cs b/src/Gml.Launcher/ViewModels/SplashScreenViewModel.cs index 7a80094..ad7c28d 100644 --- a/src/Gml.Launcher/ViewModels/SplashScreenViewModel.cs +++ b/src/Gml.Launcher/ViewModels/SplashScreenViewModel.cs @@ -4,33 +4,26 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Threading.Tasks; -using Avalonia.Controls.Shapes; using Gml.Client; using Gml.Launcher.Assets; using Gml.Launcher.Core.Exceptions; using Gml.Launcher.Core.Services; using Gml.Launcher.ViewModels.Base; using Gml.Web.Api.Domains.System; -using GmlCore.Interfaces; using GmlCore.Interfaces.Storage; -using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; -using Path = Avalonia.Controls.Shapes.Path; namespace Gml.Launcher.ViewModels; public class SplashScreenViewModel : WindowViewModelBase { - private readonly ISystemService _systemService; - private readonly IGmlClientManager _manager; private readonly ILocalizationService _localizationService; + private readonly IGmlClientManager _manager; + private readonly ISystemService _systemService; - [Reactive] public string StatusText { get; set; } - [Reactive] public bool InfinityLoading { get; set; } = true; - [Reactive] public Int16 Progress { get; set; } - - public SplashScreenViewModel(ISystemService? systemService = null, IGmlClientManager? manager = null, ILocalizationService? localizationService = null) + public SplashScreenViewModel(ISystemService? systemService = null, IGmlClientManager? manager = null, + ILocalizationService? localizationService = null) { _systemService = systemService ?? Locator.Current.GetService() ?? throw new ServiceNotFoundException(typeof(ISystemService)); @@ -44,6 +37,10 @@ public SplashScreenViewModel(ISystemService? systemService = null, IGmlClientMan StatusText = _localizationService.GetString(ResourceKeysDictionary.PreparingLaunch); } + [Reactive] public string StatusText { get; set; } + [Reactive] public bool InfinityLoading { get; set; } = true; + [Reactive] public short Progress { get; set; } + public async Task InitializeAsync() { var osType = _systemService.GetOsType(); @@ -58,13 +55,13 @@ public async Task InitializeAsync() { ChangeState(_localizationService.GetString(ResourceKeysDictionary.InstallingUpdates), false); - string exePath = Process.GetCurrentProcess().MainModule?.FileName - ?? throw new Exception(ResourceKeysDictionary.FailedOs); + var exePath = Process.GetCurrentProcess().MainModule?.FileName + ?? throw new Exception(ResourceKeysDictionary.FailedOs); var process = _manager.ProgressChanged.Subscribe( percentage => Progress = Convert.ToInt16(percentage)); - await _manager.UpdateCurrentLauncher(versionInfo, osType, System.IO.Path.GetFileName(exePath)); + await _manager.UpdateCurrentLauncher(versionInfo, osType, Path.GetFileName(exePath)); process.Dispose(); } @@ -75,10 +72,7 @@ public async Task InitializeAsync() { var actualVersion = await _manager.GetActualVersion(osType, osArch); - if (actualVersion is null) - { - return (null, true); - } + if (actualVersion is null) return (null, true); var version = Assembly.GetExecutingAssembly().GetName().Version ?? new Version(1, 0, 0, 0); diff --git a/src/Gml.Launcher/Views/Components/BackgroundComponent.axaml b/src/Gml.Launcher/Views/Components/BackgroundComponent.axaml index dcab09b..f26726d 100644 --- a/src/Gml.Launcher/Views/Components/BackgroundComponent.axaml +++ b/src/Gml.Launcher/Views/Components/BackgroundComponent.axaml @@ -19,9 +19,8 @@ + SourceStream="{TemplateBinding SourceStream}" /> - diff --git a/src/Gml.Launcher/Views/Components/BackgroundComponent.axaml.cs b/src/Gml.Launcher/Views/Components/BackgroundComponent.axaml.cs index ea1db3b..27bf622 100644 --- a/src/Gml.Launcher/Views/Components/BackgroundComponent.axaml.cs +++ b/src/Gml.Launcher/Views/Components/BackgroundComponent.axaml.cs @@ -7,22 +7,23 @@ namespace Gml.Launcher.Views.Components; public class BackgroundComponent : TemplatedControl { + public static readonly StyledProperty SourceProperty = + AvaloniaProperty.Register( + nameof(Source)); - public static readonly StyledProperty SourceProperty = AvaloniaProperty.Register( - nameof(Source)); - - public static readonly StyledProperty SourceStreamProperty = AvaloniaProperty.Register( - nameof(SourceStream)); + public static readonly StyledProperty SourceStreamProperty = + AvaloniaProperty.Register( + nameof(SourceStream)); public IImage? Source { get => GetValue(SourceProperty); set => SetValue(SourceProperty, value); } + public Stream? SourceStream { get => GetValue(SourceStreamProperty); set => SetValue(SourceStreamProperty, value); } } - diff --git a/src/Gml.Launcher/Views/Components/BadgeComponent.axaml b/src/Gml.Launcher/Views/Components/BadgeComponent.axaml index 8a88213..d79bee1 100644 --- a/src/Gml.Launcher/Views/Components/BadgeComponent.axaml +++ b/src/Gml.Launcher/Views/Components/BadgeComponent.axaml @@ -9,11 +9,11 @@ - diff --git a/src/Gml.Launcher/Views/Components/BadgeComponent.axaml.cs b/src/Gml.Launcher/Views/Components/BadgeComponent.axaml.cs index 0fcc0a8..b8df275 100644 --- a/src/Gml.Launcher/Views/Components/BadgeComponent.axaml.cs +++ b/src/Gml.Launcher/Views/Components/BadgeComponent.axaml.cs @@ -1,12 +1,10 @@ using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.Primitives; namespace Gml.Launcher.Views.Components; public class BadgeComponent : TemplatedControl { - public static readonly StyledProperty TextProperty = AvaloniaProperty.Register( nameof(Text), "Badge"); @@ -16,4 +14,3 @@ public string Text set => SetValue(TextProperty, value); } } - diff --git a/src/Gml.Launcher/Views/Components/GmlButton.axaml b/src/Gml.Launcher/Views/Components/GmlButton.axaml index cb2becc..bcec941 100644 --- a/src/Gml.Launcher/Views/Components/GmlButton.axaml +++ b/src/Gml.Launcher/Views/Components/GmlButton.axaml @@ -62,7 +62,8 @@ - diff --git a/src/Gml.Launcher/Views/Components/GmlButton.axaml.cs b/src/Gml.Launcher/Views/Components/GmlButton.axaml.cs index 0afc7e4..a7d267a 100644 --- a/src/Gml.Launcher/Views/Components/GmlButton.axaml.cs +++ b/src/Gml.Launcher/Views/Components/GmlButton.axaml.cs @@ -1,12 +1,18 @@ -using System.Windows.Input; +using System; +using System.Linq; +using System.Windows.Input; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; +using Avalonia.Controls.Templates; +using Avalonia.Interactivity; namespace Gml.Launcher.Views.Components; public class GmlButton : TemplatedControl { + public static readonly RoutedEvent ClickEvent = + RoutedEvent.Register(nameof(Click), RoutingStrategies.Bubble); public static readonly StyledProperty IconPathProperty = AvaloniaProperty.Register( nameof(IconPath), "/Assets/Images/profile.svg"); @@ -26,8 +32,9 @@ public class GmlButton : TemplatedControl public static readonly StyledProperty IsDefaultProperty = AvaloniaProperty.Register( nameof(IsDefault)); - public static readonly StyledProperty CommandParameterProperty = AvaloniaProperty.Register( - nameof(CommandParameter)); + public static readonly StyledProperty CommandParameterProperty = + AvaloniaProperty.Register( + nameof(CommandParameter)); public object? CommandParameter { @@ -71,5 +78,21 @@ public string IconPath set => SetValue(IconPathProperty, value); } -} + public event EventHandler? Click + { + add => AddHandler(ClickEvent, value); + remove => RemoveHandler(ClickEvent, value); + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + if (this.GetTemplateChildren().First() is Button button) + button.Click += (sender, args) => + { + RaiseEvent(new RoutedEventArgs(ClickEvent)); + Command?.Execute(CommandParameter); + }; + } +} diff --git a/src/Gml.Launcher/Views/Components/LoadingControl.axaml b/src/Gml.Launcher/Views/Components/LoadingControl.axaml index e1d6e8b..c89413c 100644 --- a/src/Gml.Launcher/Views/Components/LoadingControl.axaml +++ b/src/Gml.Launcher/Views/Components/LoadingControl.axaml @@ -9,18 +9,18 @@ - + - + - diff --git a/src/Gml.Launcher/Views/Components/LoadingControl.axaml.cs b/src/Gml.Launcher/Views/Components/LoadingControl.axaml.cs index 868743b..1b1e183 100644 --- a/src/Gml.Launcher/Views/Components/LoadingControl.axaml.cs +++ b/src/Gml.Launcher/Views/Components/LoadingControl.axaml.cs @@ -1,12 +1,10 @@ using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.Primitives; namespace Gml.Launcher.Views.Components; public class LoadingControl : TemplatedControl { - public static readonly StyledProperty SizeProperty = AvaloniaProperty.Register( nameof(Size), 16); @@ -15,6 +13,4 @@ public double Size get => GetValue(SizeProperty); set => SetValue(SizeProperty, value); } - } - diff --git a/src/Gml.Launcher/Views/Components/LogoComponent.axaml b/src/Gml.Launcher/Views/Components/LogoComponent.axaml index 2fca82d..a7e8ba0 100644 --- a/src/Gml.Launcher/Views/Components/LogoComponent.axaml +++ b/src/Gml.Launcher/Views/Components/LogoComponent.axaml @@ -17,7 +17,7 @@ + Height="{TemplateBinding Size}" /> @@ -30,15 +30,14 @@ Spacing="15"> + Height="{TemplateBinding Size}" /> + Foreground="{StaticResource HeadlineColor}" /> - diff --git a/src/Gml.Launcher/Views/Components/LogoComponent.axaml.cs b/src/Gml.Launcher/Views/Components/LogoComponent.axaml.cs index f09950b..262f87e 100644 --- a/src/Gml.Launcher/Views/Components/LogoComponent.axaml.cs +++ b/src/Gml.Launcher/Views/Components/LogoComponent.axaml.cs @@ -1,12 +1,10 @@ using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.Primitives; namespace Gml.Launcher.Views.Components; public class LogoComponent : TemplatedControl { - public static readonly StyledProperty SizeProperty = AvaloniaProperty.Register( nameof(Size), 32); @@ -15,6 +13,4 @@ public double Size get => GetValue(SizeProperty); set => SetValue(SizeProperty, value); } - } - diff --git a/src/Gml.Launcher/Views/Components/OnlineComponent.axaml.cs b/src/Gml.Launcher/Views/Components/OnlineComponent.axaml.cs index 662365f..abd3efd 100644 --- a/src/Gml.Launcher/Views/Components/OnlineComponent.axaml.cs +++ b/src/Gml.Launcher/Views/Components/OnlineComponent.axaml.cs @@ -1,5 +1,4 @@ using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.Primitives; namespace Gml.Launcher.Views.Components; @@ -15,4 +14,3 @@ public string Online set => SetValue(OnlineProperty, value); } } - diff --git a/src/Gml.Launcher/Views/Components/ProfileInfoComponent.axaml b/src/Gml.Launcher/Views/Components/ProfileInfoComponent.axaml index 2747625..27acb90 100644 --- a/src/Gml.Launcher/Views/Components/ProfileInfoComponent.axaml +++ b/src/Gml.Launcher/Views/Components/ProfileInfoComponent.axaml @@ -32,7 +32,7 @@ StrokeJoin="Round" StrokeLineCap="Round" StrokeThickness="1" - Stroke="{DynamicResource FormBorderColor}"/> + Stroke="{DynamicResource FormBorderColor}" /> @@ -42,4 +42,3 @@ - diff --git a/src/Gml.Launcher/Views/Components/ProfileInfoComponent.axaml.cs b/src/Gml.Launcher/Views/Components/ProfileInfoComponent.axaml.cs index 51b30af..4bd8b34 100644 --- a/src/Gml.Launcher/Views/Components/ProfileInfoComponent.axaml.cs +++ b/src/Gml.Launcher/Views/Components/ProfileInfoComponent.axaml.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.Primitives; using Gml.Launcher.Models; diff --git a/src/Gml.Launcher/Views/Components/ProfileUserControl.axaml b/src/Gml.Launcher/Views/Components/ProfileUserControl.axaml index 686b388..727a05c 100644 --- a/src/Gml.Launcher/Views/Components/ProfileUserControl.axaml +++ b/src/Gml.Launcher/Views/Components/ProfileUserControl.axaml @@ -1,9 +1,6 @@  + Size="45" /> - + diff --git a/src/Gml.Launcher/Views/Components/ProfileUserControl.axaml.cs b/src/Gml.Launcher/Views/Components/ProfileUserControl.axaml.cs index b48d35b..b5bafe7 100644 --- a/src/Gml.Launcher/Views/Components/ProfileUserControl.axaml.cs +++ b/src/Gml.Launcher/Views/Components/ProfileUserControl.axaml.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Primitives; using Gml.Launcher.Models; namespace Gml.Launcher.Views.Components; diff --git a/src/Gml.Launcher/Views/Components/ProgressBar.axaml b/src/Gml.Launcher/Views/Components/ProgressBar.axaml index bb39bd6..6a53083 100644 --- a/src/Gml.Launcher/Views/Components/ProgressBar.axaml +++ b/src/Gml.Launcher/Views/Components/ProgressBar.axaml @@ -43,14 +43,14 @@ Background="Transparent" Foreground="{DynamicResource PrimaryColor}" Margin="8" - Size="28"/> + Size="28" /> + Foreground="{DynamicResource PrimaryColor}" /> diff --git a/src/Gml.Launcher/Views/Components/ProgressBar.axaml.cs b/src/Gml.Launcher/Views/Components/ProgressBar.axaml.cs index 4331bfc..f6d591d 100644 --- a/src/Gml.Launcher/Views/Components/ProgressBar.axaml.cs +++ b/src/Gml.Launcher/Views/Components/ProgressBar.axaml.cs @@ -1,17 +1,15 @@ using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.Primitives; namespace Gml.Launcher.Views.Components; public class ProgressBar : TemplatedControl { - public static readonly StyledProperty PercentageProperty = AvaloniaProperty.Register( nameof(Percentage), "50"); public static readonly StyledProperty DescriptionProperty = AvaloniaProperty.Register( - nameof(Description), "Hitech"); + nameof(Description), "Загружено: 1596 / 6599"); public static readonly StyledProperty HeadlineProperty = AvaloniaProperty.Register( nameof(Headline), "Обновление"); @@ -33,6 +31,4 @@ public string Percentage get => GetValue(PercentageProperty); set => SetValue(PercentageProperty, value); } - } - diff --git a/src/Gml.Launcher/Views/Components/ServerInfo.axaml b/src/Gml.Launcher/Views/Components/ServerInfo.axaml index dcea920..0f14354 100644 --- a/src/Gml.Launcher/Views/Components/ServerInfo.axaml +++ b/src/Gml.Launcher/Views/Components/ServerInfo.axaml @@ -10,11 +10,11 @@ - diff --git a/src/Gml.Launcher/Views/Components/ServerInfo.axaml.cs b/src/Gml.Launcher/Views/Components/ServerInfo.axaml.cs index 04e777f..67ddf0a 100644 --- a/src/Gml.Launcher/Views/Components/ServerInfo.axaml.cs +++ b/src/Gml.Launcher/Views/Components/ServerInfo.axaml.cs @@ -1,13 +1,11 @@ using System.Windows.Input; using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.Primitives; namespace Gml.Launcher.Views.Components; public class ServerInfo : TemplatedControl { - public static readonly StyledProperty ProfileNameProperty = AvaloniaProperty.Register( nameof(ProfileName), "Techno Magic"); @@ -17,14 +15,17 @@ public class ServerInfo : TemplatedControl public static readonly StyledProperty SpacingProperty = AvaloniaProperty.Register( nameof(Spacing)); - public static readonly StyledProperty PlayCommandProperty = AvaloniaProperty.Register( - nameof(PlayCommand)); + public static readonly StyledProperty PlayCommandProperty = + AvaloniaProperty.Register( + nameof(PlayCommand)); - public static readonly StyledProperty SettingsCommandProperty = AvaloniaProperty.Register( - nameof(SettingsCommand)); + public static readonly StyledProperty SettingsCommandProperty = + AvaloniaProperty.Register( + nameof(SettingsCommand)); - public static readonly StyledProperty ProfileDescriptionProperty = AvaloniaProperty.Register( - nameof(ProfileDescription)); + public static readonly StyledProperty ProfileDescriptionProperty = + AvaloniaProperty.Register( + nameof(ProfileDescription)); public string ProfileDescription { @@ -61,6 +62,4 @@ public string ProfileName get => GetValue(ProfileNameProperty); set => SetValue(ProfileNameProperty, value); } - } - diff --git a/src/Gml.Launcher/Views/Components/ServerListComponent.axaml b/src/Gml.Launcher/Views/Components/ServerListComponent.axaml index c8c0f80..bacca1b 100644 --- a/src/Gml.Launcher/Views/Components/ServerListComponent.axaml +++ b/src/Gml.Launcher/Views/Components/ServerListComponent.axaml @@ -10,49 +10,48 @@ mc:Ignorable="d" d:DesignWidth="80" d:DesignHeight="350" x:Class="Gml.Launcher.Views.Components.ServerListComponent"> + HorizontalAlignment="Center" + ClipToBounds="True" + MaxHeight="350" + Padding="5" + CornerRadius="50"> - - + + - + - - - - - + + + + + - - - - - - - - + + + + + + + + - diff --git a/src/Gml.Launcher/Views/Components/ServerListComponent.axaml.cs b/src/Gml.Launcher/Views/Components/ServerListComponent.axaml.cs index 9207fa8..257848d 100644 --- a/src/Gml.Launcher/Views/Components/ServerListComponent.axaml.cs +++ b/src/Gml.Launcher/Views/Components/ServerListComponent.axaml.cs @@ -1,6 +1,4 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; +using Avalonia.Controls; namespace Gml.Launcher.Views.Components; @@ -11,4 +9,3 @@ public ServerListComponent() InitializeComponent(); } } - diff --git a/src/Gml.Launcher/Views/Components/SidebarComponent.axaml.cs b/src/Gml.Launcher/Views/Components/SidebarComponent.axaml.cs index 4a6578c..500860d 100644 --- a/src/Gml.Launcher/Views/Components/SidebarComponent.axaml.cs +++ b/src/Gml.Launcher/Views/Components/SidebarComponent.axaml.cs @@ -7,18 +7,21 @@ namespace Gml.Launcher.Views.Components; public class SidebarComponent : TemplatedControl { + public static readonly StyledProperty ProfileCommandProperty = + AvaloniaProperty.Register( + nameof(ProfileCommand)); - public static readonly StyledProperty ProfileCommandProperty = AvaloniaProperty.Register( - nameof(ProfileCommand)); + public static readonly StyledProperty LogoutCommandProperty = + AvaloniaProperty.Register( + nameof(LogoutCommand)); - public static readonly StyledProperty LogoutCommandProperty = AvaloniaProperty.Register( - nameof(LogoutCommand)); + public static readonly StyledProperty ListViewModelProperty = + AvaloniaProperty.Register( + nameof(ListViewModel)); - public static readonly StyledProperty ListViewModelProperty = AvaloniaProperty.Register( - nameof(ListViewModel)); - - public static readonly StyledProperty HomeCommandProperty = AvaloniaProperty.Register( - nameof(HomeCommand)); + public static readonly StyledProperty HomeCommandProperty = + AvaloniaProperty.Register( + nameof(HomeCommand)); public ICommand HomeCommand { @@ -43,6 +46,4 @@ public ICommand ProfileCommand get => GetValue(ProfileCommandProperty); set => SetValue(ProfileCommandProperty, value); } - } - diff --git a/src/Gml.Launcher/Views/Components/StackFrameBorder.axaml b/src/Gml.Launcher/Views/Components/StackFrameBorder.axaml index 440ea7f..1d62890 100644 --- a/src/Gml.Launcher/Views/Components/StackFrameBorder.axaml +++ b/src/Gml.Launcher/Views/Components/StackFrameBorder.axaml @@ -9,16 +9,16 @@ - diff --git a/src/Gml.Launcher/Views/Components/StackFrameBorder.axaml.cs b/src/Gml.Launcher/Views/Components/StackFrameBorder.axaml.cs index 43b8151..008070e 100644 --- a/src/Gml.Launcher/Views/Components/StackFrameBorder.axaml.cs +++ b/src/Gml.Launcher/Views/Components/StackFrameBorder.axaml.cs @@ -1,13 +1,10 @@ using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Metadata; namespace Gml.Launcher.Views.Components; public class StackFrameBorder : ItemsControl { - public static readonly StyledProperty SpacingProperty = AvaloniaProperty.Register( nameof(Spacing)); @@ -16,6 +13,4 @@ public int Spacing get => GetValue(SpacingProperty); set => SetValue(SpacingProperty, value); } - } - diff --git a/src/Gml.Launcher/Views/MainWindow.axaml b/src/Gml.Launcher/Views/MainWindow.axaml index 44eb611..c391654 100644 --- a/src/Gml.Launcher/Views/MainWindow.axaml +++ b/src/Gml.Launcher/Views/MainWindow.axaml @@ -15,6 +15,7 @@ Height="600" MinHeight="600" CanResize="False" + Closed="WindowClosed" x:Class="Gml.Launcher.Views.MainWindow" x:DataType="vm:MainWindowViewModel" Background="Transparent" diff --git a/src/Gml.Launcher/Views/MainWindow.axaml.cs b/src/Gml.Launcher/Views/MainWindow.axaml.cs index d7c6b89..5c50066 100644 --- a/src/Gml.Launcher/Views/MainWindow.axaml.cs +++ b/src/Gml.Launcher/Views/MainWindow.axaml.cs @@ -1,7 +1,5 @@ using System; -using System.Reactive.Subjects; using Avalonia; -using Avalonia.Controls; using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; @@ -14,14 +12,12 @@ public partial class MainWindow : ReactiveWindow { public MainWindow() { - this.WhenActivated(disposables => { }); + this.WhenActivated(_ => { }); AvaloniaXamlLoader.Load(this); #if DEBUG this.AttachDevTools(); #endif - - } protected override void OnDataContextChanged(EventArgs e) @@ -40,14 +36,24 @@ protected override void OnDataContextChanged(EventArgs e) protected override void OnClosed(EventArgs e) { - if(DataContext is MainWindowViewModel viewModel) - viewModel.OnClosed.OnNext(false); + SendCloseEvent(); base.OnClosed(e); } + private void SendCloseEvent() + { + if (DataContext is MainWindowViewModel viewModel) + viewModel.OnClosed.OnNext(false); + } + protected override void OnPointerPressed(PointerPressedEventArgs e) { BeginMoveDrag(e); } + + private void WindowClosed(object? sender, EventArgs e) + { + SendCloseEvent(); + } } diff --git a/src/Gml.Launcher/Views/Pages/LoginPageView.axaml b/src/Gml.Launcher/Views/Pages/LoginPageView.axaml index 02dddc6..843dbd6 100644 --- a/src/Gml.Launcher/Views/Pages/LoginPageView.axaml +++ b/src/Gml.Launcher/Views/Pages/LoginPageView.axaml @@ -5,7 +5,6 @@ xmlns:vm="clr-namespace:Gml.Launcher.ViewModels.Pages" xmlns:lang="clr-namespace:Gml.Launcher.Assets.Resources" xmlns:components="clr-namespace:Gml.Launcher.Views.Components" - xmlns:system="clr-namespace:System;assembly=System.Runtime" xmlns:converters="clr-namespace:Gml.Launcher.Core.Converters" mc:Ignorable="d" d:DesignWidth="800" @@ -49,7 +48,7 @@ + Margin="0, 0, 0, 20" /> + - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - + + - + diff --git a/src/Gml.Launcher/Views/Pages/SettingsPageView.axaml.cs b/src/Gml.Launcher/Views/Pages/SettingsPageView.axaml.cs index 33a4d74..327fdf0 100644 --- a/src/Gml.Launcher/Views/Pages/SettingsPageView.axaml.cs +++ b/src/Gml.Launcher/Views/Pages/SettingsPageView.axaml.cs @@ -1,9 +1,14 @@ -using System.Linq; +using System; +using System.Linq; using Avalonia; using Avalonia.Controls; -using Avalonia.Input; +using Avalonia.Interactivity; using Avalonia.Markup.Xaml; +using Avalonia.Platform.Storage; using Avalonia.ReactiveUI; +using Avalonia.VisualTree; +using GamerVII.Notification.Avalonia; +using Gml.Launcher.Assets; using Gml.Launcher.ViewModels.Pages; using ReactiveUI; @@ -24,10 +29,37 @@ private void OnTextInput(object sender, AvaloniaPropertyChangedEventArgs e) private void OnTextInput(object? sender, TextChangedEventArgs e) { - if (sender is TextBox textBox) + if (sender is TextBox textBox) textBox.Text = string.Concat(textBox.Text?.Where(char.IsDigit) ?? string.Empty); + } + + private async void OpenFileDialog(object? sender, RoutedEventArgs e) + { + try { - textBox.Text = string.Concat(textBox.Text?.Where(char.IsDigit) ?? string.Empty); - } + if (this.GetVisualRoot() is MainWindow mainWindow) + { + var folders = await mainWindow.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions + { + AllowMultiple = false, + Title = "Select a folder" + }); + if (folders.Count != 1) return; + + ViewModel!.InstallationFolder = folders[0].Path.AbsolutePath; + ViewModel!.ChangeFolder(); + } + } + catch (Exception exception) + { + //ToDo: Sentry send + ViewModel?.MainViewModel.Manager + .CreateMessage(true, "#D03E3E", + ViewModel.LocalizationService.GetString(ResourceKeysDictionary.Error), + ViewModel.LocalizationService.GetString(ResourceKeysDictionary.InvalidFolder)) + .Dismiss() + .WithDelay(TimeSpan.FromSeconds(3)) + .Queue(); + } } } diff --git a/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml b/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml index 617d3f0..3432c23 100644 --- a/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml +++ b/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml @@ -39,7 +39,7 @@ + Foreground="{DynamicResource ContentColor}" /> diff --git a/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml.cs b/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml.cs index e1bf1ca..2692191 100644 --- a/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml.cs +++ b/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml.cs @@ -1,6 +1,4 @@ -using Avalonia; using Avalonia.Controls; -using Avalonia.Markup.Xaml; using Gml.Launcher.ViewModels; namespace Gml.Launcher.Views.SplashScreen; @@ -16,7 +14,7 @@ public MainWindow GetMainWindow() { return new MainWindow { - DataContext = new MainWindowViewModel(), + DataContext = new MainWindowViewModel() }; } } diff --git a/src/Gml.Launcher/app.manifest b/src/Gml.Launcher/app.manifest index ed05310..132e5ed 100644 --- a/src/Gml.Launcher/app.manifest +++ b/src/Gml.Launcher/app.manifest @@ -1,18 +1,18 @@  - - + + - - - + + + - - - - + + + +