mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-22 17:24:27 +08:00
changed.更了好多
This commit is contained in:
@@ -3,16 +3,20 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:views="clr-namespace:LanMountainDesktop.Launcher.Views"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:fi="using:FluentIcons.Avalonia"
|
||||
mc:Ignorable="d"
|
||||
x:Class="LanMountainDesktop.Launcher.Views.ErrorWindow"
|
||||
x:DataType="views:ErrorWindow"
|
||||
Title="LanMountain Desktop"
|
||||
Width="560"
|
||||
Height="320"
|
||||
Width="760"
|
||||
Height="460"
|
||||
MinWidth="640"
|
||||
MinHeight="420"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#111318"
|
||||
TransparencyLevelHint="None"
|
||||
Background="{DynamicResource SolidBackgroundFillColorBaseBrush}"
|
||||
TransparencyLevelHint="Mica, AcrylicBlur, None"
|
||||
Icon="/Assets/logo.ico">
|
||||
<Design.DataContext>
|
||||
<views:ErrorWindow />
|
||||
@@ -20,79 +24,128 @@
|
||||
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<Grid Grid.Row="0"
|
||||
Margin="24"
|
||||
Margin="28,24,28,20"
|
||||
RowDefinitions="Auto,Auto,*"
|
||||
ColumnDefinitions="Auto,*">
|
||||
<Border x:Name="ErrorIconBorder"
|
||||
Grid.Column="0"
|
||||
Width="52"
|
||||
Height="52"
|
||||
Margin="0,4,18,0"
|
||||
Background="#2B161A"
|
||||
CornerRadius="26"
|
||||
Width="56"
|
||||
Height="56"
|
||||
Margin="0,0,18,0"
|
||||
Background="{DynamicResource SystemFillColorCriticalBackgroundBrush}"
|
||||
CornerRadius="28"
|
||||
VerticalAlignment="Top">
|
||||
<TextBlock Text="!"
|
||||
FontSize="24"
|
||||
FontWeight="Bold"
|
||||
Foreground="#FFB4AB"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
<fi:SymbolIcon Symbol="ErrorCircle"
|
||||
IconVariant="Regular"
|
||||
FontSize="28"
|
||||
Foreground="{DynamicResource SystemFillColorCriticalBrush}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Border>
|
||||
|
||||
<StackPanel Grid.Column="1"
|
||||
Spacing="10">
|
||||
Spacing="8">
|
||||
<TextBlock x:Name="TitleText"
|
||||
Text="Launcher could not confirm startup"
|
||||
FontSize="20"
|
||||
FontSize="22"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#F6F7FB"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock x:Name="ErrorMessageText"
|
||||
Text="LanMountain Desktop did not reach the expected startup state."
|
||||
FontSize="14"
|
||||
Foreground="#D2D7E1"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap"
|
||||
LineHeight="22" />
|
||||
|
||||
<TextBlock x:Name="SuggestionText"
|
||||
Text="You can inspect logs, retry when the old process is gone, or reactivate the current instance."
|
||||
FontSize="13"
|
||||
Foreground="#9BA5B7"
|
||||
TextWrapping="Wrap"
|
||||
LineHeight="20" />
|
||||
</StackPanel>
|
||||
|
||||
<ui:FAInfoBar x:Name="SuggestionInfoBar"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="0,20,0,14"
|
||||
IsOpen="True"
|
||||
IsClosable="False"
|
||||
Severity="Warning"
|
||||
Title="Startup recovery"
|
||||
Message="You can inspect logs, wait for the current process, or activate the running desktop instance.">
|
||||
<ui:FAInfoBar.IconSource>
|
||||
<ui:FAFontIconSource Glyph="󰊈"
|
||||
FontFamily="avares://fluenticons.resources.avalonia/Assets#Seagull Fluent Icons" />
|
||||
</ui:FAInfoBar.IconSource>
|
||||
</ui:FAInfoBar>
|
||||
|
||||
<Expander Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Header="Diagnostic details"
|
||||
IsExpanded="True">
|
||||
<TextBox x:Name="ErrorDetailsTextBox"
|
||||
Margin="0,10,0,0"
|
||||
MinHeight="150"
|
||||
MaxHeight="190"
|
||||
AcceptsReturn="True"
|
||||
TextWrapping="Wrap"
|
||||
IsReadOnly="True"
|
||||
BorderThickness="0"
|
||||
FontSize="12"
|
||||
Text="Stage: launch
Code: unknown"
|
||||
VerticalContentAlignment="Top" />
|
||||
</Expander>
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="1"
|
||||
Padding="24,16"
|
||||
Background="#171A21">
|
||||
<Grid ColumnDefinitions="*,Auto,Auto,Auto"
|
||||
ColumnSpacing="8">
|
||||
<Button x:Name="OpenLogButton"
|
||||
Grid.Column="0"
|
||||
Content="Open Logs"
|
||||
MinWidth="108"
|
||||
Height="34"
|
||||
HorizontalAlignment="Left" />
|
||||
Padding="18,14"
|
||||
Background="{DynamicResource LayerOnMicaBaseAltFillColorDefaultBrush}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto"
|
||||
ColumnSpacing="12">
|
||||
<StackPanel Grid.Column="0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<Button x:Name="OpenLogButton"
|
||||
MinWidth="112"
|
||||
Height="34">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<fi:SymbolIcon Symbol="FolderOpen" IconVariant="Regular" FontSize="16"/>
|
||||
<TextBlock Text="Open Logs"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button x:Name="SecondaryActionButton"
|
||||
Grid.Column="1"
|
||||
Content="Wait"
|
||||
MinWidth="108"
|
||||
Height="34"
|
||||
IsVisible="False" />
|
||||
<Button x:Name="CopyDetailsButton"
|
||||
MinWidth="100"
|
||||
Height="34">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<fi:SymbolIcon Symbol="Copy" IconVariant="Regular" FontSize="16"/>
|
||||
<TextBlock Text="Copy"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
<Button x:Name="ExitButton"
|
||||
Grid.Column="2"
|
||||
Content="Exit"
|
||||
MinWidth="90"
|
||||
Height="34" />
|
||||
<StackPanel Grid.Column="2"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<Button x:Name="SecondaryActionButton"
|
||||
Content="Wait"
|
||||
MinWidth="96"
|
||||
Height="34"
|
||||
IsVisible="False" />
|
||||
|
||||
<Button x:Name="PrimaryActionButton"
|
||||
Grid.Column="3"
|
||||
Content="Retry"
|
||||
MinWidth="108"
|
||||
Height="34" />
|
||||
<Button x:Name="ExitButton"
|
||||
MinWidth="92"
|
||||
Height="34">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<fi:SymbolIcon Symbol="Dismiss" IconVariant="Regular" FontSize="16"/>
|
||||
<TextBlock Text="Exit"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button x:Name="PrimaryActionButton"
|
||||
Classes="accent"
|
||||
Content="Retry"
|
||||
MinWidth="112"
|
||||
Height="34" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Diagnostics;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Input.Platform;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using LanMountainDesktop.Launcher.Services;
|
||||
|
||||
namespace LanMountainDesktop.Launcher.Views;
|
||||
@@ -33,9 +35,21 @@ public partial class ErrorWindow : Window
|
||||
|
||||
public void SetErrorMessage(string message)
|
||||
{
|
||||
var normalizedMessage = string.IsNullOrWhiteSpace(message)
|
||||
? "LanMountain Desktop did not reach the expected startup state."
|
||||
: message.Trim();
|
||||
var firstLine = normalizedMessage
|
||||
.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)
|
||||
.FirstOrDefault() ?? normalizedMessage;
|
||||
|
||||
if (this.FindControl<TextBlock>("ErrorMessageText") is { } errorText)
|
||||
{
|
||||
errorText.Text = message;
|
||||
errorText.Text = firstLine;
|
||||
}
|
||||
|
||||
if (this.FindControl<TextBox>("ErrorDetailsTextBox") is { } detailsTextBox)
|
||||
{
|
||||
detailsTextBox.Text = normalizedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +134,11 @@ public partial class ErrorWindow : Window
|
||||
{
|
||||
openLogButton.Click += OnOpenLogClick;
|
||||
}
|
||||
|
||||
if (this.FindControl<Button>("CopyDetailsButton") is { } copyDetailsButton)
|
||||
{
|
||||
copyDetailsButton.Click += OnCopyDetailsClick;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyActionLayout(
|
||||
@@ -138,9 +157,9 @@ public partial class ErrorWindow : Window
|
||||
titleText.Text = title;
|
||||
}
|
||||
|
||||
if (this.FindControl<TextBlock>("SuggestionText") is { } suggestionText)
|
||||
if (this.FindControl<FAInfoBar>("SuggestionInfoBar") is { } suggestionInfoBar)
|
||||
{
|
||||
suggestionText.Text = suggestion;
|
||||
suggestionInfoBar.Message = suggestion;
|
||||
}
|
||||
|
||||
if (this.FindControl<Button>("PrimaryActionButton") is { } primaryButton)
|
||||
@@ -243,6 +262,28 @@ public partial class ErrorWindow : Window
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async void OnCopyDetailsClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var details = this.FindControl<TextBox>("ErrorDetailsTextBox")?.Text;
|
||||
if (string.IsNullOrWhiteSpace(details))
|
||||
{
|
||||
details = this.FindControl<TextBlock>("ErrorMessageText")?.Text;
|
||||
}
|
||||
|
||||
var clipboard = TopLevel.GetTopLevel(this)?.Clipboard;
|
||||
if (clipboard is not null && !string.IsNullOrWhiteSpace(details))
|
||||
{
|
||||
await clipboard.SetTextAsync(details);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[ErrorWindow] Failed to copy diagnostics: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void ScanDevPaths()
|
||||
{
|
||||
var executable = OperatingSystem.IsWindows() ? "LanMountainDesktop.exe" : "LanMountainDesktop";
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:views="clr-namespace:LanMountainDesktop.Launcher.Views"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:fi="using:FluentIcons.Avalonia"
|
||||
mc:Ignorable="d"
|
||||
x:Class="LanMountainDesktop.Launcher.Views.MultiInstancePromptWindow"
|
||||
x:DataType="views:MultiInstancePromptWindow"
|
||||
Title="LanMountain Desktop"
|
||||
Width="620"
|
||||
Height="360"
|
||||
MinWidth="560"
|
||||
MinHeight="330"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="{DynamicResource SolidBackgroundFillColorBaseBrush}"
|
||||
TransparencyLevelHint="Mica, AcrylicBlur, None"
|
||||
Icon="/Assets/logo.ico">
|
||||
<Design.DataContext>
|
||||
<views:MultiInstancePromptWindow />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<Grid Grid.Row="0"
|
||||
Margin="28,26,28,20"
|
||||
RowDefinitions="Auto,Auto,*"
|
||||
ColumnDefinitions="Auto,*">
|
||||
<Border Grid.Column="0"
|
||||
Width="52"
|
||||
Height="52"
|
||||
Margin="0,0,18,0"
|
||||
Background="{DynamicResource SystemFillColorAttentionBackgroundBrush}"
|
||||
CornerRadius="26"
|
||||
VerticalAlignment="Top">
|
||||
<fi:SymbolIcon Symbol="Desktop"
|
||||
IconVariant="Regular"
|
||||
FontSize="26"
|
||||
Foreground="{DynamicResource SystemFillColorAttentionBrush}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Border>
|
||||
|
||||
<StackPanel Grid.Column="1"
|
||||
Spacing="8">
|
||||
<TextBlock Text="LanMountain Desktop is already running"
|
||||
FontSize="22"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock x:Name="MessageText"
|
||||
Text="Launcher found an existing desktop instance and did not start another process."
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap"
|
||||
LineHeight="22" />
|
||||
</StackPanel>
|
||||
|
||||
<ui:FAInfoBar Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="0,22,0,14"
|
||||
IsOpen="True"
|
||||
IsClosable="False"
|
||||
Severity="Informational"
|
||||
Title="Repeated launch"
|
||||
Message="Your current setting is to show this prompt without opening the desktop automatically.">
|
||||
<ui:FAInfoBar.IconSource>
|
||||
<ui:FAFontIconSource Glyph="󰊈"
|
||||
FontFamily="avares://fluenticons.resources.avalonia/Assets#Seagull Fluent Icons" />
|
||||
</ui:FAInfoBar.IconSource>
|
||||
</ui:FAInfoBar>
|
||||
|
||||
<TextBlock x:Name="DetailsText"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap"
|
||||
Text="No second Host process was created." />
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="1"
|
||||
Padding="18,14"
|
||||
Background="{DynamicResource LayerOnMicaBaseAltFillColorDefaultBrush}">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<Button x:Name="CopyDetailsButton"
|
||||
Grid.Column="0"
|
||||
MinWidth="104"
|
||||
Height="34"
|
||||
HorizontalAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<fi:SymbolIcon Symbol="Copy" IconVariant="Regular" FontSize="16"/>
|
||||
<TextBlock Text="Copy"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<StackPanel Grid.Column="1"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<Button x:Name="CloseButton"
|
||||
MinWidth="92"
|
||||
Height="34">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<fi:SymbolIcon Symbol="Dismiss" IconVariant="Regular" FontSize="16"/>
|
||||
<TextBlock Text="Close"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button x:Name="OpenDesktopButton"
|
||||
Classes="accent"
|
||||
MinWidth="136"
|
||||
Height="34">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<fi:SymbolIcon Symbol="ArrowRight" IconVariant="Regular" FontSize="16"/>
|
||||
<TextBlock Text="Open desktop"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,76 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input.Platform;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace LanMountainDesktop.Launcher.Views;
|
||||
|
||||
public partial class MultiInstancePromptWindow : Window
|
||||
{
|
||||
private readonly TaskCompletionSource<MultiInstancePromptResult> _completionSource =
|
||||
new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
private string _details = "LanMountain Desktop is already running.";
|
||||
|
||||
public MultiInstancePromptWindow()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
Loaded += OnLoaded;
|
||||
Closed += (_, _) => _completionSource.TrySetResult(MultiInstancePromptResult.Close);
|
||||
}
|
||||
|
||||
public Task<MultiInstancePromptResult> WaitForChoiceAsync() => _completionSource.Task;
|
||||
|
||||
public void SetDetails(int processId, string shellState)
|
||||
{
|
||||
_details = $"Existing host PID: {processId}\nShell state: {shellState}\nNo second Host process was created.";
|
||||
|
||||
if (this.FindControl<TextBlock>("DetailsText") is { } detailsText)
|
||||
{
|
||||
detailsText.Text = _details;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (this.FindControl<Button>("CloseButton") is { } closeButton)
|
||||
{
|
||||
closeButton.Click += (_, _) => Complete(MultiInstancePromptResult.Close);
|
||||
}
|
||||
|
||||
if (this.FindControl<Button>("OpenDesktopButton") is { } openDesktopButton)
|
||||
{
|
||||
openDesktopButton.Click += (_, _) => Complete(MultiInstancePromptResult.OpenDesktop);
|
||||
}
|
||||
|
||||
if (this.FindControl<Button>("CopyDetailsButton") is { } copyDetailsButton)
|
||||
{
|
||||
copyDetailsButton.Click += OnCopyDetailsClick;
|
||||
}
|
||||
}
|
||||
|
||||
private void Complete(MultiInstancePromptResult result)
|
||||
{
|
||||
_completionSource.TrySetResult(result);
|
||||
Close();
|
||||
}
|
||||
|
||||
private async void OnCopyDetailsClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (TopLevel.GetTopLevel(this)?.Clipboard is IClipboard clipboard)
|
||||
{
|
||||
await clipboard.SetTextAsync(_details);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum MultiInstancePromptResult
|
||||
{
|
||||
Close,
|
||||
OpenDesktop
|
||||
}
|
||||
Reference in New Issue
Block a user