mirror of
https://github.com/ZuneDev/ZuneModdingHelper.git
synced 2026-07-27 13:12:21 -07:00
281 lines
12 KiB
C#
281 lines
12 KiB
C#
using ControlzEx.Theming;
|
|
using Flurl.Http;
|
|
using MahApps.Metro.Controls;
|
|
using MahApps.Metro.Controls.Dialogs;
|
|
using Microsoft.AppCenter.Analytics;
|
|
using Microsoft.WindowsAPICodePack.Dialogs;
|
|
using Newtonsoft.Json.Linq;
|
|
using OwlCore.AbstractUI.Models;
|
|
using Syroot.Windows.IO;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Windows;
|
|
using System.Windows.Navigation;
|
|
using ZuneModCore;
|
|
|
|
namespace ZuneModdingHelper
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for MainWindow.xaml
|
|
/// </summary>
|
|
public partial class MainWindow : MetroWindow
|
|
{
|
|
private readonly MetroDialogSettings defaultMetroDialogSettings = new()
|
|
{
|
|
ColorScheme = MetroDialogColorScheme.Accented,
|
|
AnimateShow = true,
|
|
AnimateHide = true,
|
|
AffirmativeButtonText = "OK"
|
|
};
|
|
|
|
public MainWindow()
|
|
{
|
|
InitializeComponent();
|
|
|
|
ThemeManager.Current.ThemeSyncMode = ThemeSyncMode.SyncWithAppMode;
|
|
ThemeManager.Current.SyncTheme();
|
|
}
|
|
|
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
|
{
|
|
ModList.ItemsSource = Mod.AvailableMods;
|
|
ZuneInstallDirBox.Text = Mod.ZuneInstallDir;
|
|
}
|
|
|
|
private async void ModInstallButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var progDialog = await this.ShowProgressAsync("Getting ready...", "Preparing to apply mod", settings: defaultMetroDialogSettings);
|
|
Mod mod = (Mod)((FrameworkElement)sender).DataContext;
|
|
Mod.ZuneInstallDir = ZuneInstallDirBox.Text;
|
|
|
|
progDialog.Maximum = 3;
|
|
int numCompleted = 0;
|
|
|
|
// Stage 0: Initialize mod
|
|
progDialog.SetTitle($"Installing '{mod.Title}'");
|
|
progDialog.SetMessage("Preparing to install...");
|
|
await mod.Init();
|
|
progDialog.SetProgress(++numCompleted);
|
|
|
|
// Stage 1: Display AbstractUI for options
|
|
progDialog.SetMessage("Awaiting options...");
|
|
if (mod.OptionsUI != null)
|
|
{
|
|
var optionsDialog = new AbstractUIGroupDialog(mod.OptionsUI);
|
|
bool? optionsResult = optionsDialog.ShowDialog();
|
|
if (!(optionsResult.HasValue && optionsResult.Value))
|
|
{
|
|
await progDialog.CloseAsync();
|
|
return;
|
|
}
|
|
mod.OptionsUI = (AbstractUICollection)optionsDialog.ViewModel.Model;
|
|
}
|
|
progDialog.SetProgress(++numCompleted);
|
|
|
|
// Stage 2: Apply mod
|
|
progDialog.SetMessage("Applying mod...");
|
|
string applyResult = await mod.Apply();
|
|
if (applyResult != null)
|
|
{
|
|
Analytics.TrackEvent("Failed to apply mod", new Dictionary<string, string> {
|
|
{ "ModID", mod.Id },
|
|
{ "ErrorMessage", applyResult }
|
|
});
|
|
|
|
await progDialog.CloseAsync();
|
|
await this.ShowMessageAsync($"Failed to apply '{mod.Title}'", applyResult, settings: defaultMetroDialogSettings);
|
|
|
|
return;
|
|
}
|
|
progDialog.SetProgress(++numCompleted);
|
|
|
|
Analytics.TrackEvent("Applied mod", new Dictionary<string, string> {
|
|
{ "ModID", mod.Id },
|
|
});
|
|
|
|
await progDialog.CloseAsync();
|
|
await this.ShowMessageAsync("Completed", $"Installed '{mod.Title}'", settings: defaultMetroDialogSettings);
|
|
}
|
|
|
|
private async void ModResetButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (sender is FrameworkElement elem && elem.DataContext is Mod mod)
|
|
{
|
|
var progDialog = await this.ShowProgressAsync("Getting ready...", "Preparing to reset mod", settings: defaultMetroDialogSettings);
|
|
Mod.ZuneInstallDir = ZuneInstallDirBox.Text;
|
|
|
|
progDialog.Maximum = 2;
|
|
int numCompleted = 0;
|
|
|
|
progDialog.SetTitle("Resetting mod...");
|
|
progDialog.SetMessage($"Setting up '{mod.Title}'");
|
|
await mod.Init();
|
|
progDialog.SetProgress(++numCompleted);
|
|
|
|
// TODO: Implement AbstractUI display for options
|
|
//if (mod.OptionsUI != null)
|
|
//{
|
|
// var optionsDialog = new AbstractUIGroupDialog();
|
|
// optionsDialog.OptionsUIPresenter.ViewModel = new AbstractUICollectionViewModel(mod.OptionsUI);
|
|
// optionsDialog.ShowDialog();
|
|
//}
|
|
|
|
progDialog.SetMessage($"Resetting '{mod.Title}'");
|
|
string resetResult = await mod.Reset();
|
|
if (resetResult != null)
|
|
{
|
|
Analytics.TrackEvent("Failed to reset mod", new Dictionary<string, string> {
|
|
{ "ModID", mod.Id },
|
|
{ "ErrorMessage", resetResult }
|
|
});
|
|
|
|
await progDialog.CloseAsync();
|
|
await this.ShowMessageAsync("Completed", $"Failed to reset '{mod.Title}':\r\n{resetResult}", settings: defaultMetroDialogSettings);
|
|
return;
|
|
}
|
|
|
|
progDialog.SetProgress(++numCompleted);
|
|
|
|
Analytics.TrackEvent("Reset mod", new Dictionary<string, string> {
|
|
{ "ModID", mod.Id },
|
|
});
|
|
|
|
await progDialog.CloseAsync();
|
|
await this.ShowMessageAsync("Completed", $"Successfully reset '{mod.Title}'", settings: defaultMetroDialogSettings);
|
|
}
|
|
}
|
|
|
|
private void AboutButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
AboutFlyout.Width = Math.Max(Math.Min(500, ActualWidth), ActualWidth / 3);
|
|
AboutFlyout.IsOpen = true;
|
|
}
|
|
|
|
private void Link_RequestNavigate(object sender, RequestNavigateEventArgs e)
|
|
{
|
|
App.OpenInBrowser(e.Uri.AbsoluteUri);
|
|
e.Handled = true;
|
|
}
|
|
|
|
private async void UpdatesButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var checkDialog = await this.ShowProgressAsync("Checking for updates...", "Please wait.", settings: defaultMetroDialogSettings);
|
|
checkDialog.SetIndeterminate();
|
|
|
|
try
|
|
{
|
|
// Get releases list from GitHub
|
|
List<JObject> releases = await "https://api.github.com/repos/ZuneDev/ZuneModdingHelper/releases"
|
|
.WithHeader("User-Agent", App.Title.Replace(" ", "") + "/" + App.VersionStr)
|
|
.GetJsonAsync<List<JObject>>();
|
|
JObject latest = releases[0];
|
|
string latestVerStr = latest["tag_name"].Value<string>();
|
|
if (!ReleaseVersion.TryParse(latestVerStr, out var latestVer) || App.Version >= latestVer)
|
|
{
|
|
// Already up-to-date
|
|
|
|
Analytics.TrackEvent("Checked for updates", new Dictionary<string, string> {
|
|
{ "UpdatesFound", bool.FalseString },
|
|
});
|
|
|
|
await checkDialog.CloseAsync();
|
|
await this.ShowMessageAsync("No updates available", "You're already using the latest version.", settings: defaultMetroDialogSettings);
|
|
return;
|
|
}
|
|
|
|
// Newer version available, prompt user to download
|
|
MetroDialogSettings promptSettings = new()
|
|
{
|
|
ColorScheme = MetroDialogColorScheme.Accented,
|
|
AnimateShow = true,
|
|
AnimateHide = true,
|
|
AffirmativeButtonText = "Download",
|
|
NegativeButtonText = "Later"
|
|
};
|
|
await checkDialog.CloseAsync();
|
|
var promptResult = await this.ShowMessageAsync("Update available", $"Release {latest["name"]} is available. Would you like to download it now?",
|
|
MessageDialogStyle.AffirmativeAndNegative, promptSettings);
|
|
bool acceptedUpdate = promptResult == MessageDialogResult.Affirmative;
|
|
|
|
if (acceptedUpdate)
|
|
{
|
|
var progDialog = await this.ShowProgressAsync("Downloading update...", "This may take a few minutes.", settings: defaultMetroDialogSettings);
|
|
progDialog.Maximum = 100;
|
|
progDialog.SetIndeterminate();
|
|
|
|
// Download new version to AppData
|
|
JObject asset = latest["assets"].ToObject<List<JObject>>()[0];
|
|
string assetName = asset["name"].Value<string>();
|
|
string downloadedFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), assetName);
|
|
if (File.Exists(downloadedFile)) File.Delete(downloadedFile);
|
|
using (var client = new System.Net.WebClient())
|
|
{
|
|
client.DownloadProgressChanged += (object sender, System.Net.DownloadProgressChangedEventArgs e) => {
|
|
// Update UI with download progress
|
|
progDialog.SetProgress(e.ProgressPercentage);
|
|
};
|
|
|
|
progDialog.SetProgress(0);
|
|
await client.DownloadFileTaskAsync(new Uri(asset["browser_download_url"].Value<string>()), downloadedFile);
|
|
}
|
|
|
|
// Ask user to save file
|
|
Microsoft.Win32.SaveFileDialog saveFileDialog = new()
|
|
{
|
|
FileName = assetName,
|
|
InitialDirectory = new KnownFolder(KnownFolderType.Downloads).Path
|
|
};
|
|
bool dialogResult = saveFileDialog.ShowDialog() ?? false;
|
|
await progDialog.CloseAsync();
|
|
if (dialogResult)
|
|
{
|
|
File.Copy(downloadedFile, saveFileDialog.FileName, true);
|
|
await this.ShowMessageAsync("Update complete", "You may now exit this program and open the new version.", settings: defaultMetroDialogSettings);
|
|
}
|
|
}
|
|
|
|
Analytics.TrackEvent("Checked for updates", new Dictionary<string, string> {
|
|
{ "UpdatesFound", bool.TrueString },
|
|
{ "Accepted", acceptedUpdate.ToString() },
|
|
});
|
|
}
|
|
catch
|
|
{
|
|
App.OpenInBrowser("https://github.com/ZuneDev/ZuneModdingHelper/releases");
|
|
}
|
|
finally
|
|
{
|
|
if (checkDialog.IsOpen)
|
|
await checkDialog.CloseAsync();
|
|
}
|
|
}
|
|
|
|
private void DonateButton_Click(object sender, RoutedEventArgs e) => App.OpenInBrowser(App.DonateLink);
|
|
|
|
private void LocateZuneButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (CommonFileDialog.IsPlatformSupported)
|
|
{
|
|
CommonOpenFileDialog dialog = new()
|
|
{
|
|
IsFolderPicker = true,
|
|
DefaultDirectory = Mod.ZuneInstallDir
|
|
};
|
|
CommonFileDialogResult result = dialog.ShowDialog();
|
|
if (result == CommonFileDialogResult.Ok)
|
|
{
|
|
ZuneInstallDirBox.Text = dialog.FileName;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: Fallback to pre-Vista dialog
|
|
this.ShowMessageAsync("Error",
|
|
"Please use File Explorer to locate and copy the path.",
|
|
settings: defaultMetroDialogSettings);
|
|
}
|
|
}
|
|
}
|
|
}
|