mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-22 17:24:27 +08:00
feat.数字时钟,白板功能修复
This commit is contained in:
@@ -1,9 +1,59 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sty="using:FluentAvalonia.Styling"
|
||||
xmlns:fi="using:FluentIcons.Avalonia"
|
||||
x:Class="LanMountainDesktop.AirAppHost.AirApp"
|
||||
RequestedThemeVariant="Default">
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<sty:FluentAvaloniaTheme />
|
||||
|
||||
<Style Selector="Window">
|
||||
<Setter Property="FontFamily" Value="{DynamicResource AppFontFamily}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="UserControl">
|
||||
<Setter Property="FontFamily" Value="{DynamicResource AppFontFamily}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="FontFeatures" Value="tnum" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="SelectableTextBlock">
|
||||
<Setter Property="FontFeatures" Value="tnum" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ScrollViewer">
|
||||
<Setter Property="ScrollViewer.IsScrollInertiaEnabled" Value="False" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="fi|SymbolIcon">
|
||||
<Setter Property="Foreground" Value="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="fi|FluentIcon">
|
||||
<Setter Property="Foreground" Value="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="fi|SymbolIcon.icon-s, fi|FluentIcon.icon-s">
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="fi|SymbolIcon.icon-m, fi|FluentIcon.icon-m">
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="fi|SymbolIcon.icon-l, fi|FluentIcon.icon-l">
|
||||
<Setter Property="FontSize" Value="20" />
|
||||
</Style>
|
||||
</Application.Styles>
|
||||
|
||||
<Application.Resources>
|
||||
|
||||
@@ -6,7 +6,8 @@ public sealed record AirAppLaunchOptions(
|
||||
string? SourceComponentId,
|
||||
string? SourcePlacementId,
|
||||
string? LauncherPipeName,
|
||||
string? InstanceKey)
|
||||
string? InstanceKey,
|
||||
string? DataRoot)
|
||||
{
|
||||
public const string WorldClockAppId = "world-clock";
|
||||
public const string WhiteboardAppId = "whiteboard";
|
||||
@@ -28,6 +29,19 @@ public sealed record AirAppLaunchOptions(
|
||||
continue;
|
||||
}
|
||||
|
||||
var equalsIndex = key.IndexOf('=');
|
||||
if (equalsIndex > 0)
|
||||
{
|
||||
var inlineValue = key[(equalsIndex + 1)..];
|
||||
key = key[..equalsIndex].Trim();
|
||||
if (!string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
values[key] = inlineValue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index + 1 < args.Count && !args[index + 1].StartsWith("--", StringComparison.Ordinal))
|
||||
{
|
||||
values[key] = args[index + 1];
|
||||
@@ -45,7 +59,8 @@ public sealed record AirAppLaunchOptions(
|
||||
GetOptionalValue(values, "source-component-id"),
|
||||
GetOptionalValue(values, "source-placement-id"),
|
||||
GetOptionalValue(values, "launcher-pipe"),
|
||||
GetOptionalValue(values, "instance-key"));
|
||||
GetOptionalValue(values, "instance-key"),
|
||||
GetOptionalValue(values, "data-root"));
|
||||
}
|
||||
|
||||
private static string GetValue(IReadOnlyDictionary<string, string> values, string key, string fallback)
|
||||
|
||||
@@ -14,6 +14,7 @@ public sealed partial class AirAppWindow : Window
|
||||
{
|
||||
private readonly AirAppLaunchOptions _options;
|
||||
private readonly AirAppWindowDescriptor _descriptor;
|
||||
private WhiteboardWidget? _whiteboardWidget;
|
||||
private string _instanceKey = string.Empty;
|
||||
|
||||
public AirAppWindow()
|
||||
@@ -117,6 +118,7 @@ public sealed partial class AirAppWindow : Window
|
||||
? 4
|
||||
: 2;
|
||||
var widget = new WhiteboardWidget(baseWidthCells);
|
||||
_whiteboardWidget = widget;
|
||||
widget.SetComponentPlacementContext(componentId, _options.SourcePlacementId);
|
||||
widget.SetSurfaceMode(
|
||||
WhiteboardWidgetSurfaceMode.AirApp,
|
||||
@@ -127,6 +129,9 @@ public sealed partial class AirAppWindow : Window
|
||||
});
|
||||
|
||||
ContentHost.Content = widget;
|
||||
AppLogger.Info(
|
||||
"AirAppWindow",
|
||||
$"Whiteboard content created. ComponentId='{componentId}'; PlacementId='{_options.SourcePlacementId ?? string.Empty}'.");
|
||||
}
|
||||
|
||||
protected override void OnOpened(EventArgs e)
|
||||
@@ -144,6 +149,7 @@ public sealed partial class AirAppWindow : Window
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
SaveAndDisposeWhiteboard();
|
||||
_ = UnregisterWithLauncherAsync();
|
||||
base.OnClosed(e);
|
||||
}
|
||||
@@ -158,9 +164,45 @@ public sealed partial class AirAppWindow : Window
|
||||
|
||||
private void OnCloseClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
SaveWhiteboard();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void SaveAndDisposeWhiteboard()
|
||||
{
|
||||
var widget = _whiteboardWidget;
|
||||
if (widget is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SaveWhiteboard();
|
||||
if (ContentHost.Content == widget)
|
||||
{
|
||||
ContentHost.Content = null;
|
||||
}
|
||||
|
||||
widget.Dispose();
|
||||
_whiteboardWidget = null;
|
||||
}
|
||||
|
||||
private void SaveWhiteboard()
|
||||
{
|
||||
if (_whiteboardWidget is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_whiteboardWidget.ForceSaveNote();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Warn("AirAppWindow", "Failed to force-save whiteboard before closing Air APP.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RegisterWithLauncherAsync()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_options.LauncherPipeName))
|
||||
|
||||
@@ -25,7 +25,11 @@ public sealed record AirAppWindowDescriptor(
|
||||
return Standard(
|
||||
"World Clock - Air APP",
|
||||
"World Clock",
|
||||
"Air APP");
|
||||
"Air APP",
|
||||
width: 360,
|
||||
height: 220,
|
||||
minWidth: 320,
|
||||
minHeight: 220);
|
||||
}
|
||||
|
||||
if (string.Equals(options.AppId, AirAppLaunchOptions.WhiteboardAppId, StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -25,5 +25,6 @@
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" />
|
||||
<PackageReference Include="FluentAvaloniaUI" />
|
||||
<PackageReference Include="FluentIcons.Avalonia" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Avalonia;
|
||||
using LanMountainDesktop.Services;
|
||||
|
||||
namespace LanMountainDesktop.AirAppHost;
|
||||
|
||||
@@ -7,8 +8,22 @@ internal static class Program
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
AppLogger.Initialize();
|
||||
AppDataPathProvider.Initialize(args);
|
||||
RegisterGlobalExceptionLogging();
|
||||
AppLogger.Info("AirAppHost", $"Starting. Args='{string.Join(" ", args)}'.");
|
||||
|
||||
try
|
||||
{
|
||||
BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
AppLogger.Info("AirAppHost", "Exited normally.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Critical("AirAppHost", "Unhandled startup exception.", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static AppBuilder BuildAvaloniaApp()
|
||||
@@ -18,4 +33,21 @@ internal static class Program
|
||||
.WithInterFont()
|
||||
.LogToTrace();
|
||||
}
|
||||
|
||||
private static void RegisterGlobalExceptionLogging()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += (_, e) =>
|
||||
{
|
||||
AppLogger.Critical(
|
||||
"AirAppHost",
|
||||
"Unhandled AppDomain exception.",
|
||||
e.ExceptionObject as Exception);
|
||||
};
|
||||
|
||||
TaskScheduler.UnobservedTaskException += (_, e) =>
|
||||
{
|
||||
AppLogger.Error("AirAppHost", "Unobserved task exception.", e.Exception);
|
||||
e.SetObserved();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,26 +2,26 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="LanMountainDesktop.AirAppHost.WorldClockAirAppView">
|
||||
<Grid RowDefinitions="*,Auto"
|
||||
Margin="24,8,24,24">
|
||||
Margin="18,0,18,16">
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="10">
|
||||
Spacing="8">
|
||||
<TextBlock x:Name="TimeTextBlock"
|
||||
Text="00:00:00"
|
||||
FontSize="58"
|
||||
FontSize="42"
|
||||
FontWeight="SemiBold"
|
||||
LetterSpacing="0"
|
||||
Foreground="{DynamicResource AirAppTitleTextBrush}"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="DateTextBlock"
|
||||
Text="0000-00-00"
|
||||
FontSize="17"
|
||||
FontSize="14"
|
||||
FontWeight="Medium"
|
||||
Foreground="{DynamicResource AirAppSecondaryTextBrush}"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="TimeZoneTextBlock"
|
||||
Text="Local Time"
|
||||
FontSize="13"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource AirAppSecondaryTextBrush}"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
Reference in New Issue
Block a user