public void UpdatePlugins()
        {
            try {
                var pluginsDirectory = new DirectoryInfo(this.pluginDirectory);
                this.installStatus = PluginInstallStatus.Success;
                foreach (var installed in pluginsDirectory.GetDirectories())
                {
                    var versions = installed.GetDirectories();

                    if (versions.Length == 0)
                    {
                        Log.Information("Has no versions: {0}", installed.FullName);
                        continue;
                    }

                    var sortedVersions = versions.OrderBy(x => x.CreationTime);
                    var latest         = sortedVersions.Last();

                    var localInfoFile = new FileInfo(Path.Combine(latest.FullName, $"{installed.Name}.json"));

                    if (!localInfoFile.Exists)
                    {
                        Log.Information("Has no definition: {0}", localInfoFile.FullName);
                        continue;
                    }

                    var info = JsonConvert.DeserializeObject <PluginDefinition>(File.ReadAllText(localInfoFile.FullName));

                    var remoteInfo = this.pluginMaster.FirstOrDefault(x => x.Name == info.Name);

                    if (remoteInfo == null)
                    {
                        Log.Information("Is not in pluginmaster: {0}", info.Name);
                        continue;
                    }

                    if (remoteInfo.AssemblyVersion != info.AssemblyVersion)
                    {
                        this.manager.DisablePlugin(info);
                        InstallPlugin(remoteInfo);
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e, "Plugin update failed hard.");
                this.installStatus = PluginInstallStatus.Fail;
            }
        }
        private void InstallPlugin(PluginDefinition definition)
        {
            try {
                var outputDir    = new DirectoryInfo(Path.Combine(this.pluginDirectory, definition.InternalName, definition.AssemblyVersion));
                var dllFile      = new FileInfo(Path.Combine(outputDir.FullName, $"{definition.InternalName}.dll"));
                var disabledFile = new FileInfo(Path.Combine(outputDir.FullName, ".disabled"));

                if (dllFile.Exists)
                {
                    if (disabledFile.Exists)
                    {
                        disabledFile.Delete();
                    }

                    this.installStatus = this.manager.LoadPluginFromAssembly(dllFile, false) ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
                    return;
                }

                if (outputDir.Exists)
                {
                    outputDir.Delete(true);
                }
                outputDir.Create();

                var path = Path.GetTempFileName();
                Log.Information("Downloading plugin to {0}", path);
                using var client = new WebClient();
                client.DownloadFile(PluginRepoBaseUrl + $"/plugins/{definition.InternalName}/latest.zip", path);

                Log.Information("Extracting to {0}", outputDir);

                ZipFile.ExtractToDirectory(path, outputDir.FullName);

                this.installStatus = this.manager.LoadPluginFromAssembly(dllFile, false) ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
            } catch (Exception e) {
                Log.Error(e, "Plugin download failed hard.");
                this.installStatus = PluginInstallStatus.Fail;
            }
        }
        /// <summary>
        /// Draw the plugin installer view ImGui.
        /// </summary>
        public override void Draw()
        {
            ImGui.SetCursorPosY(ImGui.GetCursorPosY() - (5 * ImGui.GetIO().FontGlobalScale));
            var descriptionText = Loc.Localize("InstallerHint", "This window allows you to install and remove in-game plugins.\nThey are made by third-party developers.");

            ImGui.Text(descriptionText);

            var sortingTextSize = ImGui.CalcTextSize(Loc.Localize("SortDownloadCounts", "Download Count")) + ImGui.CalcTextSize(Loc.Localize("PluginSort", "Sort By"));

            ImGui.SameLine(ImGui.GetWindowWidth() - sortingTextSize.X - ((250 + 20) * ImGui.GetIO().FontGlobalScale));
            ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (ImGui.CalcTextSize(descriptionText).Y / 4) - 2);
            ImGui.SetCursorPosX(ImGui.GetWindowWidth() - sortingTextSize.X - ((250 + 20) * ImGui.GetIO().FontGlobalScale));

            ImGui.SetNextItemWidth(240 * ImGui.GetIO().FontGlobalScale);
            ImGui.InputTextWithHint("###XPlPluginInstaller_Search", Loc.Localize("InstallerSearch", "Search"), ref this.searchText, 100);

            ImGui.SameLine();
            ImGui.SetNextItemWidth((10 * ImGui.GetIO().FontGlobalScale) + ImGui.CalcTextSize(Loc.Localize("SortDownloadCounts", "Download Count")).X);
            if (ImGui.BeginCombo(Loc.Localize("PluginSort", "Sort By"), this.filterText, ImGuiComboFlags.NoArrowButton))
            {
                if (ImGui.Selectable(Loc.Localize("SortAlphabetical", "Alphabetical")))
                {
                    this.sortKind   = PluginSortKind.Alphabetical;
                    this.filterText = Loc.Localize("SortAlphabetical", "Alphabetical");

                    this.ResortPlugins();
                }

                if (ImGui.Selectable(Loc.Localize("SortDownloadCounts", "Download Count")))
                {
                    this.sortKind   = PluginSortKind.DownloadCount;
                    this.filterText = Loc.Localize("SortDownloadCounts", "Download Count");

                    this.ResortPlugins();
                }

                if (ImGui.Selectable(Loc.Localize("SortLastUpdate", "Last Update")))
                {
                    this.sortKind   = PluginSortKind.LastUpdate;
                    this.filterText = Loc.Localize("SortLastUpdate", "Last Update");

                    this.ResortPlugins();
                }

                ImGui.EndCombo();
            }

            ImGui.SetCursorPosY(ImGui.GetCursorPosY() - (5 * ImGui.GetIO().FontGlobalScale));

            string initializationStatusText = null;

            if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.InProgress)
            {
                initializationStatusText = Loc.Localize("InstallerLoading", "Loading plugins...");
                this.pluginListAvailable = null;
            }
            else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.Fail)
            {
                initializationStatusText = Loc.Localize("InstallerDownloadFailed", "Download failed.");
                this.pluginListAvailable = null;
            }
            else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.FailThirdRepo)
            {
                initializationStatusText = Loc.Localize("InstallerDownloadFailedThird", "One of your third party repos is unreachable or there is no internet connection.");
                this.pluginListAvailable = null;
            }
            else
            {
                if (this.pluginListAvailable == null)
                {
                    this.RefetchPlugins();
                }
            }

            ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3) * ImGui.GetIO().FontGlobalScale);

            if (ImGui.BeginTabBar("PluginsTabBar", ImGuiTabBarFlags.NoTooltip))
            {
                this.DrawTab(false, initializationStatusText);
                this.DrawTab(true, initializationStatusText);

                ImGui.EndTabBar();
                ImGui.Separator();
            }

            ImGui.PopStyleVar();

            ImGui.Dummy(new Vector2(3f, 3f) * ImGui.GetIO().FontGlobalScale);

            if (this.installStatus == PluginInstallStatus.InProgress)
            {
                ImGui.Button(Loc.Localize("InstallerUpdating", "Updating..."));
            }
            else
            {
                if (this.updateComplete)
                {
                    ImGui.Button(this.updatePluginCount == 0
                                     ? Loc.Localize("InstallerNoUpdates", "No updates found!")
                                     : string.Format(Loc.Localize("InstallerUpdateComplete", "{0} plugins updated!"), this.updatePluginCount));
                }
                else
                {
                    if (ImGui.Button(Loc.Localize("InstallerUpdatePlugins", "Update plugins")) &&
                        this.dalamud.PluginRepository.State == PluginRepository.InitializationState.Success)
                    {
                        this.installStatus = PluginInstallStatus.InProgress;

                        Task.Run(() => this.dalamud.PluginRepository.UpdatePlugins()).ContinueWith(t =>
                        {
                            this.installStatus =
                                t.Result.Success ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
                            this.installStatus =
                                t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;

                            if (this.installStatus == PluginInstallStatus.Success)
                            {
                                this.updateComplete = true;
                            }

                            if (t.Result.UpdatedPlugins != null)
                            {
                                this.updatePluginCount = t.Result.UpdatedPlugins.Count;
                                this.updatedPlugins    = t.Result.UpdatedPlugins;
                            }

                            this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                            this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;

                            this.dalamud.PluginRepository.PrintUpdatedPlugins(
                                this.updatedPlugins, Loc.Localize("DalamudPluginUpdates", "Updates:"));

                            this.RefetchPlugins();
                        });
                    }
                }
            }

            ImGui.SameLine();

            if (ImGui.Button(Loc.Localize("SettingsInstaller", "Settings")))
            {
                this.dalamud.DalamudUi.OpenSettings();
            }

            var closeText = Loc.Localize("Close", "Close");

            ImGui.SameLine(ImGui.GetWindowWidth() - ImGui.CalcTextSize(closeText).X - (16 * ImGui.GetIO().FontGlobalScale));
            if (ImGui.Button(closeText))
            {
                this.IsOpen = false;
                this.dalamud.Configuration.Save();
            }

            if (ImGui.BeginPopupModal(Loc.Localize("InstallerError", "Installer failed"), ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize))
            {
                var message = Loc.Localize(
                    "InstallerErrorHint",
                    "The plugin installer ran into an issue or the plugin is incompatible.\nPlease restart the game and report this error on our discord.");

                if (this.updatedPlugins != null)
                {
                    if (this.updatedPlugins.Any(x => x.WasUpdated == false))
                    {
                        var extraInfoMessage = Loc.Localize(
                            "InstallerErrorPluginInfo",
                            "\n\nThe following plugins caused these issues:\n\n{0}\nYou may try removing these plugins manually and reinstalling them.");

                        var insert = this.updatedPlugins.Where(x => x.WasUpdated == false)
                                     .Aggregate(
                            string.Empty,
                            (current, pluginUpdateStatus) =>
                            current + $"* {pluginUpdateStatus.InternalName}\n");
                        extraInfoMessage = string.Format(extraInfoMessage, insert);
                        message         += extraInfoMessage;
                    }
                }

                ImGui.Text(message);

                ImGui.Spacing();

                if (ImGui.Button(Loc.Localize("OK", "OK"), new Vector2(120, 40)))
                {
                    ImGui.CloseCurrentPopup();
                }

                ImGui.EndPopup();
            }

            if (this.errorModalOnNextFrame)
            {
                ImGui.OpenPopup(Loc.Localize("InstallerError", "Installer failed"));
                this.errorModalOnNextFrame = false;
            }
        }
        private void DrawPluginList(List <PluginDefinition> pluginDefinitions, bool installed)
        {
            var didAny           = false;
            var didAnyWithSearch = false;
            var hasSearchString  = !string.IsNullOrWhiteSpace(this.searchText);

            for (var index = 0; index < pluginDefinitions.Count; index++)
            {
                var pluginDefinition = pluginDefinitions[index];

                if (pluginDefinition.ApplicableVersion != this.gameVersion &&
                    pluginDefinition.ApplicableVersion != "any")
                {
                    continue;
                }

                if (pluginDefinition.IsHide)
                {
                    continue;
                }

                if (pluginDefinition.DalamudApiLevel < PluginManager.DalamudApiLevel)
                {
                    continue;
                }

                if (this.dalamud.Configuration.HiddenPluginInternalName.Contains(pluginDefinition.InternalName))
                {
                    continue;
                }

                didAny = true;

                if (hasSearchString &&
                    !(pluginDefinition.Name.ToLowerInvariant().Contains(this.searchText.ToLowerInvariant()) ||
                      string.Equals(pluginDefinition.Author, this.searchText, StringComparison.InvariantCultureIgnoreCase) ||
                      (pluginDefinition.Tags != null && pluginDefinition.Tags.Contains(
                           this.searchText.ToLowerInvariant(),
                           StringComparer.InvariantCultureIgnoreCase))))
                {
                    continue;
                }

                didAnyWithSearch = true;

                var isInstalled = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).Any(
                    x => x.Definition.InternalName == pluginDefinition.InternalName);

                var isTestingAvailable = false;
                if (Version.TryParse(pluginDefinition.AssemblyVersion, out var assemblyVersion) &&
                    Version.TryParse(pluginDefinition.TestingAssemblyVersion, out var testingAssemblyVersion))
                {
                    isTestingAvailable = this.dalamud.Configuration.DoPluginTest &&
                                         testingAssemblyVersion > assemblyVersion;
                }

                if (this.dalamud.Configuration.DoPluginTest && pluginDefinition.IsTestingExclusive)
                {
                    isTestingAvailable = true;
                }
                else if (!installed && !this.dalamud.Configuration.DoPluginTest && pluginDefinition.IsTestingExclusive)
                {
                    continue;
                }

                var label = string.Empty;
                if (isInstalled && !installed)
                {
                    label += Loc.Localize("InstallerInstalled", " (installed)");
                }
                else if (!isInstalled && installed)
                {
                    label += Loc.Localize("InstallerDisabled", " (disabled)");
                }

                if (this.updatedPlugins != null &&
                    this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && x.WasUpdated))
                {
                    label += Loc.Localize("InstallerUpdated", " (updated)");
                }
                else if (this.updatedPlugins != null &&
                         this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName &&
                                                 x.WasUpdated == false))
                {
                    label += Loc.Localize("InstallerUpdateFailed", " (update failed)");
                }

                if (isTestingAvailable)
                {
                    label += Loc.Localize("InstallerTestingVersion", " (testing version)");
                }

                ImGui.PushID(pluginDefinition.InternalName + pluginDefinition.AssemblyVersion + installed + index);

                if (ImGui.CollapsingHeader(pluginDefinition.Name + label + "###Header" + pluginDefinition.InternalName))
                {
                    ImGui.Indent();

                    ImGui.Text(pluginDefinition.Name);

                    ImGui.SameLine();

                    var info = $" by {pluginDefinition.Author}";
                    info += pluginDefinition.DownloadCount != 0
                                ? $", {pluginDefinition.DownloadCount} downloads"
                                : ", download count unavailable";
                    if (pluginDefinition.RepoNumber != 0)
                    {
                        info += $", from custom plugin repository #{pluginDefinition.RepoNumber}";
                    }
                    ImGui.TextColored(ImGuiColors.DalamudGrey3, info);

                    if (!string.IsNullOrWhiteSpace(pluginDefinition.Description))
                    {
                        ImGui.TextWrapped(pluginDefinition.Description);
                    }

                    if (!isInstalled)
                    {
                        if (this.installStatus == PluginInstallStatus.InProgress)
                        {
                            ImGui.Button(Loc.Localize("InstallerInProgress", "Install in progress..."));
                        }
                        else
                        {
                            var versionString = isTestingAvailable
                                                    ? pluginDefinition.TestingAssemblyVersion + " (testing version)"
                                                    : pluginDefinition.AssemblyVersion;

                            if (ImGui.Button($"Install v{versionString}"))
                            {
                                this.installStatus = PluginInstallStatus.InProgress;

                                Task.Run(() => this.dalamud.PluginRepository.InstallPlugin(pluginDefinition, true, false, isTestingAvailable)).ContinueWith(t =>
                                {
                                    this.installStatus =
                                        t.Result ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
                                    this.installStatus =
                                        t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;

                                    this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                                    this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;
                                });
                            }
                        }

                        if (!string.IsNullOrEmpty(pluginDefinition.RepoUrl))
                        {
                            ImGui.PushFont(InterfaceManager.IconFont);

                            ImGui.SameLine();
                            if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()) &&
                                pluginDefinition.RepoUrl.StartsWith("https://"))
                            {
                                Process.Start(pluginDefinition.RepoUrl);
                            }

                            ImGui.PopFont();
                        }
                    }
                    else
                    {
                        var installedPlugin = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).First(
                            x => x.Definition.InternalName ==
                            pluginDefinition.InternalName);

                        var commands = this.dalamud.CommandManager.Commands.Where(
                            x => x.Value.LoaderAssemblyName == installedPlugin.Definition?.InternalName &&
                            x.Value.ShowInHelp);
                        if (commands.Any())
                        {
                            ImGui.Dummy(new Vector2(10f, 10f) * ImGui.GetIO().FontGlobalScale);
                            foreach (var command in commands)
                            {
                                ImGui.TextWrapped($"{command.Key} → {command.Value.HelpMessage}");
                            }
                        }

                        ImGui.NewLine();

                        if (!installedPlugin.IsRaw)
                        {
                            ImGui.SameLine();

                            if (ImGui.Button(Loc.Localize("InstallerDisable", "Disable")))
                            {
                                try
                                {
                                    this.dalamud.PluginManager.DisablePlugin(installedPlugin.Definition);
                                }
                                catch (Exception exception)
                                {
                                    Log.Error(exception, "Could not disable plugin.");
                                    this.errorModalDrawing     = true;
                                    this.errorModalOnNextFrame = true;
                                }
                            }
                        }

                        if (installedPlugin.PluginInterface.UiBuilder.HasConfigUi)
                        {
                            ImGui.SameLine();

                            if (ImGui.Button(Loc.Localize("InstallerOpenConfig", "Open Configuration")))
                            {
                                installedPlugin.PluginInterface.UiBuilder.OpenConfigUi();
                            }
                        }

                        if (!string.IsNullOrEmpty(installedPlugin.Definition.RepoUrl))
                        {
                            ImGui.PushFont(InterfaceManager.IconFont);

                            ImGui.SameLine();
                            if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()) &&
                                installedPlugin.Definition.RepoUrl.StartsWith("https://"))
                            {
                                Process.Start(installedPlugin.Definition.RepoUrl);
                            }

                            ImGui.PopFont();
                        }

                        ImGui.SameLine();
                        ImGui.TextColored(ImGuiColors.DalamudGrey3, $" v{installedPlugin.Definition.AssemblyVersion}");

                        if (installedPlugin.IsRaw)
                        {
                            ImGui.SameLine();
                            ImGui.TextColored(
                                ImGuiColors.DalamudRed,
                                this.dalamud.PluginRepository.PluginMaster.Any(x => x.InternalName == installedPlugin.Definition.InternalName)
                                                   ? " This plugin is available in one of your repos, please remove it from the devPlugins folder."
                                                   : " To disable this plugin, please remove it from the devPlugins folder.");
                        }
                    }

                    ImGui.Unindent();
                }

                if (ImGui.BeginPopupContextItem("item context menu"))
                {
                    if (ImGui.Selectable("Hide from installer"))
                    {
                        this.dalamud.Configuration.HiddenPluginInternalName.Add(pluginDefinition.InternalName);
                    }
                    ImGui.EndPopup();
                }

                ImGui.PopID();
            }

            if (!didAny)
            {
                if (installed)
                {
                    ImGui.TextColored(
                        ImGuiColors.DalamudGrey,
                        Loc.Localize(
                            "InstallerNoInstalled",
                            "No plugins are currently installed. You can install them from the Available Plugins tab."));
                }
                else
                {
                    ImGui.TextColored(
                        ImGuiColors.DalamudGrey,
                        Loc.Localize(
                            "InstallerNoCompatible",
                            "No compatible plugins were found :( Please restart your game and try again."));
                }
            }
            else if (!didAnyWithSearch)
            {
                ImGui.TextColored(
                    ImGuiColors.DalamudGrey2,
                    Loc.Localize("InstallNoMatching", "No plugins were found matching your search."));
            }
        }
        public bool Draw()
        {
            var windowOpen = true;

            ImGui.SetNextWindowSize(new Vector2(750, 520));

            ImGui.Begin(Loc.Localize("InstallerHeader", "Plugin Installer"), ref windowOpen,
                        ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar);

            ImGui.Text(Loc.Localize("InstallerHint", "This window allows you install and remove in-game plugins.\nThey are made by third-party developers."));
            ImGui.Separator();

            ImGui.BeginChild("scrolling", new Vector2(0, 400), true, ImGuiWindowFlags.HorizontalScrollbar);

            ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3));

            if (this.repository.State == PluginRepository.InitializationState.InProgress)
            {
                ImGui.Text(Loc.Localize("InstallerLoading", "Loading plugins..."));
            }
            else if (this.repository.State == PluginRepository.InitializationState.Fail)
            {
                ImGui.Text(Loc.Localize("InstallerDownloadFailed", "Download failed."));
            }
            else
            {
                foreach (var pluginDefinition in this.repository.PluginMaster)
                {
                    if (pluginDefinition.ApplicableVersion != this.gameVersion &&
                        pluginDefinition.ApplicableVersion != "any")
                    {
                        continue;
                    }

                    if (pluginDefinition.IsHide)
                    {
                        continue;
                    }

                    ImGui.PushID(pluginDefinition.InternalName + pluginDefinition.AssemblyVersion);

                    var isInstalled = this.manager.Plugins.Where(x => x.Definition != null).Any(
                        x => x.Definition.InternalName == pluginDefinition.InternalName);

                    if (ImGui.CollapsingHeader(pluginDefinition.Name + (isInstalled ? Loc.Localize("InstallerInstalled", " (installed)") : string.Empty)))
                    {
                        ImGui.Indent();

                        ImGui.Text(pluginDefinition.Name);
                        ImGui.SameLine();
                        ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" by {pluginDefinition.Author}");

                        ImGui.Text(pluginDefinition.Description);

                        if (!isInstalled)
                        {
                            if (this.installStatus == PluginInstallStatus.InProgress)
                            {
                                ImGui.Button(Loc.Localize("InstallerInProgress", "Install in progress..."));
                            }
                            else
                            {
                                if (ImGui.Button($"Install v{pluginDefinition.AssemblyVersion}"))
                                {
                                    this.installStatus = PluginInstallStatus.InProgress;

                                    Task.Run(() => this.repository.InstallPlugin(pluginDefinition)).ContinueWith(t => {
                                        this.installStatus =
                                            t.Result ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
                                        this.installStatus =
                                            t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;

                                        this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                                        this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;
                                    });
                                }
                            }
                        }
                        else
                        {
                            var installedPlugin = this.manager.Plugins.Where(x => x.Definition != null).First(
                                x => x.Definition.InternalName ==
                                pluginDefinition.InternalName);

                            if (ImGui.Button(Loc.Localize("InstallerDisable", "Disable")))
                            {
                                try {
                                    this.manager.DisablePlugin(installedPlugin.Definition);
                                } catch (Exception exception) {
                                    Log.Error(exception, "Could not disable plugin.");
                                    this.errorModalDrawing     = true;
                                    this.errorModalOnNextFrame = true;
                                }
                            }

                            if (installedPlugin.PluginInterface.UiBuilder.OnOpenConfigUi != null)
                            {
                                ImGui.SameLine();

                                if (ImGui.Button(Loc.Localize("InstallerOpenConfig", "Open Configuration")))
                                {
                                    installedPlugin.PluginInterface.UiBuilder.OnOpenConfigUi?.Invoke(null, null);
                                }
                            }

                            ImGui.SameLine();
                            ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" v{pluginDefinition.AssemblyVersion}");
                        }

                        ImGui.Unindent();
                    }

                    ImGui.PopID();
                }
            }

            ImGui.PopStyleVar();

            ImGui.EndChild();

            ImGui.Separator();

            if (this.installStatus == PluginInstallStatus.InProgress)
            {
                ImGui.Button(Loc.Localize("InstallerUpdating", "Updating..."));
            }
            else
            {
                if (this.updateComplete)
                {
                    ImGui.Button(this.updatePluginCount == 0
                                     ? Loc.Localize("InstallerNoUpdates", "No updates found!")
                                     : string.Format(Loc.Localize("InstallerUpdateComplete", "{0} plugins updated!"), this.updatePluginCount));
                }
                else
                {
                    if (ImGui.Button(Loc.Localize("InstallerUpdatePlugins", "Update plugins")))
                    {
                        this.installStatus = PluginInstallStatus.InProgress;

                        Task.Run(() => this.repository.UpdatePlugins()).ContinueWith(t => {
                            this.installStatus =
                                t.Result.Success ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
                            this.installStatus =
                                t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;

                            if (this.installStatus == PluginInstallStatus.Success)
                            {
                                this.updateComplete    = true;
                                this.updatePluginCount = t.Result.UpdatedCount;
                            }

                            this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                            this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;
                        });
                    }
                }
            }


            ImGui.SameLine();

            if (ImGui.Button(Loc.Localize("Close", "Close")))
            {
                windowOpen = false;
            }

            ImGui.Spacing();

            if (ImGui.BeginPopupModal(Loc.Localize("InstallerError", "Installer failed"), ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize))
            {
                ImGui.Text(Loc.Localize("InstallerErrorHint", "The plugin installer ran into an issue or the plugin is incompatible.\nPlease restart the game and report this error on our discord."));

                ImGui.Spacing();

                if (ImGui.Button(Loc.Localize("OK", "OK"), new Vector2(120, 40)))
                {
                    ImGui.CloseCurrentPopup();
                }

                ImGui.EndPopup();
            }

            if (this.errorModalOnNextFrame)
            {
                ImGui.OpenPopup(Loc.Localize("InstallerError", "Installer failed"));
                this.errorModalOnNextFrame = false;
            }


            ImGui.End();

            return(windowOpen);
        }
Beispiel #6
0
        public bool Draw()
        {
            var windowOpen = true;

            ImGui.SetNextWindowSize(new Vector2(750, 520));

            ImGui.Begin(Loc.Localize("InstallerHeader", "Plugin Installer") + (this.dalamud.Configuration.DoPluginTest ? " (TESTING)" : string.Empty) + "###XlPluginInstaller", ref windowOpen,
                        ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar);

            ImGui.Text(Loc.Localize("InstallerHint", "This window allows you install and remove in-game plugins.\nThey are made by third-party developers."));
            ImGui.SameLine();
            ImGui.InputTextWithHint("###XPlPluginInstaller_Search", Loc.Localize("InstallerSearch", "Search"), this.searchText, 100);
            ImGui.Separator();

            ImGui.BeginChild("scrolling", new Vector2(0, 400), true, ImGuiWindowFlags.HorizontalScrollbar);

            ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3));

            if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.InProgress)
            {
                ImGui.Text(Loc.Localize("InstallerLoading", "Loading plugins..."));
            }
            else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.Fail)
            {
                ImGui.Text(Loc.Localize("InstallerDownloadFailed", "Download failed."));
            }
            else
            {
                var didAny           = false;
                var didAnyWithSearch = false;
                var hasSearchString  = !string.IsNullOrWhiteSpace(this.searchText);

                foreach (var pluginDefinition in this.dalamud.PluginRepository.PluginMaster)
                {
                    if (pluginDefinition.ApplicableVersion != this.gameVersion &&
                        pluginDefinition.ApplicableVersion != "any")
                    {
                        continue;
                    }

                    if (pluginDefinition.IsHide)
                    {
                        continue;
                    }

                    if (pluginDefinition.DalamudApiLevel != PluginManager.DALAMUD_API_LEVEL)
                    {
                        continue;
                    }

                    didAny = true;

                    if (hasSearchString &&
                        !(pluginDefinition.Name.ToLowerInvariant().Contains(this.searchText.ToLowerInvariant()) ||
                          string.Equals(pluginDefinition.Author, this.searchText, StringComparison.InvariantCultureIgnoreCase) ||
                          pluginDefinition.Tags != null &&
                          pluginDefinition.Tags.Contains(this.searchText.ToLowerInvariant(), StringComparer.InvariantCultureIgnoreCase)
                          ))
                    {
                        continue;
                    }

                    didAnyWithSearch = true;

                    ImGui.PushID(pluginDefinition.InternalName + pluginDefinition.AssemblyVersion);

                    var isInstalled = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).Any(
                        x => x.Definition.InternalName == pluginDefinition.InternalName);

                    var label = isInstalled ? Loc.Localize("InstallerInstalled", " (installed)") : string.Empty;
                    label = this.updatedPlugins != null &&
                            this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && x.WasUpdated)
                                ? Loc.Localize("InstallerUpdated", " (updated)")
                                : label;

                    label = this.updatedPlugins != null &&
                            this.updatedPlugins.Any(x => x.InternalName == pluginDefinition.InternalName && x.WasUpdated == false)
                                ? Loc.Localize("InstallerUpdateFailed", " (update failed)")
                                : label;

                    if (ImGui.CollapsingHeader(pluginDefinition.Name + label + "###Header" + pluginDefinition.InternalName))
                    {
                        ImGui.Indent();

                        ImGui.Text(pluginDefinition.Name);
                        ImGui.SameLine();
                        ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" by {pluginDefinition.Author}, {pluginDefinition.DownloadCount} downloads");

                        ImGui.Text(pluginDefinition.Description);

                        if (!isInstalled)
                        {
                            if (this.installStatus == PluginInstallStatus.InProgress)
                            {
                                ImGui.Button(Loc.Localize("InstallerInProgress", "Install in progress..."));
                            }
                            else
                            {
                                if (ImGui.Button($"Install v{pluginDefinition.AssemblyVersion}"))
                                {
                                    this.installStatus = PluginInstallStatus.InProgress;

                                    Task.Run(() => this.dalamud.PluginRepository.InstallPlugin(pluginDefinition)).ContinueWith(t => {
                                        this.installStatus =
                                            t.Result ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
                                        this.installStatus =
                                            t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;

                                        this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                                        this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;
                                    });
                                }
                            }
                            if (!string.IsNullOrEmpty(pluginDefinition.RepoUrl))
                            {
                                ImGui.PushFont(InterfaceManager.IconFont);

                                ImGui.SameLine();
                                if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()) &&
                                    pluginDefinition.RepoUrl.StartsWith("https://"))
                                {
                                    Process.Start(pluginDefinition.RepoUrl);
                                }

                                ImGui.PopFont();
                            }
                        }
                        else
                        {
                            var installedPlugin = this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).First(
                                x => x.Definition.InternalName ==
                                pluginDefinition.InternalName);

                            if (ImGui.Button(Loc.Localize("InstallerDisable", "Disable")))
                            {
                                try {
                                    this.dalamud.PluginManager.DisablePlugin(installedPlugin.Definition);
                                } catch (Exception exception) {
                                    Log.Error(exception, "Could not disable plugin.");
                                    this.errorModalDrawing     = true;
                                    this.errorModalOnNextFrame = true;
                                }
                            }

                            if (installedPlugin.PluginInterface.UiBuilder.OnOpenConfigUi != null)
                            {
                                ImGui.SameLine();

                                if (ImGui.Button(Loc.Localize("InstallerOpenConfig", "Open Configuration")))
                                {
                                    installedPlugin.PluginInterface.UiBuilder.OnOpenConfigUi?.Invoke(null, null);
                                }
                            }

                            if (!string.IsNullOrEmpty(installedPlugin.Definition.RepoUrl))
                            {
                                ImGui.PushFont(InterfaceManager.IconFont);

                                ImGui.SameLine();
                                if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()) &&
                                    installedPlugin.Definition.RepoUrl.StartsWith("https://"))
                                {
                                    Process.Start(installedPlugin.Definition.RepoUrl);
                                }

                                ImGui.PopFont();
                            }

                            ImGui.SameLine();
                            ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" v{pluginDefinition.AssemblyVersion}");
                        }

                        ImGui.Unindent();
                    }

                    ImGui.PopID();
                }

                if (!didAny)
                {
                    ImGui.TextColored(new Vector4(0.70f, 0.70f, 0.70f, 1.00f), Loc.Localize("InstallerNoCompatible", "No compatible plugins were found :( Please restart your game and try again."));
                }
                else if (!didAnyWithSearch)
                {
                    ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.7f, 1.0f), Loc.Localize("InstallNoMatching", "No plugins were found matching your search."));
                }
            }

            ImGui.PopStyleVar();

            ImGui.EndChild();

            ImGui.Separator();

            if (this.installStatus == PluginInstallStatus.InProgress)
            {
                ImGui.Button(Loc.Localize("InstallerUpdating", "Updating..."));
            }
            else
            {
                if (this.updateComplete)
                {
                    ImGui.Button(this.updatePluginCount == 0
                                     ? Loc.Localize("InstallerNoUpdates", "No updates found!")
                                     : string.Format(Loc.Localize("InstallerUpdateComplete", "{0} plugins updated!"), this.updatePluginCount));
                }
                else
                {
                    if (ImGui.Button(Loc.Localize("InstallerUpdatePlugins", "Update plugins")))
                    {
                        this.installStatus = PluginInstallStatus.InProgress;

                        Task.Run(() => this.dalamud.PluginRepository.UpdatePlugins()).ContinueWith(t => {
                            this.installStatus =
                                t.Result.Success ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
                            this.installStatus =
                                t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;

                            if (this.installStatus == PluginInstallStatus.Success)
                            {
                                this.updateComplete = true;
                            }

                            if (t.Result.UpdatedPlugins != null)
                            {
                                this.updatePluginCount = t.Result.UpdatedPlugins.Count;
                                this.updatedPlugins    = t.Result.UpdatedPlugins;
                            }

                            this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                            this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;
                        });
                    }
                }
            }


            ImGui.SameLine();

            if (ImGui.Button(Loc.Localize("Close", "Close")))
            {
                windowOpen = false;
            }

            ImGui.Spacing();

            if (ImGui.BeginPopupModal(Loc.Localize("InstallerError", "Installer failed"), ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize))
            {
                var message = Loc.Localize("InstallerErrorHint",
                                           "The plugin installer ran into an issue or the plugin is incompatible.\nPlease restart the game and report this error on our discord.");

                if (this.updatedPlugins != null)
                {
                    if (this.updatedPlugins.Any(x => x.WasUpdated == false))
                    {
                        var extraInfoMessage = Loc.Localize("InstallerErrorPluginInfo",
                                                            "\n\nThe following plugins caused these issues:\n\n{0}\nYou may try removing these plugins manually and reinstalling them.");

                        var insert = this.updatedPlugins.Where(x => x.WasUpdated == false)
                                     .Aggregate(string.Empty,
                                                (current, pluginUpdateStatus) =>
                                                current + $"* {pluginUpdateStatus.InternalName}\n");
                        extraInfoMessage = string.Format(extraInfoMessage, insert);
                        message         += extraInfoMessage;
                    }
                }

                ImGui.Text(message);

                ImGui.Spacing();

                if (ImGui.Button(Loc.Localize("OK", "OK"), new Vector2(120, 40)))
                {
                    ImGui.CloseCurrentPopup();
                }

                ImGui.EndPopup();
            }

            if (this.errorModalOnNextFrame)
            {
                ImGui.OpenPopup(Loc.Localize("InstallerError", "Installer failed"));
                this.errorModalOnNextFrame = false;
            }


            ImGui.End();

            return(windowOpen);
        }
        public bool Draw()
        {
            var windowOpen = true;

            ImGui.SetNextWindowSize(new Vector2(810, 520) * ImGui.GetIO().FontGlobalScale);

            ImGui.Begin(Loc.Localize("InstallerHeader", "Plugin Installer") + (this.dalamud.Configuration.DoPluginTest ? " (TESTING)" : string.Empty) + "###XlPluginInstaller", ref windowOpen,
                        ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar);

            ImGui.Text(Loc.Localize("InstallerHint", "This window allows you install and remove in-game plugins.\nThey are made by third-party developers."));

            ImGui.SameLine(ImGui.GetWindowWidth() - ((250 + 20 + ImGui.CalcTextSize(Loc.Localize("SortDownloadCounts", "Download Count")).X + ImGui.CalcTextSize(Loc.Localize("PluginSort", "Sort By")).X) * ImGui.GetIO().FontGlobalScale));

            ImGui.SetNextItemWidth(240 * ImGui.GetIO().FontGlobalScale);
            ImGui.InputTextWithHint("###XPlPluginInstaller_Search", Loc.Localize("InstallerSearch", "Search"), ref this.searchText, 100);

            ImGui.SameLine();
            ImGui.SetNextItemWidth(10 + (ImGui.CalcTextSize(Loc.Localize("SortDownloadCounts", "Download Count")).X) * ImGui.GetIO().FontGlobalScale);
            if (ImGui.BeginCombo(Loc.Localize("PluginSort", "Sort By"), this.filterText, ImGuiComboFlags.NoArrowButton))
            {
                if (ImGui.Selectable(Loc.Localize("SortAlphabetical", "Alphabetical")))
                {
                    this.sortKind   = PluginSortKind.Alphabetical;
                    this.filterText = Loc.Localize("SortAlphabetical", "Alphabetical");

                    ResortAvailable();
                }

                if (ImGui.Selectable(Loc.Localize("SortDownloadCounts", "Download Count")))
                {
                    this.sortKind   = PluginSortKind.DownloadCount;
                    this.filterText = Loc.Localize("SortDownloadCounts", "Download Count");

                    ResortAvailable();
                }

                if (ImGui.Selectable(Loc.Localize("SortLastUpdate", "Last Update")))
                {
                    this.sortKind   = PluginSortKind.LastUpdate;
                    this.filterText = Loc.Localize("SortLastUpdate", "Last Update");

                    ResortAvailable();
                }

                ImGui.EndCombo();
            }

            ImGui.BeginChild("scrolling", new Vector2(0, 400 * ImGui.GetIO().FontGlobalScale), true, ImGuiWindowFlags.HorizontalScrollbar);

            ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3) * ImGui.GetIO().FontGlobalScale);

            if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.InProgress)
            {
                ImGui.Text(Loc.Localize("InstallerLoading", "Loading plugins..."));
            }
            else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.Fail)
            {
                ImGui.Text(Loc.Localize("InstallerDownloadFailed", "Download failed."));
            }
            else if (this.dalamud.PluginRepository.State == PluginRepository.InitializationState.FailThirdRepo)
            {
                ImGui.Text(Loc.Localize("InstallerDownloadFailedThird", "One of your third party repos is unreachable or there is no internet connection."));
            }
            else
            {
                if (this.pluginListAvailable == null)
                {
                    var hiddenPlugins = this.dalamud.PluginManager.Plugins.Where(
                        x => this.dalamud.PluginRepository.PluginMaster.All(
                            y => y.InternalName != x.Definition.InternalName || y.InternalName == x.Definition.InternalName && y.IsHide)).Select(x => x.Definition).ToList();
                    this.pluginListInstalled = this.dalamud.PluginRepository.PluginMaster
                                               .Where(def => {
                        return(this.dalamud.PluginManager.Plugins.Where(x => x.Definition != null).Any(
                                   x => x.Definition.InternalName == def.InternalName));
                    })
                                               .ToList();
                    this.pluginListInstalled.AddRange(hiddenPlugins);
                    this.pluginListInstalled.Sort((x, y) => x.Name.CompareTo(y.Name));

                    ResortAvailable();
                }

                ImGui.TextColored(this.colorGrey,
                                  Loc.Localize("InstallerAvailablePluginList",
                                               "Available Plugins:"));
                DrawPluginList(this.pluginListAvailable, false);

                ImGui.Dummy(new Vector2(5, 5));
                ImGui.Separator();
                ImGui.Dummy(new Vector2(5, 5));

                ImGui.TextColored(this.colorGrey,
                                  Loc.Localize("InstallerInstalledPluginList",
                                               "Installed Plugins:"));
                DrawPluginList(this.pluginListInstalled, true);
            }

            ImGui.PopStyleVar();

            ImGui.EndChild();

            ImGui.Separator();

            if (this.installStatus == PluginInstallStatus.InProgress)
            {
                ImGui.Button(Loc.Localize("InstallerUpdating", "Updating..."));
            }
            else
            {
                if (this.updateComplete)
                {
                    ImGui.Button(this.updatePluginCount == 0
                                     ? Loc.Localize("InstallerNoUpdates", "No updates found!")
                                     : string.Format(Loc.Localize("InstallerUpdateComplete", "{0} plugins updated!"), this.updatePluginCount));
                }
                else
                {
                    if (ImGui.Button(Loc.Localize("InstallerUpdatePlugins", "Update plugins")))
                    {
                        this.installStatus = PluginInstallStatus.InProgress;

                        Task.Run(() => this.dalamud.PluginRepository.UpdatePlugins()).ContinueWith(t => {
                            this.installStatus =
                                t.Result.Success ? PluginInstallStatus.Success : PluginInstallStatus.Fail;
                            this.installStatus =
                                t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;

                            if (this.installStatus == PluginInstallStatus.Success)
                            {
                                this.updateComplete = true;
                            }

                            if (t.Result.UpdatedPlugins != null)
                            {
                                this.updatePluginCount = t.Result.UpdatedPlugins.Count;
                                this.updatedPlugins    = t.Result.UpdatedPlugins;
                            }

                            this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                            this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;

                            this.dalamud.PluginRepository.PrintUpdatedPlugins(updatedPlugins, Loc.Localize("DalamudPluginUpdates", "Updates:"));
                        });
                    }
                }
            }


            ImGui.SameLine();

            if (ImGui.Button(Loc.Localize("Close", "Close")))
            {
                windowOpen = false;
            }

            ImGui.Spacing();

            if (ImGui.BeginPopupModal(Loc.Localize("InstallerError", "Installer failed"), ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize))
            {
                var message = Loc.Localize("InstallerErrorHint",
                                           "The plugin installer ran into an issue or the plugin is incompatible.\nPlease restart the game and report this error on our discord.");

                if (this.updatedPlugins != null)
                {
                    if (this.updatedPlugins.Any(x => x.WasUpdated == false))
                    {
                        var extraInfoMessage = Loc.Localize("InstallerErrorPluginInfo",
                                                            "\n\nThe following plugins caused these issues:\n\n{0}\nYou may try removing these plugins manually and reinstalling them.");

                        var insert = this.updatedPlugins.Where(x => x.WasUpdated == false)
                                     .Aggregate(string.Empty,
                                                (current, pluginUpdateStatus) =>
                                                current + $"* {pluginUpdateStatus.InternalName}\n");
                        extraInfoMessage = string.Format(extraInfoMessage, insert);
                        message         += extraInfoMessage;
                    }
                }

                ImGui.Text(message);

                ImGui.Spacing();

                if (ImGui.Button(Loc.Localize("OK", "OK"), new Vector2(120, 40)))
                {
                    ImGui.CloseCurrentPopup();
                }

                ImGui.EndPopup();
            }

            if (this.errorModalOnNextFrame)
            {
                ImGui.OpenPopup(Loc.Localize("InstallerError", "Installer failed"));
                this.errorModalOnNextFrame = false;
            }


            ImGui.End();

            return(windowOpen);
        }
        public bool Draw()
        {
            var windowOpen = true;

            ImGui.SetNextWindowSize(new Vector2(750, 518));

            ImGui.Begin("Plugin Installer", ref windowOpen,
                        ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar);

            ImGui.Text("This window allows you install and remove in-game plugins.");
            ImGui.Text("They are made by third-party developers.");
            ImGui.Separator();

            ImGui.BeginChild("scrolling", new Vector2(0, 400), true, ImGuiWindowFlags.HorizontalScrollbar);

            ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 3));

            if (this.pluginMaster == null)
            {
                ImGui.Text("Loading plugins...");
            }
            else if (this.masterDownloadFailed)
            {
                ImGui.Text("Download failed.");
            }
            else
            {
                foreach (var pluginDefinition in this.pluginMaster)
                {
                    if (pluginDefinition.ApplicableVersion != this.gameVersion &&
                        pluginDefinition.ApplicableVersion != "any")
                    {
                        continue;
                    }

                    if (pluginDefinition.IsHide)
                    {
                        continue;
                    }

                    if (ImGui.CollapsingHeader(pluginDefinition.Name))
                    {
                        ImGui.Indent();

                        ImGui.Text(pluginDefinition.Name);
                        ImGui.SameLine();
                        ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" by {pluginDefinition.Author}");

                        ImGui.Text(pluginDefinition.Description);

                        var isInstalled = this.manager.Plugins.Where(x => x.Definition != null).Any(
                            x => x.Definition.InternalName == pluginDefinition.InternalName);

                        if (!isInstalled)
                        {
                            if (this.installStatus == PluginInstallStatus.InProgress)
                            {
                                ImGui.Button("Install in progress...");
                            }
                            else
                            {
                                if (ImGui.Button($"Install v{pluginDefinition.AssemblyVersion}"))
                                {
                                    this.installStatus = PluginInstallStatus.InProgress;

                                    Task.Run(() => InstallPlugin(pluginDefinition)).ContinueWith(t => {
                                        this.installStatus =
                                            t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;
                                        this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                                        this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;
                                    });
                                }
                            }
                        }
                        else
                        {
                            var installedPlugin = this.manager.Plugins.Where(x => x.Definition != null).First(
                                x => x.Definition.InternalName ==
                                pluginDefinition.InternalName);

                            if (ImGui.Button("Disable"))
                            {
                                try {
                                    this.manager.DisablePlugin(installedPlugin.Definition);
                                } catch (Exception exception) {
                                    Log.Error(exception, "Could not disable plugin.");
                                    this.errorModalDrawing     = true;
                                    this.errorModalOnNextFrame = true;
                                }
                            }

                            if (installedPlugin.Plugin is IHasConfigUi v2Plugin && v2Plugin.OpenConfigUi != null)
                            {
                                ImGui.SameLine();

                                if (ImGui.Button("Open Configuration"))
                                {
                                    v2Plugin.OpenConfigUi?.Invoke(null, null);
                                }
                            }

                            ImGui.SameLine();
                            ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.5f, 1.0f), $" v{pluginDefinition.AssemblyVersion}");
                        }

                        ImGui.Unindent();
                    }
                }
            }

            ImGui.PopStyleVar();

            ImGui.EndChild();

            ImGui.Separator();

            if (this.installStatus == PluginInstallStatus.InProgress)
            {
                ImGui.Button("In progress...");
            }
            else
            {
                if (ImGui.Button("Update plugins"))
                {
                    this.installStatus = PluginInstallStatus.InProgress;

                    Task.Run(() => UpdatePlugins()).ContinueWith(t => {
                        this.installStatus =
                            t.IsFaulted ? PluginInstallStatus.Fail : this.installStatus;
                        this.errorModalDrawing     = this.installStatus == PluginInstallStatus.Fail;
                        this.errorModalOnNextFrame = this.installStatus == PluginInstallStatus.Fail;
                    });
                }
            }


            ImGui.SameLine();

            if (ImGui.Button("Close"))
            {
                windowOpen = false;
            }

            ImGui.Spacing();

            if (ImGui.BeginPopupModal("Installer failed", ref this.errorModalDrawing, ImGuiWindowFlags.AlwaysAutoResize))
            {
                ImGui.Text("The plugin installer ran into an issue or the plugin is incompatible.");
                ImGui.Text("Please restart the game and report this error on our discord.");

                ImGui.Spacing();

                if (ImGui.Button("OK", new Vector2(120, 40)))
                {
                    ImGui.CloseCurrentPopup();
                }

                ImGui.EndPopup();
            }

            if (this.errorModalOnNextFrame)
            {
                ImGui.OpenPopup("Installer failed");
                this.errorModalOnNextFrame = false;
            }


            ImGui.End();

            return(windowOpen);
        }