355 lines
11 KiB
C#
355 lines
11 KiB
C#
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Interactivity;
|
|
using Avalonia.Media;
|
|
using Avalonia.Platform.Storage;
|
|
using Avalonia.Threading;
|
|
using ModpackUpdater.Apps.Client.Gui.LangRes;
|
|
using ModpackUpdater.Manager;
|
|
using Pilz.Extensions;
|
|
using Pilz.SymbolPacks.Sets;
|
|
using Pilz.UI.AvaloniaUI.Symbols;
|
|
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;
|
|
|
|
Dispatcher.UIThread.Post(() => loadingData = false, DispatcherPriority.Background);
|
|
}
|
|
|
|
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
|
|
{
|
|
// Ignore
|
|
}
|
|
|
|
if (loadProfileToUi)
|
|
LoadProfileToUi();
|
|
|
|
try
|
|
{
|
|
updateConfig = ModpackConfig.LoadFromUrl(TextBoxModpackConfig.Text);
|
|
}
|
|
catch
|
|
{
|
|
// Ignore
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
#if !DISABLE_UPDATE && !DEBUG
|
|
try
|
|
{
|
|
var myAppPath = EnvironmentEx.ProcessPath!;
|
|
var updater = new UpdateClient(Program.UpdateUrl, Assembly.GetEntryAssembly()!.GetAppVersion(), AppChannel.Stable)
|
|
{
|
|
Distro = RuntimeInformationsEx.GetRuntimeIdentifier(),
|
|
};
|
|
|
|
if (await updater.CheckForUpdate() is {} packageToInstall
|
|
&& await MessageBoxManager.GetMessageBoxStandard(MsgBoxLangRes.UpdateAvailable_Title, MsgBoxLangRes.UpdateAvailable, ButtonEnum.YesNo, MsBox.Avalonia.Enums.Icon.Info).ShowWindowDialogAsync(this) == ButtonResult.Yes)
|
|
{
|
|
SetStatus(GeneralLangRes.DownloadProgramUpdate, Symbols.Fluent.GetImageSource(SymbolsFluent.software_installer));
|
|
IsEnabled = false;
|
|
if (await updater.DownloadPackageAsync(packageToInstall)
|
|
&& await updater.InstallPackageAsync(packageToInstall, myAppPath))
|
|
{
|
|
IsVisible = false;
|
|
await Process.Start(myAppPath).WaitForExitAsync();
|
|
Environment.Exit(0);
|
|
return;
|
|
}
|
|
IsEnabled = true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await MessageBoxManager.GetMessageBoxStandard("error", ex.ToString(), ButtonEnum.Ok, MsBox.Avalonia.Enums.Icon.Error).ShowWindowDialogAsync(this);
|
|
IsEnabled = true;
|
|
}
|
|
#endif
|
|
|
|
CheckStatusAndUpdate(true);
|
|
}
|
|
|
|
private void TextBoxMinecraftProfileFolder_TextChanged(object? o, TextChangedEventArgs args)
|
|
{
|
|
if (!loadingData)
|
|
CheckStatusAndUpdate(true);
|
|
}
|
|
|
|
private void TextBoxModpackConfig_TextChanged(object? o, RoutedEventArgs args)
|
|
{
|
|
if (!loadingData)
|
|
CheckStatusAndUpdate(false);
|
|
}
|
|
|
|
private void TextBoxInstallKey_TextChanged(object? o, RoutedEventArgs 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.AbsolutePath;
|
|
}
|
|
|
|
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
|
|
} |