Add startup application support and dialog for user prompts
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ public class DevDriveConfig
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("paths")]
|
[JsonPropertyName("paths")]
|
||||||
public List<SymlinkEntry> Paths { get; set; } = [];
|
public List<SymlinkEntry> Paths { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of applications to prompt for launch after mounting.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("startupApps")]
|
||||||
|
public List<StartupApp> StartupApps { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -55,3 +61,39 @@ public class SymlinkEntry
|
|||||||
[JsonPropertyName("path")]
|
[JsonPropertyName("path")]
|
||||||
public string Path { get; set; } = string.Empty;
|
public string Path { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an application to launch after mounting.
|
||||||
|
/// </summary>
|
||||||
|
public class StartupApp
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Display name shown in the dialog.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path to the executable.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("path")]
|
||||||
|
public string Path { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command line arguments (optional).
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("arguments")]
|
||||||
|
public string Arguments { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Working directory (optional, defaults to executable's directory).
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("workingDirectory")]
|
||||||
|
public string WorkingDirectory { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this app is checked by default in the dialog.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("checkedByDefault")]
|
||||||
|
public bool CheckedByDefault { get; set; } = true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -301,6 +301,12 @@ public static class Program
|
|||||||
MountDrive();
|
MountDrive();
|
||||||
SyncSymlinksFromConfig(config);
|
SyncSymlinksFromConfig(config);
|
||||||
_lastConfig = config;
|
_lastConfig = config;
|
||||||
|
|
||||||
|
if (config.StartupApps.Count > 0)
|
||||||
|
{
|
||||||
|
var driveName = config.DriveName ?? "Dev Drive";
|
||||||
|
Task.Run(() => StartupDialog.ShowIfNeeded(config.StartupApps, driveName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
201
StartupDialog.cs
Normal file
201
StartupDialog.cs
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
|
namespace DevDrive;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dialog that prompts the user to select which startup apps to launch.
|
||||||
|
/// </summary>
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
public class StartupDialog : Form
|
||||||
|
{
|
||||||
|
private readonly List<StartupApp> _apps;
|
||||||
|
private readonly List<CheckBox> _checkboxes = [];
|
||||||
|
private readonly Button _launchButton;
|
||||||
|
private readonly Button _cancelButton;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new startup dialog for the given apps.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apps">List of startup apps to display.</param>
|
||||||
|
/// <param name="driveName">Name of the drive for the title.</param>
|
||||||
|
public StartupDialog(List<StartupApp> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Launches all selected apps.
|
||||||
|
/// </summary>
|
||||||
|
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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the startup dialog if there are apps to display.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apps">List of startup apps.</param>
|
||||||
|
/// <param name="driveName">Name of the drive.</param>
|
||||||
|
public static void ShowIfNeeded(List<StartupApp> 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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user