using System.Diagnostics; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using LanMountainDesktop.Launcher.Services; namespace LanMountainDesktop.Launcher.Views; public partial class ErrorWindow : Window { private const int DebugModeClickThreshold = 5; private readonly TaskCompletionSource _completionSource = new(TaskCreationOptions.RunContinuationsAsynchronously); private int _iconClickCount; private bool _isDebugMode; private bool _devModeEnabled; private string? _customHostPath; private ErrorWindowResult _primaryAction = ErrorWindowResult.Retry; private ErrorWindowResult? _secondaryAction; public ErrorWindow() { AvaloniaXamlLoader.Load(this); _devModeEnabled = LoadDevModeStateInternal(); _customHostPath = LoadCustomHostPathInternal(); Loaded += OnWindowLoaded; Closed += (_, _) => _completionSource.TrySetResult(ErrorWindowResult.Exit); ConfigureForGenericFailure(allowRetry: true); } public void SetErrorMessage(string message) { if (this.FindControl("ErrorMessageText") is { } errorText) { errorText.Text = message; } } public void SetDebugMode(bool isDebugMode) { _isDebugMode = isDebugMode; if (isDebugMode && this.FindControl("TitleText") is { } titleText) { titleText.Text = "[Debug] Launcher error"; } } public void ConfigureForHostNotFound() { ApplyActionLayout( title: "Launcher could not find the desktop executable", suggestion: "Pick another executable in debug mode, inspect logs, or retry after fixing the deployment path.", primaryLabel: "Retry", primaryAction: ErrorWindowResult.Retry, secondaryLabel: null, secondaryAction: null); } public void ConfigureForGenericFailure(bool allowRetry) { ApplyActionLayout( title: "Launcher could not confirm startup", suggestion: allowRetry ? "Inspect logs, then retry once the previous startup attempt has fully finished." : "Inspect logs or exit. Launcher will avoid creating another desktop process while the old one is still running.", primaryLabel: allowRetry ? "Retry" : "Activate", primaryAction: allowRetry ? ErrorWindowResult.Retry : ErrorWindowResult.ActivateExisting, secondaryLabel: allowRetry ? null : "Wait", secondaryAction: allowRetry ? null : ErrorWindowResult.ContinueWaiting); } public void ConfigureForRunningHostFailure(int? hostPid) { var pidHint = hostPid is > 0 ? $" Current host PID: {hostPid}." : string.Empty; ApplyActionLayout( title: "Startup is still pending", suggestion: $"The desktop process is still running, so Launcher will not start a second instance.{pidHint}", primaryLabel: "Activate", primaryAction: ErrorWindowResult.ActivateExisting, secondaryLabel: "Wait", secondaryAction: ErrorWindowResult.ContinueWaiting); } public string? GetCustomHostPath() => _customHostPath; public bool IsDevModeEnabled() => _devModeEnabled; public Task WaitForChoiceAsync() => _completionSource.Task; public static bool CheckDevModeEnabled() => LoadDevModeStateInternal(); public static string? GetSavedCustomHostPath() => LoadCustomHostPathInternal(); private void OnWindowLoaded(object? sender, RoutedEventArgs e) { if (this.FindControl("ErrorIconBorder") is { } errorIconBorder) { errorIconBorder.PointerPressed += OnErrorIconClick; } if (this.FindControl