diff --git a/DevDrive.csproj b/DevDrive.csproj index b94b7ed..ce18578 100644 --- a/DevDrive.csproj +++ b/DevDrive.csproj @@ -3,6 +3,7 @@ WinExe net8.0-windows + true enable enable x64 diff --git a/DevDriveConfig.cs b/DevDriveConfig.cs index f08a759..6fc0f11 100644 --- a/DevDriveConfig.cs +++ b/DevDriveConfig.cs @@ -36,6 +36,12 @@ public class DevDriveConfig /// [JsonPropertyName("paths")] public List Paths { get; set; } = []; + + /// + /// List of applications to prompt for launch after mounting. + /// + [JsonPropertyName("startupApps")] + public List StartupApps { get; set; } = []; } /// @@ -55,3 +61,39 @@ public class SymlinkEntry [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; } + +/// +/// Represents an application to launch after mounting. +/// +public class StartupApp +{ + /// + /// Display name shown in the dialog. + /// + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// + /// Path to the executable. + /// + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// + /// Command line arguments (optional). + /// + [JsonPropertyName("arguments")] + public string Arguments { get; set; } = string.Empty; + + /// + /// Working directory (optional, defaults to executable's directory). + /// + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; + + /// + /// Whether this app is checked by default in the dialog. + /// + [JsonPropertyName("checkedByDefault")] + public bool CheckedByDefault { get; set; } = true; +} diff --git a/Program.cs b/Program.cs index 6cb9a82..1b75839 100644 --- a/Program.cs +++ b/Program.cs @@ -301,6 +301,12 @@ public static class Program MountDrive(); SyncSymlinksFromConfig(config); _lastConfig = config; + + if (config.StartupApps.Count > 0) + { + var driveName = config.DriveName ?? "Dev Drive"; + Task.Run(() => StartupDialog.ShowIfNeeded(config.StartupApps, driveName)); + } } } } diff --git a/StartupDialog.cs b/StartupDialog.cs new file mode 100644 index 0000000..6d92cd9 --- /dev/null +++ b/StartupDialog.cs @@ -0,0 +1,201 @@ +using System.Diagnostics; +using System.Runtime.Versioning; + +namespace DevDrive; + +/// +/// Dialog that prompts the user to select which startup apps to launch. +/// +[SupportedOSPlatform("windows")] +public class StartupDialog : Form +{ + private readonly List _apps; + private readonly List _checkboxes = []; + private readonly Button _launchButton; + private readonly Button _cancelButton; + + /// + /// Creates a new startup dialog for the given apps. + /// + /// List of startup apps to display. + /// Name of the drive for the title. + public StartupDialog(List apps, string driveName) + { + _apps = apps; + + Text = $"{driveName} - Startup Apps"; + FormBorderStyle = FormBorderStyle.FixedDialog; + StartPosition = FormStartPosition.CenterScreen; + MaximizeBox = false; + MinimizeBox = false; + AutoScaleMode = AutoScaleMode.Dpi; + + var padding = 16; + var checkboxHeight = 28; + var buttonHeight = 32; + var buttonWidth = 100; + + var contentHeight = padding + (_apps.Count * checkboxHeight) + padding + buttonHeight + padding; + var contentWidth = 350; + + ClientSize = new Size(contentWidth, contentHeight); + + var yPos = padding; + + foreach (var app in _apps) + { + var checkbox = new CheckBox + { + Text = app.Name, + Tag = app, + Checked = app.CheckedByDefault, + Location = new Point(padding, yPos), + Size = new Size(contentWidth - (padding * 2), checkboxHeight), + Font = new Font("Segoe UI", 10) + }; + + _checkboxes.Add(checkbox); + Controls.Add(checkbox); + yPos += checkboxHeight; + } + + yPos += padding; + + _launchButton = new Button + { + Text = "Launch", + DialogResult = DialogResult.OK, + Location = new Point(contentWidth - padding - buttonWidth - 8 - buttonWidth, yPos), + Size = new Size(buttonWidth, buttonHeight), + Font = new Font("Segoe UI", 9) + }; + _launchButton.Click += OnLaunchClick; + Controls.Add(_launchButton); + + _cancelButton = new Button + { + Text = "Skip", + DialogResult = DialogResult.Cancel, + Location = new Point(contentWidth - padding - buttonWidth, yPos), + Size = new Size(buttonWidth, buttonHeight), + Font = new Font("Segoe UI", 9) + }; + Controls.Add(_cancelButton); + + AcceptButton = _launchButton; + CancelButton = _cancelButton; + } + + private void OnLaunchClick(object? sender, EventArgs e) + { + LaunchSelectedApps(); + } + + /// + /// Launches all selected apps. + /// + private void LaunchSelectedApps() + { + foreach (var checkbox in _checkboxes) + { + if (!checkbox.Checked) + { + continue; + } + + if (checkbox.Tag is not StartupApp app) + { + continue; + } + + try + { + var startInfo = new ProcessStartInfo + { + FileName = Environment.ExpandEnvironmentVariables(app.Path), + UseShellExecute = true + }; + + if (!string.IsNullOrWhiteSpace(app.Arguments)) + { + startInfo.Arguments = Environment.ExpandEnvironmentVariables(app.Arguments); + } + + if (!string.IsNullOrWhiteSpace(app.WorkingDirectory)) + { + startInfo.WorkingDirectory = Environment.ExpandEnvironmentVariables(app.WorkingDirectory); + } + + Process.Start(startInfo); + Console.WriteLine($"[DevDrive] Launched: {app.Name}"); + } + catch (Exception ex) + { + Console.WriteLine($"[DevDrive] Failed to launch {app.Name}: {ex.Message}"); + } + } + } + + /// + /// Shows the startup dialog if there are apps to display. + /// + /// List of startup apps. + /// Name of the drive. + public static void ShowIfNeeded(List apps, string driveName) + { + if (apps.Count == 0) + { + return; + } + + if (apps.Count == 1) + { + var app = apps[0]; + var result = MessageBox.Show( + $"Launch {app.Name}?", + $"{driveName} - Startup", + MessageBoxButtons.YesNo, + MessageBoxIcon.Question + ); + + if (result == DialogResult.Yes) + { + LaunchSingleApp(app); + } + return; + } + + Application.EnableVisualStyles(); + using var dialog = new StartupDialog(apps, driveName); + dialog.ShowDialog(); + } + + private static void LaunchSingleApp(StartupApp app) + { + try + { + var startInfo = new ProcessStartInfo + { + FileName = Environment.ExpandEnvironmentVariables(app.Path), + UseShellExecute = true + }; + + if (!string.IsNullOrWhiteSpace(app.Arguments)) + { + startInfo.Arguments = Environment.ExpandEnvironmentVariables(app.Arguments); + } + + if (!string.IsNullOrWhiteSpace(app.WorkingDirectory)) + { + startInfo.WorkingDirectory = Environment.ExpandEnvironmentVariables(app.WorkingDirectory); + } + + Process.Start(startInfo); + Console.WriteLine($"[DevDrive] Launched: {app.Name}"); + } + catch (Exception ex) + { + Console.WriteLine($"[DevDrive] Failed to launch {app.Name}: {ex.Message}"); + } + } +}