Files
LanMountainDesktop/LanMountainDesktop/Views/Components/WhiteboardWidget.axaml
lincube 68ca532dc0 Move whiteboard persistence to file storage
Switch whiteboard note storage from legacy DB rows to per-note JSON files and add migration support. Update WhiteboardNoteSnapshot schema (version bump, viewport, canvas, expires, PathSvgData) and change IWhiteboardNotePersistenceService.SaveNote to return bool to surface write failures (e.g. read-only files). Implement file-based WhiteboardNotePersistenceService with legacy DB migration/cleanup, retention handling, and logging. Add comprehensive unit tests for persistence, stroke path builder, SVG import and viewport helper. Also add ThirdParty/DotNetCampus.InkCanvas project and reference it in the main csproj, and bump PostHog package to 2.6.0.
2026-05-06 00:45:33 +08:00

180 lines
8.9 KiB
XML

<UserControl 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:fi="using:FluentIcons.Avalonia"
xmlns:inking="using:DotNetCampus.Inking"
mc:Ignorable="d"
d:DesignWidth="240"
d:DesignHeight="480"
x:Class="LanMountainDesktop.Views.Components.WhiteboardWidget">
<Grid>
<Border x:Name="RootBorder"
Background="{DynamicResource AdaptiveSurfaceRaisedBrush}"
BorderBrush="{DynamicResource AdaptiveButtonBorderBrush}"
BorderThickness="1"
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
ClipToBounds="True"
Padding="12">
<Grid RowDefinitions="*,Auto"
RowSpacing="8">
<Border x:Name="CanvasBorder"
Grid.Row="0"
Background="#FFFFFF"
BorderBrush="#24000000"
BorderThickness="1"
CornerRadius="{DynamicResource DesignCornerRadiusSm}"
ClipToBounds="True">
<Grid x:Name="ViewportRoot"
ClipToBounds="True">
<Canvas x:Name="ViewportCanvas"
ClipToBounds="True">
<inking:InkCanvas x:Name="InkCanvas"
Width="1"
Height="1"
Canvas.Left="0"
Canvas.Top="0"
RenderTransformOrigin="0,0" />
</Canvas>
<Border x:Name="PanZoomInputLayer"
Background="Transparent"
IsHitTestVisible="False" />
</Grid>
</Border>
<Border x:Name="ToolbarBorder"
Grid.Row="1"
HorizontalAlignment="Center"
Background="#E6FFFFFF"
BorderBrush="#16000000"
BorderThickness="1"
CornerRadius="{DynamicResource DesignCornerRadiusSm}"
Padding="8,6">
<StackPanel x:Name="ToolbarButtonsPanel"
Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="8">
<Button x:Name="PenButton"
Width="30"
Height="30"
Padding="0"
CornerRadius="15"
ToolTip.Tip="Pen"
Click="OnPenButtonClick">
<fi:SymbolIcon x:Name="PenIcon"
Symbol="Pen"
IconVariant="Regular"
FontSize="14" />
</Button>
<Button x:Name="EraserButton"
Width="30"
Height="30"
Padding="0"
CornerRadius="15"
ToolTip.Tip="Eraser"
Click="OnEraserButtonClick">
<fi:SymbolIcon x:Name="EraserIcon"
Symbol="EraserTool"
IconVariant="Regular"
FontSize="14" />
</Button>
<Button x:Name="HandButton"
Width="30"
Height="30"
Padding="0"
CornerRadius="15"
ToolTip.Tip="Pan / Zoom"
Click="OnHandButtonClick">
<fi:SymbolIcon x:Name="HandIcon"
Symbol="HandDraw"
IconVariant="Regular"
FontSize="14" />
</Button>
<Button x:Name="ClearButton"
Width="30"
Height="30"
Padding="0"
CornerRadius="15"
ToolTip.Tip="Clear"
Click="OnClearButtonClick">
<fi:SymbolIcon x:Name="ClearIcon"
Symbol="Delete"
IconVariant="Regular"
FontSize="14" />
</Button>
<Button x:Name="FileButton"
Width="30"
Height="30"
Padding="0"
CornerRadius="15"
ToolTip.Tip="SVG">
<fi:SymbolIcon x:Name="FileIcon"
Symbol="Document"
IconVariant="Regular"
FontSize="14" />
<Button.Flyout>
<MenuFlyout>
<MenuItem Header="Open SVG"
Click="OnImportButtonClick">
<MenuItem.Icon>
<fi:SymbolIcon Symbol="ArrowImport"
IconVariant="Regular"
FontSize="14" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Export SVG"
Click="OnExportButtonClick">
<MenuItem.Icon>
<fi:SymbolIcon Symbol="ArrowExport"
IconVariant="Regular"
FontSize="14" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Button.Flyout>
</Button>
</StackPanel>
</Border>
</Grid>
</Border>
<Popup x:Name="ColorPickerPopup"
Placement="Top"
PlacementTarget="{Binding #PenButton}"
IsLightDismissEnabled="True"
WindowManagerAddShadowHint="False">
<Border Background="{DynamicResource AdaptiveSurfaceBaseBrush}"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="{DynamicResource DesignCornerRadiusXs}"
Padding="12">
<StackPanel Spacing="12">
<ColorView x:Name="InkColorPicker"
IsAlphaEnabled="False"
IsColorSpectrumVisible="True"
IsColorPaletteVisible="True"
IsHexInputVisible="True"
ColorChanged="OnColorPickerColorChanged" />
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="8">
<TextBlock Grid.Column="0"
Text="粗细"
VerticalAlignment="Center"
FontSize="12" />
<Slider x:Name="InkThicknessSlider"
Grid.Column="1"
Minimum="1"
Maximum="8"
Value="2.5"
SmallChange="0.5"
LargeChange="1"
ValueChanged="OnInkThicknessSliderValueChanged" />
</Grid>
</StackPanel>
</Border>
</Popup>
</Grid>
</UserControl>