using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Platform.Storage; using ModpackUpdater.Apps.Client.Gui.LangRes; using ModpackUpdater.Manager; using MsBox.Avalonia; using MsBox.Avalonia.Enums; using Pilz.Extensions; using Pilz.SymbolPacks.Sets; using Pilz.UI.AvaloniaUI.Symbols; using System.Diagnostics; using System.Reflection; using Pilz.UI.Symbols; namespace ModpackUpdater.Apps.Client.Gui; public partial class MainForm : Window { private readonly UpdateCheckOptions updateOptions = new(); private ModpackInfo modpackInfo = new(); private ModpackConfig updateConfig = new(); private ModpackFeatures? features; private UpdateCheckResult? lastUpdateCheckResult; private bool currentUpdating; private bool loadingData; private int curOptionsRow = 3; public MainForm() { InitializeComponent(); Title = $"{Title} (v{Assembly.GetExecutingAssembly().GetAppVersion()})"; Closing += MainForm_Closing; Loaded += MainForm_Loaded; ButtonSearchProfileFolder.ImageSource = Symbols.Fluent.GetImageSource(SymbolsFluent.opened_folder); ButtonCheckForUpdates.ImageSource = Symbols.Fluent.GetImageSource(SymbolsFluent.update); ButtonInstall.ImageSource = Symbols.Fluent.GetImageSource(SymbolsFluent.software_installer); MenuItemRepair.Icon = Symbols.Fluent.GetImage(SymbolsFluent.wrench, SymbolSize.Small); ClearStatus(); LoadProfileToUi(); } #region Features private void SetStatus(string statusText, IImage? image) { TextStatus.Text = statusText; ImageStatus.Source = image; } private void ClearStatus() { TextStatus.Text = "-"; ImageStatus.Source = null; } private void LoadProfileToUi() { loadingData = true; TextBoxMinecraftProfileFolder.Text = modpackInfo?.LocaLPath ?? AppConfig.Instance.LastMinecraftProfilePath ?? TextBoxMinecraftProfileFolder.Text; TextBoxModpackConfig.Text = modpackInfo?.ConfigUrl ?? TextBoxModpackConfig.Text; TextBoxInstallKey.Text = modpackInfo?.ExtrasKey ?? TextBoxInstallKey.Text; loadingData = false; } private void LoadOptionsToUi() { //foreach (var set in ) //{ // // ... //} } private async void CheckStatusAndUpdate(bool loadProfileToUi) { if (CheckStatus(loadProfileToUi)) await ExecuteUpdate(false, false); } private bool CheckStatus(bool loadProfileToUi) { try { modpackInfo = ModpackInfo.TryLoad(TextBoxMinecraftProfileFolder.Text?.Trim()); } catch { } if (loadProfileToUi) LoadProfileToUi(); try { updateConfig = ModpackConfig.LoadFromUrl(TextBoxModpackConfig.Text); } catch (Exception) { } if (modpackInfo != null) features = new(updateConfig); LabelInstallKey.IsVisible = TextBoxInstallKey.IsVisible = !string.IsNullOrWhiteSpace(updateConfig.UnleashApiUrl); if (modpackInfo == null || string.IsNullOrWhiteSpace(TextBoxMinecraftProfileFolder.Text) /*|| modpackInfo.Valid*/) { SetStatus(GeneralLangRes.MinecraftProfileFolderSeemsInvalid, Symbols.Fluent.GetImageSource(SymbolsFluent.warning_shield)); ButtonCheckForUpdates.IsEnabled = false; ButtonInstall.IsEnabled = false; return false; } else if (string.IsNullOrWhiteSpace(TextBoxModpackConfig.Text)) { SetStatus(GeneralLangRes.ConfigIncompleteOrNotLoaded, Symbols.Fluent.GetImageSource(SymbolsFluent.warning_shield)); ButtonCheckForUpdates.IsEnabled = false; ButtonInstall.IsEnabled = false; return false; } else if (updateConfig.Maintenance && !updateOptions.IgnoreMaintenance) { SetStatus(GeneralLangRes.UpdateServerInMaintenance, Symbols.Fluent.GetImageSource(SymbolsFluent.services)); ButtonCheckForUpdates.IsEnabled = false; ButtonInstall.IsEnabled = false; return false; } LoadOptionsToUi(); ButtonCheckForUpdates.IsEnabled = true; ButtonInstall.IsEnabled = true; return true; } private async Task ExecuteUpdate(bool doInstall, bool repair) { // Ensure set extras key modpackInfo.ExtrasKey = TextBoxInstallKey.Text?.Trim(); var updater = new ModpackInstaller(updateConfig, modpackInfo); updater.InstallProgessUpdated += Update_InstallProgessUpdated; updater.CheckingProgressUpdated += Updated_CheckingProgresssUpdated; void error() { SetStatus(GeneralLangRes.ErrorOnUpdateCheckOrUpdating, Symbols.Fluent.GetImageSource(SymbolsFluent.close)); currentUpdating = false; } void installing() { SetStatus(GeneralLangRes.Installing, Symbols.Fluent.GetImageSource(SymbolsFluent.software_installer)); currentUpdating = true; } void updatesAvailable() { SetStatus(GeneralLangRes.AnUpdateIsAvailable, Symbols.Fluent.GetImageSource(SymbolsFluent.software_installer)); } void everythingOk() { SetStatus(GeneralLangRes.EverythingIsRightAndUpToDate, Symbols.Fluent.GetImageSource(SymbolsFluent.done)); currentUpdating = false; } // Check only if not pressed "install", not really needed otherwise. if (lastUpdateCheckResult is null || !doInstall || repair) { SetStatus(GeneralLangRes.CheckingForUpdates, Symbols.Fluent.GetImageSource(SymbolsFluent.update)); // Check for extras once again updateOptions.IncludeExtras = features != null && features.IsEnabled(ModpackFeatures.FeatureAllowExtas, new AllowExtrasFeatureContext(modpackInfo)); // Force re-install on repair updateOptions.IgnoreInstalledVersion = repair; try { lastUpdateCheckResult = await updater.Check(updateOptions); } catch (Exception) { error(); if (Debugger.IsAttached) throw; } finally { } } // Error while update check if (lastUpdateCheckResult is null || lastUpdateCheckResult.HasError) { error(); return; } // Load options // lastUpdateCheckResult.OptionsAvailable... // lastUpdateCheckResult.OptionsEnabled... // No updates available if (!lastUpdateCheckResult.HasUpdates) { everythingOk(); return; } // Updates available (but don't install) if (!doInstall) { updatesAvailable(); return; } // Install updates installing(); currentUpdating = true; try { // Install if (await updater.Install(lastUpdateCheckResult) == false) { error(); return; } // Success lastUpdateCheckResult = null; // Reset last update check, a new one would be needed now. everythingOk(); } catch (Exception) { // Error error(); if (Debugger.IsAttached) throw; } } private void Updated_CheckingProgresssUpdated(int toCheck, int processed) { SetStatus(Math.Round(processed / (double)toCheck * 100d, 1) + "%", Symbols.Fluent.GetImageSource(SymbolsFluent.update)); } private void Update_InstallProgessUpdated(UpdateCheckResult result, int processedSyncs) { int actionCount = result.Actions.Count; SetStatus(Math.Round(processedSyncs / (double)actionCount * 100d, 1) + "%", Symbols.Fluent.GetImageSource(SymbolsFluent.software_installer)); } #endregion #region Gui private void MainForm_Closing(object? sender, WindowClosingEventArgs e) { AppConfig.Instance.LastMinecraftProfilePath = TextBoxMinecraftProfileFolder.Text?.Trim(); } private async void MainForm_Loaded(object? sender, RoutedEventArgs e) { var updater = new AppUpdater(Program.UPDATE_URL); if (await updater.Check() && await MessageBoxManager.GetMessageBoxStandard(MsgBoxLangRes.UpdateAvailable_Title, MsgBoxLangRes.UpdateAvailable, ButtonEnum.YesNo).ShowWindowDialogAsync(this) == ButtonResult.Ok) { SetStatus(GeneralLangRes.DownloadProgramUpdate, Symbols.Fluent.GetImageSource(SymbolsFluent.software_installer)); IsEnabled = false; await updater.Install(); //Application.Restart(); // FIXME return; } CheckStatusAndUpdate(true); } private void TextBoxMinecraftProfileFolder_TextInserted(object? o, Avalonia.Input.TextInputEventArgs args) { if (!loadingData) CheckStatusAndUpdate(true); } private void TextBoxModpackConfig_TextInserted(object? o, Avalonia.Input.TextInputEventArgs args) { if (!loadingData) CheckStatusAndUpdate(false); } private void TextBoxInstallKey_TextInserted(object? o, Avalonia.Input.TextInputEventArgs args) { if (!loadingData) CheckStatusAndUpdate(false); } private async void ButtonSearchProfileFolder_Click(object? sender, RoutedEventArgs e) { var filePaths = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = GeneralLangRes.SelectMinecraftProfileFolder, SuggestedStartLocation = await StorageProvider.TryGetFolderFromPathAsync(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)), AllowMultiple = false, }); if (filePaths.Count >= 1) TextBoxMinecraftProfileFolder.Text = filePaths[0].Path.ToString(); } private async void ButtonCheckForUpdates_Click(object? sender, RoutedEventArgs e) { ClearStatus(); await ExecuteUpdate(false, false); } private async void ButtonInstall_Click(object? sender, RoutedEventArgs e) { if (currentUpdating) return; ClearStatus(); await ExecuteUpdate(true, false); } private async void MenuItemRepair_Click(object? sender, RoutedEventArgs e) { if (currentUpdating) return; ClearStatus(); await ExecuteUpdate(true, true); } #endregion }