Files
Flyoobe/Flyoobe/InstallView/InstallControlView.cs
T
2025-09-04 18:10:14 +02:00

345 lines
13 KiB
C#

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<IInstallProvider> _providers = new List<IInstallProvider>();
// Store last selections (ISO/exe) per provider ID
private readonly Dictionary<string, LastSelections> _lastByProvider =
new Dictionary<string, LastSelections>(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();
}
}
}