diff --git a/src/ImeSense.Launchers.Belarus.Core/Manager/ISplashScreenManager.cs b/src/ImeSense.Launchers.Belarus.Core/Manager/ISplashScreenManager.cs new file mode 100644 index 0000000..d89a57c --- /dev/null +++ b/src/ImeSense.Launchers.Belarus.Core/Manager/ISplashScreenManager.cs @@ -0,0 +1,13 @@ +using ImeSense.Launchers.Belarus.Models; + +namespace ImeSense.Launchers.Belarus.Core.Manager; + +public interface ISplashScreenManager +{ + CancellationToken CancellationToken { get; } + InformationMessage SplashScreenMessage { get; } + int CurrentProgress { get; set; } + int MaxProgress { get; set; } + void UpdateInformation(InformationMessage splashScreenMessage); + void Cancel(); +} diff --git a/src/ImeSense.Launchers.Belarus.Core/Manager/InitializerManager.cs b/src/ImeSense.Launchers.Belarus.Core/Manager/InitializerManager.cs index ee81b4b..e50b255 100644 --- a/src/ImeSense.Launchers.Belarus.Core/Manager/InitializerManager.cs +++ b/src/ImeSense.Launchers.Belarus.Core/Manager/InitializerManager.cs @@ -1,10 +1,11 @@ -using System.Collections.ObjectModel; +using System; using System.Diagnostics; using ImeSense.Launchers.Belarus.Core.Helpers; using ImeSense.Launchers.Belarus.Core.Models; using ImeSense.Launchers.Belarus.Core.Services; using ImeSense.Launchers.Belarus.Core.Storage; +using ImeSense.Launchers.Belarus.Models; using Microsoft.Extensions.Logging; @@ -30,22 +31,27 @@ public class InitializerManager( public bool IsGameReleaseCurrent { get; private set; } = true; public bool IsUserAuthorized { get; private set; } - public async Task InitializeAsync(CancellationToken cancellationToken = default) + public async Task InitializeAsync(ISplashScreenManager splashScreenManager) { try { var stopwatch = new Stopwatch(); stopwatch.Start(); - _launcherStorage.IsCheckGitHubConnection = await CheckGitHubConnectionAsync(cancellationToken); + + splashScreenManager.UpdateInformation(new InformationMessage( + _localeManager.GetStringByKey("LocalizedStrings.Loading"), + _localeManager.GetStringByKey("LocalizedStrings.AccessingRepository"))); + + _launcherStorage.IsCheckGitHubConnection = await CheckGitHubConnectionAsync(splashScreenManager.CancellationToken); _logger.LogInformation("Check GitHub connection time: {Time}", stopwatch.ElapsedMilliseconds); var locale = _userManager?.UserSettings?.Locale; if (_launcherStorage.IsCheckGitHubConnection) { - var isLauncherReleaseCurrent = await IsLauncherReleaseCurrentAsync(cancellationToken); + var isLauncherReleaseCurrent = await IsLauncherReleaseCurrentAsync(splashScreenManager.CancellationToken); _logger.LogInformation("Check launcher update time: {Time}", stopwatch.ElapsedMilliseconds); if (!isLauncherReleaseCurrent) { var pathLauncherUpdater = Path.Combine(DirectoryStorage.Base, FileNameStorage.SBLauncherUpdater); - await _updaterService.UpdaterAsync(UriStorage.LauncherApiUri, pathLauncherUpdater, cancellationToken); + await _updaterService.UpdaterAsync(UriStorage.LauncherApiUri, pathLauncherUpdater, splashScreenManager.CancellationToken); var updater = Launcher.Launch(pathLauncherUpdater); updater?.Start(); @@ -53,18 +59,18 @@ public async Task InitializeAsync(CancellationToken cancellationToken = default) return; } - _launcherStorage.GitHubRelease = await _gitStorageApiService.GetLastReleaseAsync(cancellationToken: cancellationToken); + _launcherStorage.GitHubRelease = await _gitStorageApiService.GetLastReleaseAsync(cancellationToken: splashScreenManager.CancellationToken); _logger.LogInformation("Check last release time: {Time}", stopwatch.ElapsedMilliseconds); - IsGameReleaseCurrent = await IsGameReleaseCurrentAsync(cancellationToken); + IsGameReleaseCurrent = await IsGameReleaseCurrentAsync(splashScreenManager.CancellationToken); IsUserAuthorized = File.Exists(PathStorage.LauncherSetting); if (IsUserAuthorized) { - await Task.Factory.StartNew(() => LoadNewsAsync(locale, cancellationToken)); + await Task.Factory.StartNew(() => LoadNewsAsync(locale, splashScreenManager.CancellationToken)); } else { - await Task.Factory.StartNew(() => LoadNewsAsync(cancellationToken: cancellationToken)); + await Task.Factory.StartNew(() => LoadNewsAsync(cancellationToken: splashScreenManager.CancellationToken)); } - await Task.Factory.StartNew(() => LoadWebResourcesAsync(cancellationToken: cancellationToken)); + await Task.Factory.StartNew(() => LoadWebResourcesAsync(cancellationToken: splashScreenManager.CancellationToken)); } else { if (IsUserAuthorized) { _launcherStorage.NewsContents = new(LoadErrorNews(locale) ?? []); @@ -72,7 +78,7 @@ public async Task InitializeAsync(CancellationToken cancellationToken = default) _launcherStorage.NewsContents = new(LoadErrorNews() ?? []); } - _launcherStorage.GitHubRelease = await FileDataHelper.LoadDataAsync(PathStorage.CurrentRelease, cancellationToken); + _launcherStorage.GitHubRelease = await FileDataHelper.LoadDataAsync(PathStorage.CurrentRelease, splashScreenManager.CancellationToken); } stopwatch.Stop(); diff --git a/src/ImeSense.Launchers.Belarus.Core/Manager/SplashScreenManager.cs b/src/ImeSense.Launchers.Belarus.Core/Manager/SplashScreenManager.cs new file mode 100644 index 0000000..3712263 --- /dev/null +++ b/src/ImeSense.Launchers.Belarus.Core/Manager/SplashScreenManager.cs @@ -0,0 +1,33 @@ +using ImeSense.Launchers.Belarus.Models; + +using ReactiveUI; +using ReactiveUI.Fody.Helpers; + +namespace ImeSense.Launchers.Belarus.Core.Manager; + +public class SplashScreenManager : ReactiveObject, ISplashScreenManager +{ + private readonly CancellationTokenSource _cts = new(); + + public CancellationToken CancellationToken { get; } + [Reactive] public InformationMessage SplashScreenMessage { get; private set; } + [Reactive] public int CurrentProgress { get; set; } = 0; + public int MaxProgress { get; set; } + + public SplashScreenManager() + { + CancellationToken = _cts.Token; + SplashScreenMessage = new InformationMessage("Title", "Description"); + } + + public void Cancel() + { + _cts.Cancel(); + } + + public void UpdateInformation(InformationMessage splashScreenMessage) + { + CurrentProgress++; + SplashScreenMessage = splashScreenMessage; + } +} diff --git a/src/ImeSense.Launchers.Belarus.Core/Models/InformationMessage.cs b/src/ImeSense.Launchers.Belarus.Core/Models/InformationMessage.cs new file mode 100644 index 0000000..329c82c --- /dev/null +++ b/src/ImeSense.Launchers.Belarus.Core/Models/InformationMessage.cs @@ -0,0 +1,3 @@ +namespace ImeSense.Launchers.Belarus.Models; + +public record struct InformationMessage(string Title, string Description); diff --git a/src/ImeSense.Launchers.Belarus/App.axaml.cs b/src/ImeSense.Launchers.Belarus/App.axaml.cs index 537b731..e05ea48 100644 --- a/src/ImeSense.Launchers.Belarus/App.axaml.cs +++ b/src/ImeSense.Launchers.Belarus/App.axaml.cs @@ -1,7 +1,6 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; -using ImeSense.Launchers.Belarus.Models; using ImeSense.Launchers.Belarus.Services; using ImeSense.Launchers.Belarus.ViewModels; using ImeSense.Launchers.Belarus.Views; @@ -49,7 +48,6 @@ private static ServiceCollection ConfigureServices() return services; } - public override void Initialize() { var logger = _serviceProvider.GetRequiredService>(); @@ -66,14 +64,14 @@ public override void Initialize() public override async void OnFrameworkInitializationCompleted() { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - var splashScreenViewModel = _serviceProvider.GetRequiredService(); - var initializerManager = _serviceProvider.GetRequiredService(); var userManager = _serviceProvider.GetRequiredService(); - await userManager.LoadAsync(splashScreenViewModel.CancellationToken); - initializerManager.InitializeLocale(); - var localeManager = _serviceProvider.GetRequiredService(); + var splashScreenManager = _serviceProvider.GetRequiredService(); + splashScreenManager.MaxProgress = 3; + + await userManager.LoadAsync(splashScreenManager.CancellationToken); + initializerManager.InitializeLocale(); var mainViewModel = _serviceProvider.GetRequiredService(); desktop.MainWindow = new MainWindow { @@ -82,18 +80,10 @@ public override async void OnFrameworkInitializationCompleted() desktop.MainWindow.Show(); try { - mainViewModel.ShowSplashScreenImpl(splashScreenViewModel); - splashScreenViewModel.Progress++; - splashScreenViewModel.InformationMessage = new InformationMessage( - localeManager.GetStringByKey("LocalizedStrings.Loading"), - localeManager.GetStringByKey("LocalizedStrings.AccessingRepository")); - await initializerManager.InitializeAsync(splashScreenViewModel.CancellationToken); - splashScreenViewModel.Progress++; - splashScreenViewModel.InformationMessage = new InformationMessage( - localeManager.GetStringByKey("LocalizedStrings.Loading"), - localeManager.GetStringByKey("LocalizedStrings.DataInitialization")); - await mainViewModel.InitializeAsync(splashScreenViewModel.CancellationToken); - splashScreenViewModel.Progress++; + mainViewModel.ShowSplashScreenImpl(); + + await initializerManager.InitializeAsync(splashScreenManager); + await mainViewModel.InitializeAsync(splashScreenManager); } catch (TaskCanceledException) { desktop.Shutdown(); return; diff --git a/src/ImeSense.Launchers.Belarus/Injection/ServiceCollectionExtensions.cs b/src/ImeSense.Launchers.Belarus/Injection/ServiceCollectionExtensions.cs index 802c82d..4af041b 100644 --- a/src/ImeSense.Launchers.Belarus/Injection/ServiceCollectionExtensions.cs +++ b/src/ImeSense.Launchers.Belarus/Injection/ServiceCollectionExtensions.cs @@ -28,6 +28,7 @@ public static IServiceCollection AddManagers(this IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddScoped(); return services; } diff --git a/src/ImeSense.Launchers.Belarus/Models/InformationMessage.cs b/src/ImeSense.Launchers.Belarus/Models/InformationMessage.cs deleted file mode 100644 index 5cdf196..0000000 --- a/src/ImeSense.Launchers.Belarus/Models/InformationMessage.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace ImeSense.Launchers.Belarus.Models; - -public record InformationMessage(string Title, string Description); diff --git a/src/ImeSense.Launchers.Belarus/ViewModels/MainWindowViewModel.cs b/src/ImeSense.Launchers.Belarus/ViewModels/MainWindowViewModel.cs index e92bf9d..02c5306 100644 --- a/src/ImeSense.Launchers.Belarus/ViewModels/MainWindowViewModel.cs +++ b/src/ImeSense.Launchers.Belarus/ViewModels/MainWindowViewModel.cs @@ -11,6 +11,7 @@ using ReactiveUI; using ReactiveUI.Fody.Helpers; +using ImeSense.Launchers.Belarus.Models; namespace ImeSense.Launchers.Belarus.ViewModels; @@ -20,20 +21,24 @@ public class MainWindowViewModel : ReactiveObject private readonly IUpdaterService _updaterService; private readonly InitializerManager _initializerManager; private readonly ViewModelLocator _viewModelLocator; + private readonly IApplicationLocaleManager _localeManager; private readonly StartGameViewModel _startGameViewModel; private readonly LauncherViewModel _launcherViewModel; + private readonly SplashScreenViewModel _splashScreenViewModel; [Reactive] public ReactiveObject PageViewModel { get; set; } = null!; public MainWindowViewModel(ILogger? logger, InitializerManager initializerManager, - IUpdaterService updaterService, ViewModelLocator viewModelLocator) + IUpdaterService updaterService, ViewModelLocator viewModelLocator, IApplicationLocaleManager localeManager) { _logger = logger; _initializerManager = initializerManager; _updaterService = updaterService; _viewModelLocator = viewModelLocator; + _localeManager = localeManager; _startGameViewModel = viewModelLocator.StartGameViewModel; _launcherViewModel = viewModelLocator.LauncherViewModel; + _splashScreenViewModel = _viewModelLocator.SplashScreenViewModel; } public MainWindowViewModel() @@ -45,17 +50,22 @@ public MainWindowViewModel() _initializerManager = null!; _updaterService = null!; _viewModelLocator = null!; + _localeManager = null!; + _splashScreenViewModel = null!; } - public async Task InitializeAsync(CancellationToken cancellationToken = default) + public async Task InitializeAsync(ISplashScreenManager splashScreenManager) { var stopwatch = new Stopwatch(); stopwatch.Start(); + splashScreenManager.UpdateInformation(new InformationMessage( + _localeManager.GetStringByKey("LocalizedStrings.Loading"), + _localeManager.GetStringByKey("LocalizedStrings.DataInitialization"))); + ProcessHelper.KillAllXrEngine(); var isCurrentRelease = _initializerManager.IsGameReleaseCurrent; - if (File.Exists(PathStorage.LauncherSetting)) { try { if (!isCurrentRelease) { @@ -94,8 +104,8 @@ public void ShowStartGameImpl() PageViewModel = _startGameViewModel; } - public void ShowSplashScreenImpl(SplashScreenViewModel splash) + public void ShowSplashScreenImpl() { - PageViewModel = splash; + PageViewModel = _splashScreenViewModel; } } diff --git a/src/ImeSense.Launchers.Belarus/ViewModels/SplashScreenViewModel.cs b/src/ImeSense.Launchers.Belarus/ViewModels/SplashScreenViewModel.cs index 03f5af0..9f26413 100644 --- a/src/ImeSense.Launchers.Belarus/ViewModels/SplashScreenViewModel.cs +++ b/src/ImeSense.Launchers.Belarus/ViewModels/SplashScreenViewModel.cs @@ -1,6 +1,7 @@ using System.Reactive; using ImeSense.Launchers.Belarus.Core.Manager; +using ImeSense.Launchers.Belarus.Helpers; using ImeSense.Launchers.Belarus.Models; using ReactiveUI; @@ -10,30 +11,44 @@ namespace ImeSense.Launchers.Belarus.ViewModels; public class SplashScreenViewModel : ReactiveObject { - private readonly CancellationTokenSource _cts = new(); - public CancellationToken CancellationToken => _cts.Token; - private readonly IWindowManager _windowManager; - public ReactiveCommand Cancel { get; set; } = null!; - [Reactive] public InformationMessage? InformationMessage { get; set; } - [Reactive] public int Progress { get; set; } = 0; - [Reactive] public int MaxProgress { get; set; } = 3; + ISplashScreenManager SplashScreen { get; set; } + [Reactive] public InformationMessage InformationMessage { get; set; } + [Reactive] public int Progress { get; set; } + public int MaxProgress { get; private set; } + + public ReactiveCommand Cancel { get; set; } = null!; + public SplashScreenViewModel() { + ExceptionHelper.ThrowIfEmptyConstructorNotInDesignTime($"{nameof(StartGameViewModel)}"); + _windowManager = null!; + SplashScreen = null!; } - public SplashScreenViewModel(IWindowManager windowManager) : base() + public SplashScreenViewModel(IWindowManager windowManager, ISplashScreenManager splashScreen) { - InformationMessage = new InformationMessage("Title", "Description"); - Cancel = ReactiveCommand.Create(CancelImpl); _windowManager = windowManager; + SplashScreen = splashScreen; + Progress = SplashScreen.CurrentProgress; + MaxProgress = SplashScreen.MaxProgress; + + this.WhenAnyValue( + x => x.SplashScreen.CurrentProgress, + x => x.SplashScreen.SplashScreenMessage) + .Subscribe(u => { + Progress = u.Item1; + InformationMessage = u.Item2; + }); + + Cancel = ReactiveCommand.Create(CancelImpl); } private void CancelImpl() { - _cts.Cancel(); + SplashScreen.Cancel(); _windowManager.Close(); } }