VRCMelonAssistant/ModAssistant/Pages/Mods.xaml.cs

800 lines
29 KiB
C#
Raw Normal View History

using System;
2019-04-22 18:41:43 +12:00
using System.Collections.Generic;
2020-02-05 17:58:35 +13:00
using System.Diagnostics;
2019-04-22 18:41:43 +12:00
using System.IO;
2020-02-05 17:58:35 +13:00
using System.IO.Compression;
using System.Threading;
2019-04-22 18:41:43 +12:00
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Forms;
2020-11-17 02:22:30 +13:00
using System.Windows.Media.Animation;
2020-02-05 17:58:35 +13:00
using System.Windows.Navigation;
2020-04-22 12:46:28 +12:00
using ModAssistant.Libs;
2020-11-17 02:22:30 +13:00
using static ModAssistant.Http;
2020-05-16 23:31:38 +12:00
using TextBox = System.Windows.Controls.TextBox;
2019-04-22 18:41:43 +12:00
namespace ModAssistant.Pages
{
/// <summary>
/// Interaction logic for Mods.xaml
/// </summary>
public sealed partial class Mods : Page
{
public static Mods Instance = new Mods();
2020-02-03 00:04:30 +13:00
public List<string> DefaultMods = new List<string>() { "SongCore", "ScoreSaber", "BeatSaverDownloader", "BeatSaverVoting", "PlaylistCore", "Survey" };
2019-04-22 18:41:43 +12:00
public Mod[] ModsList;
2019-05-13 06:37:29 +12:00
public Mod[] AllModsList;
2019-04-22 18:41:43 +12:00
public static List<Mod> InstalledMods = new List<Mod>();
public List<string> CategoryNames = new List<string>();
public CollectionView view;
2019-05-19 03:32:14 +12:00
public bool PendingChanges;
2019-04-22 18:41:43 +12:00
2020-02-03 15:41:09 +13:00
private readonly SemaphoreSlim _modsLoadSem = new SemaphoreSlim(1, 1);
2019-04-22 18:41:43 +12:00
public List<ModListItem> ModList { get; set; }
public Mods()
{
InitializeComponent();
}
private void RefreshModsList()
{
2019-05-19 03:32:14 +12:00
if (view != null)
2020-02-03 15:41:09 +13:00
{
2019-05-19 03:32:14 +12:00
view.Refresh();
2020-02-03 15:41:09 +13:00
}
2019-04-22 18:41:43 +12:00
}
public void RefreshColumns()
{
2020-11-17 03:02:28 +13:00
if (MainWindow.Instance.Main.Content != Instance) return;
double viewWidth = ModsListView.ActualWidth;
double totalSize = 0;
GridViewColumn description = null;
2020-11-17 03:10:11 +13:00
if (ModsListView.View is GridView grid)
{
foreach (var column in grid.Columns)
{
2020-02-28 15:52:20 +13:00
if (column.Header?.ToString() == FindResource("Mods:Header:Description").ToString())
{
description = column;
}
else
{
totalSize += column.ActualWidth;
}
if (double.IsNaN(column.Width))
{
column.Width = column.ActualWidth;
column.Width = double.NaN;
}
}
double descriptionNewWidth = viewWidth - totalSize - 35;
description.Width = descriptionNewWidth > 200 ? descriptionNewWidth : 200;
}
}
public async Task LoadMods()
2019-04-22 18:41:43 +12:00
{
var versionLoadSuccess = await MainWindow.Instance.VersionLoadStatus.Task;
if (versionLoadSuccess == false) return;
2019-05-19 03:32:14 +12:00
await _modsLoadSem.WaitAsync();
2019-05-19 03:32:14 +12:00
try
{
MainWindow.Instance.InstallButton.IsEnabled = false;
MainWindow.Instance.GameVersionsBox.IsEnabled = false;
MainWindow.Instance.InfoButton.IsEnabled = false;
2019-05-19 03:32:14 +12:00
if (ModsList != null)
{
Array.Clear(ModsList, 0, ModsList.Length);
}
2019-05-19 03:32:14 +12:00
if (AllModsList != null)
{
Array.Clear(AllModsList, 0, AllModsList.Length);
}
InstalledMods = new List<Mod>();
CategoryNames = new List<string>();
ModList = new List<ModListItem>();
2019-04-22 18:41:43 +12:00
ModsListView.Visibility = Visibility.Hidden;
if (App.CheckInstalledMods)
{
MainWindow.Instance.MainText = $"{FindResource("Mods:CheckingInstalledMods")}...";
await Task.Run(async () => await CheckInstalledMods());
InstalledColumn.Width = double.NaN;
UninstallColumn.Width = 70;
DescriptionColumn.Width = 750;
}
else
{
InstalledColumn.Width = 0;
UninstallColumn.Width = 0;
DescriptionColumn.Width = 800;
}
2019-04-22 18:41:43 +12:00
MainWindow.Instance.MainText = $"{FindResource("Mods:LoadingMods")}...";
await Task.Run(async () => await PopulateModsList());
2019-04-22 18:41:43 +12:00
ModsListView.ItemsSource = ModList;
2019-04-22 18:41:43 +12:00
view = (CollectionView)CollectionViewSource.GetDefaultView(ModsListView.ItemsSource);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Category");
view.GroupDescriptions.Add(groupDescription);
2019-04-22 18:41:43 +12:00
this.DataContext = this;
2019-05-19 03:32:14 +12:00
RefreshModsList();
2020-10-20 02:01:57 +13:00
ModsListView.Visibility = ModList.Count == 0 ? Visibility.Hidden : Visibility.Visible;
NoModsGrid.Visibility = ModList.Count == 0 ? Visibility.Visible : Visibility.Hidden;
2020-10-20 02:01:57 +13:00
MainWindow.Instance.MainText = $"{FindResource("Mods:FinishedLoadingMods")}.";
MainWindow.Instance.InstallButton.IsEnabled = ModList.Count != 0;
MainWindow.Instance.GameVersionsBox.IsEnabled = true;
}
finally
{
_modsLoadSem.Release();
}
2019-04-22 18:41:43 +12:00
}
public async Task CheckInstalledMods()
{
await GetAllMods();
2020-11-17 03:09:03 +13:00
GetBSIPAVersion();
2020-11-17 03:09:03 +13:00
CheckInstallDir("IPA/Pending/Plugins");
CheckInstallDir("IPA/Pending/Libs");
CheckInstallDir("Plugins");
CheckInstallDir("Libs");
}
public async Task GetAllMods()
2019-04-22 18:41:43 +12:00
{
var resp = await HttpClient.GetAsync(Utils.Constants.BeatModsAPIUrl + "mod");
var body = await resp.Content.ReadAsStringAsync();
AllModsList = JsonSerializer.Deserialize<Mod[]>(body);
2019-04-22 18:41:43 +12:00
}
2020-11-17 03:09:03 +13:00
private void CheckInstallDir(string directory)
2019-04-22 18:41:43 +12:00
{
if (!Directory.Exists(Path.Combine(App.BeatSaberInstallDirectory, directory)))
{
return;
2020-02-02 21:38:29 +13:00
}
2019-05-26 20:53:25 +12:00
foreach (string file in Directory.GetFileSystemEntries(Path.Combine(App.BeatSaberInstallDirectory, directory)))
2019-04-22 18:41:43 +12:00
{
2019-05-26 20:53:25 +12:00
if (File.Exists(file) && Path.GetExtension(file) == ".dll" || Path.GetExtension(file) == ".manifest")
2019-04-22 18:41:43 +12:00
{
Mod mod = GetModFromHash(Utils.CalculateMD5(file));
if (mod != null)
{
2019-05-26 20:53:25 +12:00
AddDetectedMod(mod);
}
}
}
}
public void GetBSIPAVersion()
2019-05-26 20:53:25 +12:00
{
string InjectorPath = Path.Combine(App.BeatSaberInstallDirectory, "Beat Saber_Data", "Managed", "IPA.Injector.dll");
if (!File.Exists(InjectorPath)) return;
string InjectorHash = Utils.CalculateMD5(InjectorPath);
foreach (Mod mod in AllModsList)
{
if (mod.name.ToLower() == "bsipa")
{
foreach (Mod.DownloadLink download in mod.downloads)
{
foreach (Mod.FileHashes fileHash in download.hashMd5)
2019-04-22 18:41:43 +12:00
{
2019-05-26 20:53:25 +12:00
if (fileHash.hash == InjectorHash)
{
2019-05-26 20:53:25 +12:00
AddDetectedMod(mod);
}
2019-04-22 18:41:43 +12:00
}
}
}
}
}
2019-05-26 20:53:25 +12:00
private void AddDetectedMod(Mod mod)
2019-04-22 18:41:43 +12:00
{
2019-05-26 20:53:25 +12:00
if (!InstalledMods.Contains(mod))
{
InstalledMods.Add(mod);
if (App.SelectInstalledMods && !DefaultMods.Contains(mod.name))
{
DefaultMods.Add(mod.name);
}
}
}
2019-04-22 18:41:43 +12:00
2019-05-26 20:53:25 +12:00
private Mod GetModFromHash(string hash)
{
2019-05-13 06:37:29 +12:00
foreach (Mod mod in AllModsList)
2019-04-22 18:41:43 +12:00
{
2020-04-22 10:42:03 +12:00
if (mod.name.ToLower() != "bsipa" && mod.status != "declined")
2019-05-13 06:37:29 +12:00
{
2019-05-26 20:53:25 +12:00
foreach (Mod.DownloadLink download in mod.downloads)
2019-05-13 06:37:29 +12:00
{
2019-05-26 20:53:25 +12:00
foreach (Mod.FileHashes fileHash in download.hashMd5)
{
if (fileHash.hash == hash)
return mod;
}
2019-05-13 06:37:29 +12:00
}
}
2019-04-22 18:41:43 +12:00
}
2019-05-13 06:37:29 +12:00
return null;
2019-04-22 18:41:43 +12:00
}
public async Task PopulateModsList()
2019-04-22 18:41:43 +12:00
{
2019-05-19 03:50:22 +12:00
try
2019-04-22 18:41:43 +12:00
{
var resp = await HttpClient.GetAsync(Utils.Constants.BeatModsAPIUrl + Utils.Constants.BeatModsModsOptions + "&gameVersion=" + MainWindow.GameVersion);
var body = await resp.Content.ReadAsStringAsync();
ModsList = JsonSerializer.Deserialize<Mod[]>(body);
2019-05-19 03:50:22 +12:00
}
catch (Exception e)
{
2020-02-02 17:31:45 +13:00
System.Windows.MessageBox.Show($"{FindResource("Mods:LoadFailed")}.\n\n" + e);
2019-05-19 03:50:22 +12:00
return;
2019-04-22 18:41:43 +12:00
}
foreach (Mod mod in ModsList)
{
bool preSelected = mod.required;
if (DefaultMods.Contains(mod.name) || (App.SaveModSelection && App.SavedMods.Contains(mod.name)))
{
preSelected = true;
2020-02-03 00:04:30 +13:00
if (!App.SavedMods.Contains(mod.name))
2019-04-22 18:41:43 +12:00
{
App.SavedMods.Add(mod.name);
}
}
RegisterDependencies(mod);
ModListItem ListItem = new ModListItem()
{
IsSelected = preSelected,
IsEnabled = !mod.required,
ModName = mod.name,
ModVersion = mod.version,
ModDescription = mod.description.Replace("\r\n", " ").Replace("\n", " "),
2019-04-22 18:41:43 +12:00
ModInfo = mod,
Category = mod.category
};
2019-06-19 08:59:16 +12:00
foreach (Promotion promo in Promotions.ActivePromotions)
{
if (mod.name == promo.ModName)
{
ListItem.PromotionText = promo.Text;
ListItem.PromotionLink = promo.Link;
}
}
2019-04-22 18:41:43 +12:00
foreach (Mod installedMod in InstalledMods)
{
if (mod.name == installedMod.name)
{
ListItem.InstalledModInfo = installedMod;
2019-04-22 18:41:43 +12:00
ListItem.IsInstalled = true;
ListItem.InstalledVersion = installedMod.version;
break;
}
}
mod.ListItem = ListItem;
ModList.Add(ListItem);
}
foreach (Mod mod in ModsList)
{
ResolveDependencies(mod);
}
}
2020-05-10 09:40:22 +12:00
public async void InstallMods()
2019-04-22 18:41:43 +12:00
{
MainWindow.Instance.InstallButton.IsEnabled = false;
string installDirectory = App.BeatSaberInstallDirectory;
foreach (Mod mod in ModsList)
{
// Ignore mods that are newer than installed version
2020-05-09 18:23:04 +12:00
if (mod.ListItem.GetVersionComparison > 0) continue;
// Ignore mods that are on current version if we aren't reinstalling mods
2020-05-10 09:40:22 +12:00
if (mod.ListItem.GetVersionComparison == 0 && !App.ReinstallInstalledMods) continue;
2020-05-02 14:45:59 +12:00
2019-04-22 18:41:43 +12:00
if (mod.name.ToLower() == "bsipa")
{
2020-02-02 17:31:45 +13:00
MainWindow.Instance.MainText = $"{string.Format((string)FindResource("Mods:InstallingMod"), mod.name)}...";
await Task.Run(async () => await InstallMod(mod, installDirectory));
2020-02-02 17:31:45 +13:00
MainWindow.Instance.MainText = $"{string.Format((string)FindResource("Mods:InstalledMod"), mod.name)}.";
2019-05-26 20:53:25 +12:00
if (!File.Exists(Path.Combine(installDirectory, "winhttp.dll")))
2019-05-22 13:12:34 +12:00
{
await Task.Run(() =>
Process.Start(new ProcessStartInfo
{
2019-05-26 20:53:25 +12:00
FileName = Path.Combine(installDirectory, "IPA.exe"),
2019-05-22 13:12:34 +12:00
WorkingDirectory = installDirectory,
Arguments = "-n"
}).WaitForExit()
);
}
2020-11-17 03:02:28 +13:00
Options.Instance.YeetBSIPA.IsEnabled = true;
2019-04-22 18:41:43 +12:00
}
2020-02-03 00:04:30 +13:00
else if (mod.ListItem.IsSelected)
2019-04-22 18:41:43 +12:00
{
2020-02-02 17:31:45 +13:00
MainWindow.Instance.MainText = $"{string.Format((string)FindResource("Mods:InstallingMod"), mod.name)}...";
2020-05-02 14:45:59 +12:00
await Task.Run(async () => await InstallMod(mod, Path.Combine(installDirectory, @"IPA\Pending")));
MainWindow.Instance.MainText = $"{string.Format((string)FindResource("Mods:InstalledMod"), mod.name)}.";
2019-04-22 18:41:43 +12:00
}
}
MainWindow.Instance.MainText = $"{FindResource("Mods:FinishedInstallingMods")}.";
2019-04-22 18:41:43 +12:00
MainWindow.Instance.InstallButton.IsEnabled = true;
2019-05-13 07:06:26 +12:00
RefreshModsList();
2019-04-22 18:41:43 +12:00
}
private async Task InstallMod(Mod mod, string directory)
2019-04-22 18:41:43 +12:00
{
string downloadLink = null;
foreach (Mod.DownloadLink link in mod.downloads)
{
if (link.type == "universal")
{
downloadLink = link.url;
break;
}
else if (link.type.ToLower() == App.BeatSaberInstallType.ToLower())
2019-04-22 18:41:43 +12:00
{
downloadLink = link.url;
break;
}
}
2020-02-02 21:42:15 +13:00
if (string.IsNullOrEmpty(downloadLink))
2019-04-22 18:41:43 +12:00
{
2020-02-02 17:31:45 +13:00
System.Windows.MessageBox.Show(string.Format((string)FindResource("Mods:ModDownloadLinkMissing"), mod.name));
2019-04-22 18:41:43 +12:00
return;
}
using (Stream stream = await DownloadMod(Utils.Constants.BeatModsURL + downloadLink))
using (ZipArchive archive = new ZipArchive(stream))
2019-04-22 18:41:43 +12:00
{
foreach (ZipArchiveEntry file in archive.Entries)
2019-04-22 18:41:43 +12:00
{
string fileDirectory = Path.GetDirectoryName(Path.Combine(directory, file.FullName));
if (!Directory.Exists(fileDirectory))
2019-04-22 18:41:43 +12:00
{
Directory.CreateDirectory(fileDirectory);
}
2019-04-22 18:41:43 +12:00
if (!string.IsNullOrEmpty(file.Name))
{
await ExtractFile(file, Path.Combine(directory, file.FullName), 3.0, mod.name, 10);
2019-04-22 18:41:43 +12:00
}
}
}
2019-05-13 07:06:26 +12:00
if (App.CheckInstalledMods)
{
mod.ListItem.IsInstalled = true;
mod.ListItem.InstalledVersion = mod.version;
2019-05-26 20:53:25 +12:00
mod.ListItem.InstalledModInfo = mod;
2019-05-13 07:06:26 +12:00
}
2019-04-22 18:41:43 +12:00
}
private async Task ExtractFile(ZipArchiveEntry file, string path, double seconds, string name, int maxTries, int tryNumber = 0)
{
if (tryNumber < maxTries)
{
try
{
file.ExtractToFile(path, true);
}
catch
{
MainWindow.Instance.MainText = $"{string.Format((string)FindResource("Mods:FailedExtract"), name, seconds, tryNumber + 1, maxTries)}";
await Task.Delay((int)(seconds * 1000));
await ExtractFile(file, path, seconds, name, maxTries, tryNumber + 1);
}
}
else
{
System.Windows.MessageBox.Show($"{string.Format((string)FindResource("Mods:FailedExtractMaxReached"), name, maxTries)}.", "Failed to install " + name);
}
}
private async Task<Stream> DownloadMod(string link)
2019-04-22 18:41:43 +12:00
{
var resp = await HttpClient.GetAsync(link);
return await resp.Content.ReadAsStreamAsync();
2019-04-22 18:41:43 +12:00
}
private void RegisterDependencies(Mod dependent)
{
if (dependent.dependencies.Length == 0)
return;
foreach (Mod mod in ModsList)
{
foreach (Mod.Dependency dep in dependent.dependencies)
{
2020-02-02 21:38:29 +13:00
2019-04-22 18:41:43 +12:00
if (dep.name == mod.name)
{
dep.Mod = mod;
mod.Dependents.Add(dependent);
2020-02-02 21:38:29 +13:00
2019-04-22 18:41:43 +12:00
}
}
}
}
private void ResolveDependencies(Mod dependent)
{
if (dependent.ListItem.IsSelected && dependent.dependencies.Length > 0)
{
foreach (Mod.Dependency dependency in dependent.dependencies)
{
if (dependency.Mod.ListItem.IsEnabled)
{
dependency.Mod.ListItem.PreviousState = dependency.Mod.ListItem.IsSelected;
dependency.Mod.ListItem.IsSelected = true;
dependency.Mod.ListItem.IsEnabled = false;
ResolveDependencies(dependency.Mod);
}
}
}
}
private void UnresolveDependencies(Mod dependent)
{
if (!dependent.ListItem.IsSelected && dependent.dependencies.Length > 0)
{
foreach (Mod.Dependency dependency in dependent.dependencies)
{
if (!dependency.Mod.ListItem.IsEnabled)
{
bool needed = false;
foreach (Mod dep in dependency.Mod.Dependents)
{
if (dep.ListItem.IsSelected)
{
needed = true;
break;
}
}
if (!needed && !dependency.Mod.required)
{
dependency.Mod.ListItem.IsSelected = dependency.Mod.ListItem.PreviousState;
dependency.Mod.ListItem.IsEnabled = true;
UnresolveDependencies(dependency.Mod);
}
}
}
}
}
private void ModCheckBox_Checked(object sender, RoutedEventArgs e)
{
Mod mod = ((sender as System.Windows.Controls.CheckBox).Tag as Mod);
mod.ListItem.IsSelected = true;
ResolveDependencies(mod);
App.SavedMods.Add(mod.name);
2020-02-02 21:42:15 +13:00
Properties.Settings.Default.SavedMods = string.Join(",", App.SavedMods.ToArray());
2019-04-22 18:41:43 +12:00
Properties.Settings.Default.Save();
RefreshModsList();
}
private void ModCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
Mod mod = ((sender as System.Windows.Controls.CheckBox).Tag as Mod);
mod.ListItem.IsSelected = false;
UnresolveDependencies(mod);
App.SavedMods.Remove(mod.name);
2020-02-02 21:42:15 +13:00
Properties.Settings.Default.SavedMods = string.Join(",", App.SavedMods.ToArray());
2019-04-22 18:41:43 +12:00
Properties.Settings.Default.Save();
RefreshModsList();
}
public class Category
{
public string CategoryName { get; set; }
public List<ModListItem> Mods = new List<ModListItem>();
}
public class ModListItem
{
public string ModName { get; set; }
public string ModVersion { get; set; }
public string ModDescription { get; set; }
public bool PreviousState { get; set; }
public bool IsEnabled { get; set; }
public bool IsSelected { get; set; }
public Mod ModInfo { get; set; }
public string Category { get; set; }
public Mod InstalledModInfo { get; set; }
2019-04-22 18:41:43 +12:00
public bool IsInstalled { get; set; }
2020-04-22 12:46:28 +12:00
private SemVersion _installedVersion { get; set; }
2019-05-16 08:51:09 +12:00
public string InstalledVersion
{
2019-04-22 18:41:43 +12:00
get
{
2020-05-04 20:40:01 +12:00
if (!IsInstalled || _installedVersion == null) return "-";
return _installedVersion.ToString();
2019-04-22 18:41:43 +12:00
}
set
{
2020-05-04 20:40:01 +12:00
if (SemVersion.TryParse(value, out SemVersion tempInstalledVersion))
2020-05-02 14:38:33 +12:00
{
2020-05-04 20:40:01 +12:00
_installedVersion = tempInstalledVersion;
2020-11-17 03:19:59 +13:00
}
else
2020-05-02 14:38:33 +12:00
{
_installedVersion = null;
}
2019-04-22 18:41:43 +12:00
}
}
2019-05-16 08:51:09 +12:00
public string GetVersionColor
{
2019-04-22 18:41:43 +12:00
get
{
2019-05-16 08:51:09 +12:00
if (!IsInstalled) return "Black";
2020-04-22 12:46:28 +12:00
return _installedVersion >= ModVersion ? "Green" : "Red";
2019-04-22 18:41:43 +12:00
}
}
2019-12-19 16:40:06 +13:00
public string GetVersionDecoration
{
get
{
if (!IsInstalled) return "None";
2020-04-22 12:46:28 +12:00
return _installedVersion >= ModVersion ? "None" : "Strikethrough";
2019-12-19 16:40:06 +13:00
}
}
2020-05-09 18:23:04 +12:00
public int GetVersionComparison
{
get
{
2020-05-09 18:23:04 +12:00
if (!IsInstalled || _installedVersion < ModVersion) return -1;
if (_installedVersion > ModVersion) return 1;
return 0;
}
}
2019-04-22 18:41:43 +12:00
public bool CanDelete
{
get
{
return (!ModInfo.required && IsInstalled);
}
}
public string CanSeeDelete
{
get
{
if (!ModInfo.required && IsInstalled)
return "Visible";
else
return "Hidden";
}
}
2019-06-19 08:59:16 +12:00
public string PromotionText { get; set; }
public string PromotionLink { get; set; }
public string PromotionMargin
{
get
{
2020-02-02 21:42:15 +13:00
if (string.IsNullOrEmpty(PromotionText)) return "0";
2019-06-19 08:59:16 +12:00
return "0,0,5,0";
}
}
2019-04-22 18:41:43 +12:00
}
private void ModsListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
2020-11-17 03:02:28 +13:00
if ((Mods.ModListItem)Instance.ModsListView.SelectedItem == null)
{
MainWindow.Instance.InfoButton.IsEnabled = false;
}
else
{
MainWindow.Instance.InfoButton.IsEnabled = true;
}
2019-04-22 18:41:43 +12:00
}
public void UninstallBSIPA(Mod.DownloadLink links)
2019-05-26 20:53:25 +12:00
{
Process.Start(new ProcessStartInfo
{
FileName = Path.Combine(App.BeatSaberInstallDirectory, "IPA.exe"),
WorkingDirectory = App.BeatSaberInstallDirectory,
Arguments = "--revert -n"
2019-05-26 20:53:25 +12:00
}).WaitForExit();
foreach (Mod.FileHashes files in links.hashMd5)
{
string file = files.file.Replace("IPA/", "").Replace("Data", "Beat Saber_Data");
if (File.Exists(Path.Combine(App.BeatSaberInstallDirectory, file)))
File.Delete(Path.Combine(App.BeatSaberInstallDirectory, file));
}
2020-11-17 03:02:28 +13:00
Options.Instance.YeetBSIPA.IsEnabled = false;
2019-05-26 20:53:25 +12:00
}
2019-04-22 18:41:43 +12:00
private void Uninstall_Click(object sender, RoutedEventArgs e)
{
Mod mod = ((sender as System.Windows.Controls.Button).Tag as Mod);
2020-02-02 17:31:45 +13:00
string title = string.Format((string)FindResource("Mods:UninstallBox:Title"), mod.name);
string body1 = string.Format((string)FindResource("Mods:UninstallBox:Body1"), mod.name);
string body2 = string.Format((string)FindResource("Mods:UninstallBox:Body2"), mod.name);
var result = System.Windows.Forms.MessageBox.Show($"{body1}\n{body2}", title, MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
2019-04-22 18:41:43 +12:00
{
UninstallModFromList(mod);
}
}
2019-05-26 20:53:25 +12:00
private void UninstallModFromList(Mod mod)
{
UninstallMod(mod.ListItem.InstalledModInfo);
mod.ListItem.IsInstalled = false;
mod.ListItem.InstalledVersion = null;
if (App.SelectInstalledMods)
{
mod.ListItem.IsSelected = false;
UnresolveDependencies(mod);
App.SavedMods.Remove(mod.name);
2020-02-02 21:42:15 +13:00
Properties.Settings.Default.SavedMods = string.Join(",", App.SavedMods.ToArray());
Properties.Settings.Default.Save();
RefreshModsList();
}
view.Refresh();
}
public void UninstallMod(Mod mod)
{
Mod.DownloadLink links = null;
foreach (Mod.DownloadLink link in mod.downloads)
{
if (link.type.ToLower() == "universal" || link.type.ToLower() == App.BeatSaberInstallType.ToLower())
{
links = link;
break;
}
2019-04-22 18:41:43 +12:00
}
2020-11-17 03:19:59 +13:00
if (mod.name.ToLower() == "bsipa")
{
2020-11-06 05:25:56 +13:00
var hasIPAExe = File.Exists(Path.Combine(App.BeatSaberInstallDirectory, "IPA.exe"));
var hasIPADir = Directory.Exists(Path.Combine(App.BeatSaberInstallDirectory, "IPA"));
2020-11-17 03:19:59 +13:00
if (hasIPADir && hasIPAExe)
{
UninstallBSIPA(links);
}
else
{
2020-11-06 05:31:24 +13:00
var title = (string)FindResource("Mods:UninstallBSIPANotFound:Title");
var body = (string)FindResource("Mods:UninstallBSIPANotFound:Body");
2020-11-17 03:19:59 +13:00
System.Windows.Forms.MessageBox.Show(body, title, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
foreach (Mod.FileHashes files in links.hashMd5)
{
if (File.Exists(Path.Combine(App.BeatSaberInstallDirectory, files.file)))
File.Delete(Path.Combine(App.BeatSaberInstallDirectory, files.file));
if (File.Exists(Path.Combine(App.BeatSaberInstallDirectory, "IPA", "Pending", files.file)))
File.Delete(Path.Combine(App.BeatSaberInstallDirectory, "IPA", "Pending", files.file));
}
2019-04-22 18:41:43 +12:00
}
2019-06-19 08:59:16 +12:00
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
RefreshColumns();
}
2020-04-10 03:48:51 +12:00
private void CopyText(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
2020-11-17 03:19:59 +13:00
if (!(sender is TextBlock textBlock)) return;
var text = textBlock.Text;
// Ensure there's text to be copied
2020-11-17 03:19:59 +13:00
if (string.IsNullOrWhiteSpace(text)) return;
Utils.SetClipboard(text);
2020-04-10 03:48:51 +12:00
}
2020-05-16 23:31:38 +12:00
private void SearchButton_Click(object sender, RoutedEventArgs e)
{
if (SearchBar.Height == 0)
{
SearchBar.Focus();
Animate(SearchBar, 0, 16, new TimeSpan(0, 0, 0, 0, 300));
Animate(SearchText, 0, 16, new TimeSpan(0, 0, 0, 0, 300));
ModsListView.Items.Filter = new Predicate<object>(SearchFilter);
}
else
{
Animate(SearchBar, 16, 0, new TimeSpan(0, 0, 0, 0, 300));
Animate(SearchText, 16, 0, new TimeSpan(0, 0, 0, 0, 300));
ModsListView.Items.Filter = null;
}
}
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
ModsListView.Items.Filter = new Predicate<object>(SearchFilter);
if (SearchBar.Text.Length > 0)
{
SearchText.Text = null;
}
else
{
2020-05-17 09:56:41 +12:00
SearchText.Text = (string)FindResource("Mods:SearchLabel");
2020-05-16 23:31:38 +12:00
}
}
private bool SearchFilter(object mod)
{
ModListItem item = mod as ModListItem;
if (item.ModName.ToLower().Contains(SearchBar.Text.ToLower())) return true;
if (item.ModDescription.ToLower().Contains(SearchBar.Text.ToLower())) return true;
if (item.ModName.ToLower().Replace(" ", string.Empty).Contains(SearchBar.Text.ToLower().Replace(" ", string.Empty))) return true;
if (item.ModDescription.ToLower().Replace(" ", string.Empty).Contains(SearchBar.Text.ToLower().Replace(" ", string.Empty))) return true;
return false;
}
private void Animate(TextBlock target, double oldHeight, double newHeight, TimeSpan duration)
{
target.Height = oldHeight;
DoubleAnimation animation = new DoubleAnimation(newHeight, duration);
2020-11-17 03:02:28 +13:00
target.BeginAnimation(HeightProperty, animation);
2020-05-16 23:31:38 +12:00
}
private void Animate(TextBox target, double oldHeight, double newHeight, TimeSpan duration)
{
target.Height = oldHeight;
DoubleAnimation animation = new DoubleAnimation(newHeight, duration);
2020-11-17 03:02:28 +13:00
target.BeginAnimation(HeightProperty, animation);
2020-05-16 23:31:38 +12:00
}
2019-04-22 18:41:43 +12:00
}
2020-02-02 21:38:29 +13:00
}