using CustomUI.BeatSaber; using CustomUI.Utilities; using IPA.Loader; using IPA.Loader.Features; using IPA.Old; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; namespace BSIPA_ModList.UI.ViewControllers { internal interface IClickableCell { void OnSelect(ModListController cntrl); void Update(); } internal class BSIPAModCell : CustomCellInfo, IClickableCell, IDisposable { internal PluginLoader.PluginMetadata Plugin; private ModListController list; private PluginManager.PluginEnableDelegate enableDel; private PluginManager.PluginDisableDelegate disableDel; public BSIPAModCell(ModListController list, PluginLoader.PluginMetadata plugin) : base("", "", null) { Plugin = plugin; this.list = list; var thisWeakRef = new WeakReference(this); PluginManager.PluginDisableDelegate reflessDDel = null; reflessDDel = disableDel = (p, r) => PluginManager_PluginDisabled(p, r, thisWeakRef, reflessDDel); // some indirection to make it a weak link for GC PluginManager.PluginDisabled += reflessDDel; PluginManager.PluginEnableDelegate reflessEDel = null; reflessEDel = enableDel = (p, r) => PluginManager_PluginEnabled(p, r, thisWeakRef, reflessEDel); // some indirection to make it a weak link for GC PluginManager.PluginEnabled += reflessEDel; Update(propogate: false); } private static void PluginManager_PluginEnabled(PluginLoader.PluginInfo plugin, bool needsRestart, WeakReference _self, PluginManager.PluginEnableDelegate ownDel) { if (!_self.TryGetTarget(out var self)) { PluginManager.PluginEnabled -= ownDel; return; } if (plugin.Metadata != self.Plugin) return; self.Update(true, needsRestart); } private static void PluginManager_PluginDisabled(PluginLoader.PluginMetadata plugin, bool needsRestart, WeakReference _self, PluginManager.PluginDisableDelegate ownDel) { if (!_self.TryGetTarget(out var self)) { PluginManager.PluginDisabled -= ownDel; return; } if (plugin != self.Plugin) return; self.Update(false, needsRestart); } private ModInfoViewController infoView; public void OnSelect(ModListController cntrl) { Logger.log.Debug($"Selected BSIPAModCell {Plugin.Name} {Plugin.Version}"); if (infoView == null) { var desc = Plugin.Manifest.Description; if (string.IsNullOrWhiteSpace(desc)) desc = "*No description*"; infoView = BeatSaberUI.CreateViewController(); infoView.Init(icon, Plugin.Name, "v" + Plugin.Version.ToString(), subtext, desc, Plugin, Plugin.Manifest.Links, true, list.flow); } list.flow.SetSelected(infoView, immediate: list.flow.HasSelected); } void IClickableCell.Update() => Update(null, false, false); public void Update(bool? _enabled = null, bool needsRestart = false, bool propogate = true) { text = $"{Plugin.Name} v{Plugin.Version}"; subtext = Plugin.Manifest.Author; if (string.IsNullOrWhiteSpace(subtext)) subtext = "Unspecified Author"; var enabled = _enabled ?? !PluginManager.IsDisabled(Plugin); if (!enabled) subtext += " - Disabled"; if (needsRestart) subtext += " (Restart to apply)"; icon = Plugin.GetIcon(); var desc = Plugin.Manifest.Description; if (string.IsNullOrWhiteSpace(desc)) desc = "*No description*"; infoView?.Reload(Plugin.Name, "v" + Plugin.Version.ToString(), subtext, desc); if (propogate) list.Reload(); } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { PluginManager.PluginDisabled -= disableDel; PluginManager.PluginEnabled -= enableDel; } disposedValue = true; } } public void Dispose() { Dispose(true); } #endregion } internal class BSIPAIgnoredModCell : CustomCellInfo, IClickableCell { internal PluginLoader.PluginMetadata Plugin; private ModListController list; private const string authorFormat = "{0} - Not loaded"; private string authorText; public BSIPAIgnoredModCell(ModListController list, PluginLoader.PluginMetadata plugin) : base($"{plugin.Name} v{plugin.Version}", "", Utilities.DefaultBSIPAIcon) { Plugin = plugin; this.list = list; if (string.IsNullOrWhiteSpace(plugin.Manifest.Author)) authorText = "Unspecified Author"; else authorText = plugin.Manifest.Author; subtext = string.Format(authorFormat, authorText); } private ModInfoViewController infoView; public void OnSelect(ModListController cntrl) { Logger.log.Debug($"Selected BSIPAIgnoredModCell {Plugin.Name} {Plugin.Version}"); if (infoView == null) { var desc = Plugin.Manifest.Description; if (string.IsNullOrWhiteSpace(desc)) desc = "*No description*"; infoView = BeatSaberUI.CreateViewController(); infoView.Init(icon, Plugin.Name, "v" + Plugin.Version.ToString(), authorText, desc, Plugin, Plugin.Manifest.Links); } list.flow.SetSelected(infoView, immediate: list.flow.HasSelected); } public void Update() { } } internal class LibraryModCell : CustomCellInfo, IClickableCell { internal PluginLoader.PluginMetadata Plugin; private ModListController list; public LibraryModCell(ModListController list, PluginLoader.PluginMetadata plugin) : base($"{plugin.Name} v{plugin.Version}", plugin.Manifest.Author, null) { Plugin = plugin; this.list = list; if (string.IsNullOrWhiteSpace(subtext)) subtext = "Unspecified Author"; icon = Utilities.DefaultLibraryIcon; } private ModInfoViewController infoView; public void OnSelect(ModListController cntrl) { Logger.log.Debug($"Selected LibraryModCell {Plugin.Name} {Plugin.Version}"); if (infoView == null) { var desc = Plugin.Manifest.Description; if (string.IsNullOrWhiteSpace(desc)) desc = "*No description*"; infoView = BeatSaberUI.CreateViewController(); infoView.Init(icon, Plugin.Name, "v" + Plugin.Version.ToString(), subtext, desc, Plugin, Plugin.Manifest.Links); } list.flow.SetSelected(infoView, immediate: list.flow.HasSelected); } public void Update() { } } #pragma warning disable CS0618 internal class IPAModCell : CustomCellInfo, IClickableCell { internal IPlugin Plugin; private ModListController list; public IPAModCell(ModListController list, IPlugin plugin) : base($"{plugin.Name} {plugin.Version}", "Legacy", Utilities.DefaultIPAIcon) { Plugin = plugin; this.list = list; } private ModInfoViewController infoView; public void OnSelect(ModListController cntrl) { Logger.log.Debug($"Selected IPAModCell {Plugin.Name} {Plugin.Version}"); if (infoView == null) { PluginLoader.PluginMetadata updateInfo = null; try { updateInfo = new PluginLoader.PluginMetadata { Name = Plugin.Name, Id = Plugin.Name, Version = new SemVer.Version(Plugin.Version) }; } catch (Exception e) { Logger.log.Warn($"Could not generate fake update info for {Plugin.Name}"); Logger.log.Warn(e); } infoView = BeatSaberUI.CreateViewController(); infoView.Init(icon, Plugin.Name, "v" + Plugin.Version.ToString(), "Unknown Author", "This mod was written for IPA.\n===\n\n## No metadata is avaliable for this mod.\n\n" + "Please contact the mod author and ask them to port it to BSIPA to provide more information.", updateInfo); } list.flow.SetSelected(infoView, immediate: list.flow.HasSelected); } public void Update() { } } #pragma warning restore }