using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Windows.Forms; namespace Flyoobe { public partial class InstallControlView : UserControl, IView { public string ViewTitle => "Custom: Install && Repair"; // Providers & per-provider last selections private readonly List _providers = new List(); // Store last selections (ISO/exe) per provider ID private readonly Dictionary _lastByProvider = new Dictionary(StringComparer.OrdinalIgnoreCase); public InstallControlView() { InitializeComponent(); InitProviderCombo(); WireUpTooltips(); HookUpEvents(); HookSearchBox(); UpdateHint(); } private void InitProviderCombo() { // Register install sources _providers.Add(new NativeResetProvider()); _providers.Add(new RufusProvider()); _providers.Add(new MctProvider()); _providers.Add(new VentoyProvider()); _providers.Add(new InPlaceRepairProvider()); _providers.Add(new RunSetupFromIsoProvider()); _providers.Add(new MountIsoProvider()); _providers.Add(new RebootToUefiProvider()); _providers.Add(new BootMenuInfoProvider()); _providers.Add(new BackupDriversProvider()); // Bind providers to dropdown if (cboSource != null) { cboSource.DropDownStyle = ComboBoxStyle.DropDownList; cboSource.DisplayMember = nameof(IInstallProvider.DisplayName); cboSource.DataSource = _providers; cboSource.FormattingEnabled = true; cboSource.Format += (s, e) => { var p = e.ListItem as IInstallProvider; if (p == null) { e.Value = e.ListItem?.ToString(); return; } var badgeTool = p.IsExternalTool ? "🧰" : "🪟"; var badgeIso = p.TypicallyNeedsIso ? " 💿" : string.Empty; var badgeDl = !string.IsNullOrEmpty(p.DirectDownloadUrl) ? " ⬇️" : string.Empty; e.Value = $"{badgeTool}{badgeIso}{badgeDl} {p.DisplayName}"; }; // In InitProviderCombo(): nur EIN Aufruf statt zweier cboSource.SelectedIndexChanged += (s, e) => { UpdateHint(); UpdateBadgeLegend(SelectedProvider); // update badges }; if (cboSource.Items.Count > 0) cboSource.SelectedIndex = 0; // Initial legend UpdateBadgeLegend(SelectedProvider); } } // Reset all badges and highlight active ones. private void UpdateBadgeLegend(IInstallProvider p) { // local helper to style a "badge" label void Style(Label lbl, System.Drawing.Color back, System.Drawing.Color fore) { if (lbl == null) return; lbl.BackColor = back; lbl.ForeColor = fore; lbl.Padding = new Padding(6, 2, 6, 2); } // base (dim) + highlight colors var dimBack = System.Drawing.Color.FromArgb(240, 240, 240); var dimFore = System.Drawing.Color.Black; var hiBack = System.Drawing.Color.FromArgb(204, 222, 246); // blue badge var hiFore = System.Drawing.Color.Black; // reset all badges Style(lblBadgeNative, dimBack, dimFore); Style(lblBadgeExternal, dimBack, dimFore); Style(lblBadgeIso, dimBack, dimFore); Style(lblBadgeDl, dimBack, dimFore); if (p == null) return; // highlight active badges if (p.IsExternalTool) Style(lblBadgeExternal, hiBack, hiFore); else Style(lblBadgeNative, hiBack, hiFore); if (p.TypicallyNeedsIso) Style(lblBadgeIso, hiBack, hiFore); if (!string.IsNullOrEmpty(p.DirectDownloadUrl)) Style(lblBadgeDl, hiBack, hiFore); } public void RefreshView() { // Reserved for future state refresh (e.g., detect admin etc.) } // -------------------------------------------------------------------------------- // Event wiring // -------------------------------------------------------------------------------- private void HookUpEvents() { // Install section if (btnRun != null) btnRun.Click += async (s, e) => await RunSelectedAsync(); if (btnHomepage != null) btnHomepage.Click += (s, e) => OpenHomepage(); if (btnDownload != null) btnDownload.Click += async (s, e) => await DownloadProviderAsync(); // One-click actions if (btnQuickRepair != null) btnQuickRepair.Click += async (s, e) => await RunQuickAsync("winreset"); // NativeResetProvider.Id if (btnCreateUsb != null) btnCreateUsb.Click += async (s, e) => await RunQuickAsync("mct"); // MctProvider.Id } private void WireUpTooltips() { if (toolTip1 == null) return; // Install toolTip1.SetToolTip(cboSource, "Choose the install source (Rufus, MCT, Ventoy, ...)."); toolTip1.SetToolTip(btnRun, "Open provider options (if any) and run the selected tool."); toolTip1.SetToolTip(btnHomepage, "Open the provider's official website."); toolTip1.SetToolTip(btnDownload, "Download the provider binary if a direct URL is available."); } private void UpdateHint() { if (lblHint == null) return; var p = SelectedProvider; lblHint.Text = p?.Hint ?? string.Empty; } // -------------------------------------------------------------------------------- // Provider selection helpers // -------------------------------------------------------------------------------- private IInstallProvider SelectedProvider => cboSource?.SelectedItem as IInstallProvider; private LastSelections GetLast(IInstallProvider p) { if (p == null) return null; if (!_lastByProvider.TryGetValue(p.Id, out var last)) { last = new LastSelections(); _lastByProvider[p.Id] = last; } return last; } // -------------------------------------------------------------------------------- // Install: run selected provider // -------------------------------------------------------------------------------- private async System.Threading.Tasks.Task RunSelectedAsync() { var p = SelectedProvider; if (p == null) return; var last = GetLast(p); // Let provider collect options / handle itself. var args = p.ShowOptionsAndBuildArgs(this, last); if (args == null) return; // canceled or fully handled inside provider if (p.IsExternalTool) { // External: resolve/browse EXE as before var exePath = ToolHelpers.ResolveToolPath(last.LastExePath, p.ExactExeNames, p.WildcardExePatterns); if (exePath == null) { using (var ofd = new OpenFileDialog { Title = $"Select {p.DisplayName} executable", Filter = "Executables (*.exe)|*.exe|All files (*.*)|*.*" }) { try { var downloads = System.IO.Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads"); if (System.IO.Directory.Exists(downloads)) ofd.InitialDirectory = downloads; } catch { } if (ofd.ShowDialog(this) != DialogResult.OK) return; exePath = ofd.FileName; last.LastExePath = exePath; } } ToolHelpers.Run(exePath, args, asAdmin: true); } else { // Native/built-in: run by command name without file picker (UseShellExecute=true) var cmd = (p.ExactExeNames != null && p.ExactExeNames.Length > 0) ? p.ExactExeNames[0] // e.g., "systemreset.exe" : null; if (string.IsNullOrEmpty(cmd)) { MessageBox.Show(this, "No command specified for native provider.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } ToolHelpers.Run(cmd, args, asAdmin: true); } } private void OpenHomepage() { var p = SelectedProvider; if (p == null) return; if (string.IsNullOrEmpty(p.HomepageUrl)) { MessageBox.Show(this, $"No homepage is defined for {p.DisplayName}.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } ToolHelpers.OpenUri(p.HomepageUrl); } private async Task DownloadProviderAsync() { var p = SelectedProvider; if (p == null) return; if (string.IsNullOrEmpty(p.DirectDownloadUrl)) { MessageBox.Show(this, $"Direct download is not available for {p.DisplayName}. Please visit the homepage instead.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } var fileName = p.Id + ".exe"; // simple default filename await ToolHelpers.DownloadAsync(this, p.DirectDownloadUrl, fileName); } // -------------------------------------------------------------------------------- // Finds a provider by its Id in the already-registered _providers list (Quick-click) // -------------------------------------------------------------------------------- private IInstallProvider FindProviderById(string id) { if (string.IsNullOrEmpty(id)) return null; foreach (var p in _providers) if (string.Equals(p.Id, id, StringComparison.OrdinalIgnoreCase)) return p; return null; } // Selects the provider in the combo (for UI consistency) and runs it via existing pipeline private async System.Threading.Tasks.Task RunQuickAsync(string providerId) { var p = FindProviderById(providerId); if (p == null) { MessageBox.Show(this, $"Provider '{providerId}' not available.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } // Select in UI so hint/badges update if (cboSource != null) cboSource.SelectedItem = p; // Reuse your normal execution path await RunSelectedAsync(); } // -------------------------------------------------------------------------------- // Wires the search box to filter the providers list on-the-fly // -------------------------------------------------------------------------------- private void HookSearchBox() { if (textProviderSearch == null || cboSource == null) return; textProviderSearch.TextChanged += (s, e) => { var q = textProviderSearch.Text?.Trim() ?? string.Empty; FilterProviders(q); }; } // Filters the combo by DisplayName/Id/Hint (case-insensitive). private void FilterProviders(string query) { if (cboSource == null) return; // filtered view on the fly var list = string.IsNullOrEmpty(query) ? _providers : _providers.FindAll(p => (p.DisplayName ?? "").IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0 || (p.Id ?? "").IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0 || (p.Hint ?? "").IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0); // Rebind cboSource.DataSource = null; cboSource.DataSource = list; cboSource.DisplayMember = nameof(IInstallProvider.DisplayName); if (cboSource.Items.Count > 0) cboSource.SelectedIndex = 0; } private void textProviderSearch_Click(object sender, EventArgs e) { textProviderSearch.Clear(); } } }