mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-22 00:54:26 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e795e9964e |
52
.github/workflows/release.yml
vendored
52
.github/workflows/release.yml
vendored
@@ -66,8 +66,19 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [x64, x86]
|
include:
|
||||||
name: Build_Windows_${{ matrix.arch }}
|
# 完整版(自包含 .NET 运行时)
|
||||||
|
- arch: x64
|
||||||
|
self_contained: true
|
||||||
|
suffix: ''
|
||||||
|
- arch: x86
|
||||||
|
self_contained: true
|
||||||
|
suffix: ''
|
||||||
|
# 轻盈版(框架依赖,仅 x64)
|
||||||
|
- arch: x64
|
||||||
|
self_contained: false
|
||||||
|
suffix: '-lite'
|
||||||
|
name: Build_Windows_${{ matrix.arch }}${{ matrix.suffix }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -95,13 +106,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish
|
- name: Publish
|
||||||
run: |
|
run: |
|
||||||
|
$selfContained = "${{ matrix.self_contained }}" -eq "true"
|
||||||
|
$publishDir = if ($selfContained) { "publish/windows-${{ matrix.arch }}" } else { "publish/windows-${{ matrix.arch }}-lite" }
|
||||||
|
|
||||||
dotnet publish LanMountainDesktop/LanMountainDesktop.csproj `
|
dotnet publish LanMountainDesktop/LanMountainDesktop.csproj `
|
||||||
-c Release `
|
-c Release `
|
||||||
-o ./publish/windows-${{ matrix.arch }} `
|
-o ./$publishDir `
|
||||||
--self-contained `
|
--self-contained:$selfContained `
|
||||||
-r win-${{ matrix.arch }} `
|
-r win-${{ matrix.arch }} `
|
||||||
-p:PublishSingleFile=false `
|
-p:PublishSingleFile=false `
|
||||||
-p:SelfContained=true `
|
-p:SelfContained=$selfContained `
|
||||||
-p:DebugType=none `
|
-p:DebugType=none `
|
||||||
-p:DebugSymbols=false `
|
-p:DebugSymbols=false `
|
||||||
-p:PublishTrimmed=false `
|
-p:PublishTrimmed=false `
|
||||||
@@ -110,6 +124,9 @@ jobs:
|
|||||||
-p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }} `
|
-p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }} `
|
||||||
-p:FileVersion=${{ needs.prepare.outputs.assembly_version }} `
|
-p:FileVersion=${{ needs.prepare.outputs.assembly_version }} `
|
||||||
-p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}
|
-p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}
|
||||||
|
|
||||||
|
Write-Host "Published to: $publishDir"
|
||||||
|
Write-Host "Self-contained: $selfContained"
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
- name: Install Inno Setup
|
- name: Install Inno Setup
|
||||||
@@ -120,7 +137,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
$version = "${{ needs.prepare.outputs.version }}"
|
$version = "${{ needs.prepare.outputs.version }}"
|
||||||
$arch = "${{ matrix.arch }}"
|
$arch = "${{ matrix.arch }}"
|
||||||
$publishDir = "publish\windows-$arch"
|
$selfContained = "${{ matrix.self_contained }}" -eq "true"
|
||||||
|
$suffix = "${{ matrix.suffix }}"
|
||||||
|
$publishDir = if ($selfContained) { "publish\windows-$arch" } else { "publish\windows-$arch-lite" }
|
||||||
$installerScript = "LanMountainDesktop\installer\LanMountainDesktop.iss"
|
$installerScript = "LanMountainDesktop\installer\LanMountainDesktop.iss"
|
||||||
$outputDir = "build-installer"
|
$outputDir = "build-installer"
|
||||||
|
|
||||||
@@ -187,6 +206,8 @@ jobs:
|
|||||||
"/DPublishDir=$publishDir",
|
"/DPublishDir=$publishDir",
|
||||||
"/DMyOutputDir=$outputDir",
|
"/DMyOutputDir=$outputDir",
|
||||||
"/DMyAppArch=$arch",
|
"/DMyAppArch=$arch",
|
||||||
|
"/DMyAppSuffix=$suffix",
|
||||||
|
"/DIsSelfContained=$selfContained",
|
||||||
$installerScript
|
$installerScript
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -213,7 +234,7 @@ jobs:
|
|||||||
- name: Upload Installer
|
- name: Upload Installer
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-windows-${{ matrix.arch }}
|
name: release-windows-${{ matrix.arch }}${{ matrix.suffix }}
|
||||||
path: build-installer/*.exe
|
path: build-installer/*.exe
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
@@ -548,19 +569,22 @@ jobs:
|
|||||||
artifacts: "release-files/**"
|
artifacts: "release-files/**"
|
||||||
body: |
|
body: |
|
||||||
## Release ${{ needs.prepare.outputs.version }}
|
## Release ${{ needs.prepare.outputs.version }}
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
- **LanMountainDesktop-Setup-{version}-x64.exe** - 64-bit installer
|
- **LanMountainDesktop-Setup-{version}-x64.exe** - 64-bit installer (完整版,包含 .NET 运行时)
|
||||||
- **LanMountainDesktop-Setup-{version}-x86.exe** - 32-bit installer
|
- **LanMountainDesktop-Setup-{version}-x64-lite.exe** - 64-bit installer (轻量版,需安装 .NET 10 Runtime)
|
||||||
|
- **LanMountainDesktop-Setup-{version}-x86.exe** - 32-bit installer (完整版,包含 .NET 运行时)
|
||||||
|
|
||||||
|
> **轻量版说明**:轻量版不包含 .NET 运行时,体积更小。首次运行前需安装 [.NET 10 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/10.0)。
|
||||||
|
|
||||||
Installation: Double-click the .exe file and follow the wizard.
|
Installation: Double-click the .exe file and follow the wizard.
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
- **LanMountainDesktop-{version}-linux-x64.deb** - Debian package (x64)
|
- **LanMountainDesktop-{version}-linux-x64.deb** - Debian package (x64)
|
||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
- **LanMountainDesktop-{version}-macos-x64.dmg** - Intel processor
|
- **LanMountainDesktop-{version}-macos-x64.dmg** - Intel processor
|
||||||
- **LanMountainDesktop-{version}-macos-arm64.dmg** - Apple Silicon (M1/M2/M3)
|
- **LanMountainDesktop-{version}-macos-arm64.dmg** - Apple Silicon (M1/M2/M3)
|
||||||
|
|
||||||
See commits for changes.
|
See commits for changes.
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
100
.trae/specs/fused-desktop-library-redesign/spec.md
Normal file
100
.trae/specs/fused-desktop-library-redesign/spec.md
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# 融合桌面组件库窗口重设计规格
|
||||||
|
|
||||||
|
## Why
|
||||||
|
当前融合桌面组件库窗口(FusedDesktopComponentLibraryWindow)的UI设计较为基础,与Windows 11小组件编辑面板相比,缺乏现代化的交互体验和视觉层次。用户需要一个更直观、更美观的界面来浏览和添加组件到系统桌面(负一屏)。
|
||||||
|
|
||||||
|
参考Windows 11小组件编辑面板的设计特点:
|
||||||
|
- 左侧分类列表,右侧选中组件的详细预览
|
||||||
|
- 大型组件预览区域,让用户清楚看到组件效果
|
||||||
|
- 底部明显的"添加"操作按钮
|
||||||
|
- 简洁的关闭按钮(X)在右上角
|
||||||
|
- 深色主题配合毛玻璃效果
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
- **重新设计窗口布局**:从左右分栏(分类列表+组件网格)改为左侧面板+右侧预览区的布局
|
||||||
|
- **添加组件详情预览区**:选中组件后右侧显示大尺寸预览和组件信息
|
||||||
|
- **优化关闭按钮**:使用标准的X图标按钮,不使用圆形样式
|
||||||
|
- **添加底部操作栏**:包含"添加到桌面"主操作按钮和"查找更多组件"链接
|
||||||
|
- **复用阑山桌面组件库分类**:使用相同的分类ID、图标和本地化文本
|
||||||
|
- **移除搜索功能**:参考Windows 11设计,暂不提供搜索
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
- 受影响文件:
|
||||||
|
- `LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml`
|
||||||
|
- `LanMountainDesktop/Views/FusedDesktopComponentLibraryWindow.axaml.cs`
|
||||||
|
- `LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml`
|
||||||
|
- `LanMountainDesktop/Views/FusedDesktopComponentLibraryControl.axaml.cs`
|
||||||
|
- `LanMountainDesktop/ViewModels/ComponentLibraryWindowViewModel.cs`(可能需要添加新属性)
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: 窗口布局重设计
|
||||||
|
系统应提供一个类似于Windows 11小组件编辑面板的组件库窗口。
|
||||||
|
|
||||||
|
#### Scenario: 窗口整体结构
|
||||||
|
- **GIVEN** 用户从托盘菜单打开融合桌面组件库
|
||||||
|
- **WHEN** 窗口显示时
|
||||||
|
- **THEN** 窗口应呈现:
|
||||||
|
- 顶部标题栏:左侧显示"添加小组件"标题,右侧有关闭按钮(X)
|
||||||
|
- 左侧面板:分类列表(复用阑山桌面组件库的分类和图标)
|
||||||
|
- 右侧主区域:选中组件的大尺寸预览 + 组件信息 + 添加按钮
|
||||||
|
- 底部:"查找更多组件"链接
|
||||||
|
|
||||||
|
#### Scenario: 分类列表交互
|
||||||
|
- **GIVEN** 左侧显示组件分类列表
|
||||||
|
- **WHEN** 用户点击某个分类
|
||||||
|
- **THEN** 右侧应显示该分类下的第一个组件的预览
|
||||||
|
- **AND** 分类项应有选中状态视觉反馈
|
||||||
|
- **AND** 分类图标和名称应与阑山桌面组件库保持一致
|
||||||
|
|
||||||
|
#### Scenario: 组件预览区
|
||||||
|
- **GIVEN** 用户选中一个组件
|
||||||
|
- **WHEN** 预览区显示时
|
||||||
|
- **THEN** 应显示:
|
||||||
|
- 组件标题(大字号)
|
||||||
|
- 大尺寸组件预览图(接近实际尺寸)
|
||||||
|
- 组件描述/功能说明
|
||||||
|
- 底部"添加到桌面"按钮
|
||||||
|
|
||||||
|
#### Scenario: 添加组件操作
|
||||||
|
- **GIVEN** 用户查看组件预览
|
||||||
|
- **WHEN** 用户点击"添加到桌面"按钮
|
||||||
|
- **THEN** 组件应被添加到系统桌面(负一屏)中央
|
||||||
|
- **AND** 窗口应关闭
|
||||||
|
|
||||||
|
#### Scenario: 关闭按钮样式
|
||||||
|
- **GIVEN** 窗口标题栏有关闭按钮
|
||||||
|
- **THEN** 关闭按钮应使用标准的X图标
|
||||||
|
- **AND** 不使用圆形背景或特殊样式
|
||||||
|
- **AND** 使用 `DesignCornerRadiusSm` 动态资源
|
||||||
|
|
||||||
|
#### Scenario: 查找更多组件链接
|
||||||
|
- **GIVEN** 窗口底部显示"查找更多组件"链接
|
||||||
|
- **WHEN** 用户点击该链接
|
||||||
|
- **THEN** 应打开设置窗口的插件目录页面(后续将改为插件市场)
|
||||||
|
|
||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: 组件列表展示
|
||||||
|
原实现使用网格展示所有组件,新实现改为:
|
||||||
|
- 左侧列表仅显示分类(复用阑山桌面组件库的分类ID和图标映射)
|
||||||
|
- 右侧预览区一次只显示一个组件的详细信息
|
||||||
|
- ~~移除搜索功能~~(根据Windows 11设计,暂不提供搜索)
|
||||||
|
|
||||||
|
### Requirement: 关闭按钮圆角规范
|
||||||
|
原实现关闭按钮使用硬编码 `CornerRadius="18"`,应改为使用动态资源 `DesignCornerRadiusSm`。
|
||||||
|
|
||||||
|
### Requirement: 分类图标复用
|
||||||
|
分类图标映射应与阑山桌面组件库保持一致:
|
||||||
|
- Clock -> Symbol.Clock
|
||||||
|
- Date -> Symbol.CalendarDate
|
||||||
|
- Weather -> Symbol.WeatherSunny
|
||||||
|
- Board -> Symbol.Edit
|
||||||
|
- Media -> Symbol.Play
|
||||||
|
- Info -> Symbol.Info
|
||||||
|
- Calculator -> Symbol.Calculator
|
||||||
|
- Study -> Symbol.Hourglass
|
||||||
|
- 其他 -> Symbol.Apps
|
||||||
|
|
||||||
|
## REMOVED Requirements
|
||||||
|
- ~~搜索功能~~:根据Windows 11小组件面板设计,暂不提供搜索功能
|
||||||
35
.trae/specs/fused-desktop-library-redesign/tasks.md
Normal file
35
.trae/specs/fused-desktop-library-redesign/tasks.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Tasks
|
||||||
|
|
||||||
|
- [x] Task 1: 修改 FusedDesktopComponentLibraryWindow.axaml 窗口布局
|
||||||
|
- [x] SubTask 1.1: 重新设计标题栏,使用标准X关闭按钮,移除圆形样式,使用 DesignCornerRadiusSm
|
||||||
|
- [x] SubTask 1.2: 调整窗口整体布局为左侧面板+右侧预览区
|
||||||
|
- [x] SubTask 1.3: 添加底部"查找更多组件"链接区域
|
||||||
|
|
||||||
|
- [x] Task 2: 修改 FusedDesktopComponentLibraryControl.axaml 控件布局
|
||||||
|
- [x] SubTask 2.1: 重新设计左侧面板:仅保留分类列表(移除搜索框)
|
||||||
|
- [x] SubTask 2.2: 重新设计右侧预览区:组件标题 + 大尺寸预览 + 描述 + 添加按钮
|
||||||
|
- [x] SubTask 2.3: 优化分类列表项样式,添加选中状态视觉反馈
|
||||||
|
- [x] SubTask 2.4: 复用阑山桌面组件库的分类图标映射
|
||||||
|
|
||||||
|
- [x] Task 3: 更新 ViewModel 支持新交互模式
|
||||||
|
- [x] SubTask 3.1: 在 ComponentLibraryWindowViewModel 中添加 SelectedComponent 属性
|
||||||
|
- [x] SubTask 3.2: 添加组件描述属性支持
|
||||||
|
|
||||||
|
- [x] Task 4: 更新 FusedDesktopComponentLibraryControl.axaml.cs 代码逻辑
|
||||||
|
- [x] SubTask 4.1: 修改分类选择逻辑,选中分类时显示该分类第一个组件
|
||||||
|
- [x] SubTask 4.2: 添加组件选中逻辑
|
||||||
|
- [x] SubTask 4.3: 移除搜索相关代码
|
||||||
|
- [x] SubTask 4.4: 复用阑山桌面组件库的分类图标和本地化方法
|
||||||
|
- [x] SubTask 4.5: 添加"查找更多组件"链接点击处理(打开设置窗口插件目录)
|
||||||
|
|
||||||
|
- [x] Task 5: 验证和测试
|
||||||
|
- [x] SubTask 5.1: 验证关闭按钮使用动态圆角资源 DesignCornerRadiusSm
|
||||||
|
- [x] SubTask 5.2: 验证窗口布局符合Windows 11小组件面板风格
|
||||||
|
- [x] SubTask 5.3: 验证分类图标与阑山桌面组件库一致
|
||||||
|
- [x] SubTask 5.4: 验证组件添加功能正常工作
|
||||||
|
- [x] SubTask 5.5: 验证"查找更多组件"链接能打开设置窗口
|
||||||
|
|
||||||
|
# Task Dependencies
|
||||||
|
- Task 3 依赖于 Task 1 和 Task 2 的UI设计确定
|
||||||
|
- Task 4 依赖于 Task 3 的ViewModel更新
|
||||||
|
- Task 5 依赖于所有前置任务完成
|
||||||
@@ -10,6 +10,7 @@ namespace LanMountainDesktop.ViewModels;
|
|||||||
public sealed class ComponentLibraryWindowViewModel : ViewModelBase
|
public sealed class ComponentLibraryWindowViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private string _title = "Widgets";
|
private string _title = "Widgets";
|
||||||
|
private ComponentLibraryItemViewModel? _selectedComponent;
|
||||||
|
|
||||||
public string Title
|
public string Title
|
||||||
{
|
{
|
||||||
@@ -20,6 +21,12 @@ public sealed class ComponentLibraryWindowViewModel : ViewModelBase
|
|||||||
public ObservableCollection<ComponentLibraryCategoryViewModel> Categories { get; } = [];
|
public ObservableCollection<ComponentLibraryCategoryViewModel> Categories { get; } = [];
|
||||||
|
|
||||||
public ObservableCollection<ComponentLibraryItemViewModel> Components { get; } = [];
|
public ObservableCollection<ComponentLibraryItemViewModel> Components { get; } = [];
|
||||||
|
|
||||||
|
public ComponentLibraryItemViewModel? SelectedComponent
|
||||||
|
{
|
||||||
|
get => _selectedComponent;
|
||||||
|
set => SetProperty(ref _selectedComponent, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ComponentLibraryCategoryViewModel
|
public sealed class ComponentLibraryCategoryViewModel
|
||||||
@@ -51,6 +58,7 @@ public sealed class ComponentLibraryItemViewModel
|
|||||||
private readonly string _loadingPreviewText;
|
private readonly string _loadingPreviewText;
|
||||||
private readonly string _previewUnavailableText;
|
private readonly string _previewUnavailableText;
|
||||||
private string _displayName;
|
private string _displayName;
|
||||||
|
private string? _description;
|
||||||
private ComponentPreviewKey _previewKey;
|
private ComponentPreviewKey _previewKey;
|
||||||
private ComponentPreviewImageEntry? _previewImageEntry;
|
private ComponentPreviewImageEntry? _previewImageEntry;
|
||||||
private ComponentPreviewImageState _previewState;
|
private ComponentPreviewImageState _previewState;
|
||||||
@@ -61,12 +69,14 @@ public sealed class ComponentLibraryItemViewModel
|
|||||||
string componentId,
|
string componentId,
|
||||||
string displayName,
|
string displayName,
|
||||||
ComponentPreviewKey previewKey,
|
ComponentPreviewKey previewKey,
|
||||||
|
string? description = null,
|
||||||
string loadingPreviewText = "Loading preview...",
|
string loadingPreviewText = "Loading preview...",
|
||||||
string previewUnavailableText = "Preview unavailable",
|
string previewUnavailableText = "Preview unavailable",
|
||||||
ComponentPreviewImageEntry? previewImageEntry = null)
|
ComponentPreviewImageEntry? previewImageEntry = null)
|
||||||
{
|
{
|
||||||
ComponentId = componentId;
|
ComponentId = componentId;
|
||||||
_displayName = displayName;
|
_displayName = displayName;
|
||||||
|
_description = description;
|
||||||
_previewKey = previewKey;
|
_previewKey = previewKey;
|
||||||
_loadingPreviewText = loadingPreviewText;
|
_loadingPreviewText = loadingPreviewText;
|
||||||
_previewUnavailableText = previewUnavailableText;
|
_previewUnavailableText = previewUnavailableText;
|
||||||
@@ -82,6 +92,12 @@ public sealed class ComponentLibraryItemViewModel
|
|||||||
set => SetProperty(ref _displayName, value);
|
set => SetProperty(ref _displayName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string? Description
|
||||||
|
{
|
||||||
|
get => _description;
|
||||||
|
set => SetProperty(ref _description, value);
|
||||||
|
}
|
||||||
|
|
||||||
public ComponentPreviewKey PreviewKey
|
public ComponentPreviewKey PreviewKey
|
||||||
{
|
{
|
||||||
get => _previewKey;
|
get => _previewKey;
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ public partial class ComponentLibraryWindow : Window
|
|||||||
entry.ComponentId,
|
entry.ComponentId,
|
||||||
displayName,
|
displayName,
|
||||||
previewKey,
|
previewKey,
|
||||||
|
description: null,
|
||||||
_localize?.Invoke("component_library.preview.loading", "Loading preview...") ?? "Loading preview...",
|
_localize?.Invoke("component_library.preview.loading", "Loading preview...") ?? "Loading preview...",
|
||||||
_localize?.Invoke("component_library.preview.unavailable", "Preview unavailable") ?? "Preview unavailable",
|
_localize?.Invoke("component_library.preview.unavailable", "Preview unavailable") ?? "Preview unavailable",
|
||||||
previewEntry);
|
previewEntry);
|
||||||
|
|||||||
@@ -2,159 +2,203 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="using:LanMountainDesktop.ViewModels"
|
xmlns:vm="using:LanMountainDesktop.ViewModels"
|
||||||
xmlns:fi="using:FluentIcons.Avalonia"
|
xmlns:fi="using:FluentIcons.Avalonia"
|
||||||
|
xmlns:converters="using:Avalonia.Data.Converters"
|
||||||
x:Class="LanMountainDesktop.Views.FusedDesktopComponentLibraryControl"
|
x:Class="LanMountainDesktop.Views.FusedDesktopComponentLibraryControl"
|
||||||
x:DataType="vm:ComponentLibraryWindowViewModel">
|
x:DataType="vm:ComponentLibraryWindowViewModel">
|
||||||
|
|
||||||
<Grid ColumnDefinitions="240,*"
|
<UserControl.Styles>
|
||||||
ColumnSpacing="12"
|
<!-- 分类列表项样式 -->
|
||||||
|
<Style Selector="ListBoxItem.category-item">
|
||||||
|
<Setter Property="Padding" Value="0"/>
|
||||||
|
<Setter Property="Margin" Value="0,0,0,4"/>
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.category-item:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.category-item:selected /template/ ContentPresenter#PART_ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- 分类项内容容器 - 默认状态 -->
|
||||||
|
<Style Selector="Border.category-content">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AdaptiveNavItemBackgroundBrush}"/>
|
||||||
|
<Setter Property="Padding" Value="12,10"/>
|
||||||
|
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusMd}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.category-item:selected Border.category-content">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AdaptiveAccentBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.category-item:pointerover Border.category-content">
|
||||||
|
<Setter Property="Opacity" Value="0.9"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- 分类项图标和文字 - 默认状态 -->
|
||||||
|
<Style Selector="ListBoxItem.category-item fi|SymbolIcon.category-icon">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AdaptiveTextPrimaryBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.category-item:selected fi|SymbolIcon.category-icon">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AdaptiveOnAccentBrush}"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBoxItem.category-item TextBlock.category-text">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AdaptiveTextPrimaryBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.category-item:selected TextBlock.category-text">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AdaptiveOnAccentBrush}"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Styles>
|
||||||
|
|
||||||
|
<Grid ColumnDefinitions="280,*"
|
||||||
|
ColumnSpacing="16"
|
||||||
Margin="0">
|
Margin="0">
|
||||||
<!-- 分类列表 (左侧) -->
|
<!-- 分类列表 (左侧) -->
|
||||||
<Border Classes="surface-translucent-panel"
|
<Border Classes="surface-translucent-panel"
|
||||||
CornerRadius="{DynamicResource DesignCornerRadiusLg}"
|
CornerRadius="{DynamicResource DesignCornerRadiusLg}"
|
||||||
Padding="10">
|
Padding="12">
|
||||||
<Grid RowDefinitions="Auto,*">
|
<ListBox x:Name="CategoryListBox"
|
||||||
<TextBox x:Name="SearchBox"
|
Background="Transparent"
|
||||||
Watermark="搜索组件..."
|
BorderThickness="0"
|
||||||
Margin="0,0,0,12"
|
SelectionChanged="OnCategorySelectionChanged"
|
||||||
Classes="clear"
|
ItemsSource="{Binding Categories}">
|
||||||
Background="{DynamicResource AdaptiveSurfaceLowBrush}"
|
<ListBox.ItemTemplate>
|
||||||
CornerRadius="12"
|
<DataTemplate x:DataType="vm:ComponentLibraryCategoryViewModel">
|
||||||
Padding="12,8">
|
<Border Classes="category-content">
|
||||||
<TextBox.InnerLeftContent>
|
<Grid ColumnDefinitions="Auto,*"
|
||||||
<fi:SymbolIcon Symbol="Search" FontSize="16" Margin="10,0,0,0" Opacity="0.5" />
|
ColumnSpacing="12">
|
||||||
</TextBox.InnerLeftContent>
|
<fi:SymbolIcon Symbol="{Binding Icon}"
|
||||||
</TextBox>
|
IconVariant="Regular"
|
||||||
|
FontSize="20"
|
||||||
<ListBox x:Name="CategoryListBox"
|
Classes="category-icon"/>
|
||||||
Grid.Row="1"
|
<TextBlock Grid.Column="1"
|
||||||
Background="Transparent"
|
VerticalAlignment="Center"
|
||||||
BorderThickness="0"
|
FontSize="14"
|
||||||
SelectionChanged="OnCategorySelectionChanged"
|
FontWeight="SemiBold"
|
||||||
ItemsSource="{Binding Categories}">
|
Classes="category-text"
|
||||||
<ListBox.ItemTemplate>
|
Text="{Binding Title}"/>
|
||||||
<DataTemplate x:DataType="vm:ComponentLibraryCategoryViewModel">
|
</Grid>
|
||||||
<Border Padding="10"
|
</Border>
|
||||||
Margin="0,0,0,6"
|
</DataTemplate>
|
||||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}"
|
</ListBox.ItemTemplate>
|
||||||
Background="{DynamicResource AdaptiveNavItemBackgroundBrush}">
|
</ListBox>
|
||||||
<Grid ColumnDefinitions="Auto,*"
|
|
||||||
ColumnSpacing="8">
|
|
||||||
<fi:SymbolIcon Symbol="{Binding Icon}"
|
|
||||||
IconVariant="Regular"
|
|
||||||
FontSize="16" />
|
|
||||||
<TextBlock Grid.Column="1"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontWeight="SemiBold"
|
|
||||||
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"
|
|
||||||
Text="{Binding Title}" />
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListBox.ItemTemplate>
|
|
||||||
</ListBox>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- 组件网格 (右侧) -->
|
<!-- 组件预览区 (右侧) -->
|
||||||
<Border Grid.Column="1"
|
<Border Grid.Column="1"
|
||||||
Classes="surface-translucent-strong"
|
Classes="surface-translucent-strong"
|
||||||
CornerRadius="{DynamicResource DesignCornerRadiusLg}"
|
CornerRadius="{DynamicResource DesignCornerRadiusLg}"
|
||||||
Padding="10">
|
Padding="24">
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
<Panel>
|
||||||
HorizontalScrollBarVisibility="Disabled">
|
<!-- 有选中组件时的显示 -->
|
||||||
<ItemsControl x:Name="ComponentItemsControl"
|
<Grid RowDefinitions="Auto,*,Auto"
|
||||||
ItemsSource="{Binding Components}">
|
IsVisible="{Binding SelectedComponent, Converter={x:Static converters:ObjectConverters.IsNotNull}}">
|
||||||
<ItemsControl.ItemsPanel>
|
<!-- 组件标题 -->
|
||||||
<ItemsPanelTemplate>
|
<TextBlock Grid.Row="0"
|
||||||
<WrapPanel Orientation="Horizontal" />
|
FontSize="28"
|
||||||
</ItemsPanelTemplate>
|
FontWeight="Bold"
|
||||||
</ItemsControl.ItemsPanel>
|
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"
|
||||||
|
Text="{Binding SelectedComponent.DisplayName}"
|
||||||
|
Margin="0,0,0,20"/>
|
||||||
|
|
||||||
<ItemsControl.ItemTemplate>
|
<!-- 预览区域 -->
|
||||||
<DataTemplate x:DataType="vm:ComponentLibraryItemViewModel">
|
<Border Grid.Row="1"
|
||||||
<Border Width="240"
|
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
||||||
Height="220"
|
Background="{DynamicResource AdaptiveSurfaceBaseBrush}"
|
||||||
Margin="6"
|
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||||
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
|
BorderThickness="1"
|
||||||
Padding="10"
|
Padding="20"
|
||||||
Background="{DynamicResource AdaptiveSurfaceRaisedBrush}"
|
HorizontalAlignment="Center"
|
||||||
BorderBrush="{DynamicResource AdaptiveButtonBorderBrush}"
|
VerticalAlignment="Center">
|
||||||
BorderThickness="1">
|
<Grid Width="400"
|
||||||
<Grid RowDefinitions="*,Auto,Auto"
|
Height="300">
|
||||||
RowSpacing="8">
|
<!-- 预览图片 -->
|
||||||
<!-- 预览区域 -->
|
<Image Source="{Binding SelectedComponent.PreviewBitmap}"
|
||||||
<Border CornerRadius="{DynamicResource DesignCornerRadiusSm}"
|
Stretch="Uniform"
|
||||||
Background="{DynamicResource AdaptiveGlassPanelBackgroundBrush}"
|
HorizontalAlignment="Center"
|
||||||
BorderThickness="1"
|
VerticalAlignment="Center"
|
||||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
RenderOptions.BitmapInterpolationMode="HighQuality"
|
||||||
Padding="8">
|
IsVisible="{Binding SelectedComponent.IsPreviewReady}"/>
|
||||||
<Grid>
|
|
||||||
<Image Source="{Binding PreviewBitmap}"
|
|
||||||
Stretch="Uniform"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
RenderOptions.BitmapInterpolationMode="HighQuality"
|
|
||||||
IsVisible="{Binding IsPreviewReady}" />
|
|
||||||
|
|
||||||
<!-- 加载中状态 -->
|
<!-- 加载中状态 -->
|
||||||
<Border IsVisible="{Binding IsPreviewPending}"
|
<Border IsVisible="{Binding SelectedComponent.IsPreviewPending}"
|
||||||
Background="{DynamicResource AdaptiveSurfaceBaseBrush}">
|
Background="{DynamicResource AdaptiveSurfaceBaseBrush}">
|
||||||
<StackPanel HorizontalAlignment="Center"
|
<StackPanel HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Spacing="8">
|
Spacing="12">
|
||||||
<ProgressBar Width="96"
|
<ProgressBar Width="120"
|
||||||
IsIndeterminate="True" />
|
IsIndeterminate="True"/>
|
||||||
<TextBlock HorizontalAlignment="Center"
|
<TextBlock HorizontalAlignment="Center"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
FontSize="12"
|
FontSize="14"
|
||||||
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"
|
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"
|
||||||
Text="{Binding PreviewStatusText}" />
|
Text="{Binding SelectedComponent.PreviewStatusText}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- 失败状态 -->
|
<!-- 失败状态 -->
|
||||||
<Border IsVisible="{Binding IsPreviewFailed}"
|
<Border IsVisible="{Binding SelectedComponent.IsPreviewFailed}"
|
||||||
Background="{DynamicResource AdaptiveSurfaceBaseBrush}">
|
Background="{DynamicResource AdaptiveSurfaceBaseBrush}">
|
||||||
<StackPanel HorizontalAlignment="Center"
|
<StackPanel HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Spacing="8">
|
Spacing="8">
|
||||||
<TextBlock HorizontalAlignment="Center"
|
<fi:SymbolIcon Symbol="ImageOff"
|
||||||
TextAlignment="Center"
|
FontSize="48"
|
||||||
FontWeight="SemiBold"
|
Opacity="0.5"
|
||||||
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"
|
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"/>
|
||||||
Text="{Binding PreviewStatusText}" />
|
<TextBlock HorizontalAlignment="Center"
|
||||||
<TextBlock HorizontalAlignment="Center"
|
TextAlignment="Center"
|
||||||
TextAlignment="Center"
|
|
||||||
FontSize="12"
|
|
||||||
TextWrapping="Wrap"
|
|
||||||
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"
|
|
||||||
Text="{Binding PreviewErrorMessage}" />
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- 组件名称 -->
|
|
||||||
<TextBlock Grid.Row="1"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"
|
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"
|
||||||
Text="{Binding DisplayName}" />
|
Text="{Binding SelectedComponent.PreviewStatusText}"/>
|
||||||
|
<TextBlock HorizontalAlignment="Center"
|
||||||
<!-- 添加按钮 -->
|
TextAlignment="Center"
|
||||||
<Button Grid.Row="2"
|
FontSize="12"
|
||||||
HorizontalAlignment="Center"
|
TextWrapping="Wrap"
|
||||||
Padding="12,6"
|
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"
|
||||||
Tag="{Binding ComponentId}"
|
Text="{Binding SelectedComponent.PreviewErrorMessage}"/>
|
||||||
Click="OnAddComponentClick">
|
</StackPanel>
|
||||||
<TextBlock Text="添加到桌面" />
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
</Border>
|
||||||
</DataTemplate>
|
</Grid>
|
||||||
</ItemsControl.ItemTemplate>
|
</Border>
|
||||||
</ItemsControl>
|
|
||||||
</ScrollViewer>
|
<!-- 底部操作区 -->
|
||||||
|
<Grid Grid.Row="2"
|
||||||
|
ColumnDefinitions="*,Auto"
|
||||||
|
Margin="0,24,0,0">
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="14"
|
||||||
|
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"
|
||||||
|
Text="{Binding SelectedComponent.ComponentId, StringFormat='组件 ID: {0}'}"/>
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
Classes="accent"
|
||||||
|
Padding="20,12"
|
||||||
|
Tag="{Binding SelectedComponent.ComponentId}"
|
||||||
|
Click="OnAddComponentClick">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
<fi:SymbolIcon Symbol="Add" FontSize="16"/>
|
||||||
|
<TextBlock Text="添加到桌面" FontWeight="SemiBold"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<Grid IsVisible="{Binding SelectedComponent, Converter={x:Static converters:ObjectConverters.IsNull}}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<StackPanel Spacing="16" HorizontalAlignment="Center">
|
||||||
|
<fi:SymbolIcon Symbol="Apps"
|
||||||
|
FontSize="64"
|
||||||
|
Opacity="0.3"
|
||||||
|
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"/>
|
||||||
|
<TextBlock HorizontalAlignment="Center"
|
||||||
|
FontSize="16"
|
||||||
|
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"
|
||||||
|
Text="请从左侧选择一个组件"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Panel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ public partial class FusedDesktopComponentLibraryControl : UserControl
|
|||||||
|
|
||||||
LoadRegistry();
|
LoadRegistry();
|
||||||
LoadCategories();
|
LoadCategories();
|
||||||
SearchBox.KeyUp += (s, e) => FilterComponents();
|
|
||||||
|
// 为 ListBoxItem 添加 category-item 样式类
|
||||||
|
CategoryListBox.ContainerPrepared += OnCategoryListBoxContainerPrepared;
|
||||||
|
|
||||||
// 默认选择第一个分类
|
// 默认选择第一个分类
|
||||||
if (_viewModel.Categories.Count > 0)
|
if (_viewModel.Categories.Count > 0)
|
||||||
@@ -48,6 +50,14 @@ public partial class FusedDesktopComponentLibraryControl : UserControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCategoryListBoxContainerPrepared(object? sender, ContainerPreparedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Container is ListBoxItem listBoxItem)
|
||||||
|
{
|
||||||
|
listBoxItem.Classes.Add("category-item");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadRegistry()
|
private void LoadRegistry()
|
||||||
{
|
{
|
||||||
var pluginRuntimeService = (Application.Current as App)?.PluginRuntimeService;
|
var pluginRuntimeService = (Application.Current as App)?.PluginRuntimeService;
|
||||||
@@ -65,7 +75,6 @@ public partial class FusedDesktopComponentLibraryControl : UserControl
|
|||||||
private void LoadCategories()
|
private void LoadCategories()
|
||||||
{
|
{
|
||||||
_viewModel.Categories.Clear();
|
_viewModel.Categories.Clear();
|
||||||
_viewModel.Components.Clear();
|
|
||||||
|
|
||||||
// 添加"全部组件"分类
|
// 添加"全部组件"分类
|
||||||
_viewModel.Categories.Add(new ComponentLibraryCategoryViewModel(
|
_viewModel.Categories.Add(new ComponentLibraryCategoryViewModel(
|
||||||
@@ -130,10 +139,11 @@ public partial class FusedDesktopComponentLibraryControl : UserControl
|
|||||||
definition.Id,
|
definition.Id,
|
||||||
definition.DisplayName,
|
definition.DisplayName,
|
||||||
previewKey,
|
previewKey,
|
||||||
|
description: null,
|
||||||
"正在加载预览...",
|
"正在加载预览...",
|
||||||
"预览不可用",
|
"预览不可用",
|
||||||
previewEntry);
|
previewEntry);
|
||||||
|
|
||||||
if (mainWindow is not null && (previewEntry is null || previewEntry.State == ComponentPreviewImageState.Pending))
|
if (mainWindow is not null && (previewEntry is null || previewEntry.State == ComponentPreviewImageState.Pending))
|
||||||
{
|
{
|
||||||
mainWindow.RequestDetachedLibraryPreview(previewKey);
|
mainWindow.RequestDetachedLibraryPreview(previewKey);
|
||||||
@@ -158,25 +168,49 @@ public partial class FusedDesktopComponentLibraryControl : UserControl
|
|||||||
|
|
||||||
private void OnCategorySelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void OnCategorySelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
FilterComponents();
|
UpdateSelectedComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FilterComponents()
|
private void UpdateSelectedComponent()
|
||||||
{
|
{
|
||||||
var selectedCategory = (CategoryListBox.SelectedItem as ComponentLibraryCategoryViewModel)?.Id;
|
var selectedCategory = CategoryListBox.SelectedItem as ComponentLibraryCategoryViewModel;
|
||||||
var searchText = SearchBox.Text?.ToLower() ?? "";
|
if (selectedCategory is null)
|
||||||
|
|
||||||
var filtered = _allDefinitions.Where(d =>
|
|
||||||
{
|
{
|
||||||
var matchesCategory = selectedCategory == "all" || string.Equals(d.Category, selectedCategory, StringComparison.OrdinalIgnoreCase);
|
_viewModel.SelectedComponent = null;
|
||||||
var matchesSearch = string.IsNullOrEmpty(searchText) || d.DisplayName.ToLower().Contains(searchText) || d.Id.ToLower().Contains(searchText);
|
return;
|
||||||
return matchesCategory && matchesSearch;
|
}
|
||||||
});
|
|
||||||
|
|
||||||
_viewModel.Components.Clear();
|
// 获取该分类下的组件列表
|
||||||
foreach (var def in filtered)
|
IEnumerable<DesktopComponentDefinition> filtered;
|
||||||
|
if (selectedCategory.Id == "all")
|
||||||
{
|
{
|
||||||
_viewModel.Components.Add(CreateComponentItem(def));
|
filtered = _allDefinitions.OrderBy(d => d.DisplayName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filtered = _allDefinitions
|
||||||
|
.Where(d => string.Equals(d.Category, selectedCategory.Id, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.OrderBy(d => d.DisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择该分类下的第一个组件作为默认选中
|
||||||
|
var firstComponent = filtered.FirstOrDefault();
|
||||||
|
if (firstComponent is not null)
|
||||||
|
{
|
||||||
|
// 查找或创建对应的 ViewModel
|
||||||
|
var existingComponent = selectedCategory.Components.FirstOrDefault(c => c.ComponentId == firstComponent.Id);
|
||||||
|
if (existingComponent is not null)
|
||||||
|
{
|
||||||
|
_viewModel.SelectedComponent = existingComponent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_viewModel.SelectedComponent = CreateComponentItem(firstComponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_viewModel.SelectedComponent = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,21 +12,21 @@
|
|||||||
ExtendClientAreaTitleBarHeightHint="-1"
|
ExtendClientAreaTitleBarHeightHint="-1"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
TransparencyLevelHint="Mica"
|
TransparencyLevelHint="Mica"
|
||||||
Title="融合桌面组件库">
|
Title="添加小组件">
|
||||||
|
|
||||||
<Panel>
|
<Panel>
|
||||||
<!-- 背景磨砂效果 -->
|
<!-- 背景磨砂效果 -->
|
||||||
<Border Background="{DynamicResource AdaptiveSurfaceLowBrush}"
|
<Border Background="{DynamicResource AdaptiveSurfaceLowBrush}"
|
||||||
Opacity="0.85" />
|
Opacity="0.85" />
|
||||||
|
|
||||||
<Grid RowDefinitions="Auto,*">
|
<Grid RowDefinitions="Auto,*,Auto">
|
||||||
<!-- 自定义标题栏 -->
|
<!-- 自定义标题栏 -->
|
||||||
<Border Background="Transparent"
|
<Border Background="Transparent"
|
||||||
IsHitTestVisible="True"
|
IsHitTestVisible="True"
|
||||||
Padding="20,16">
|
Padding="20,16">
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
<StackPanel Spacing="6" VerticalAlignment="Center">
|
<StackPanel Spacing="6" VerticalAlignment="Center">
|
||||||
<TextBlock Text="融合桌面组件库"
|
<TextBlock Text="添加小组件"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
FontSize="20"
|
FontSize="20"
|
||||||
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
||||||
@@ -35,23 +35,35 @@
|
|||||||
FontSize="13"
|
FontSize="13"
|
||||||
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1"
|
||||||
Classes="accent"
|
|
||||||
Width="36" Height="36"
|
Width="36" Height="36"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
CornerRadius="18"
|
CornerRadius="{DynamicResource DesignCornerRadiusSm}"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
Background="{DynamicResource AdaptiveButtonHoverBackgroundBrush}"
|
|
||||||
Click="OnCloseClick">
|
Click="OnCloseClick">
|
||||||
<fi:SymbolIcon Symbol="Dismiss" FontSize="18" />
|
<fi:SymbolIcon Symbol="Dismiss" FontSize="18" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- 组件库控件 -->
|
<!-- 组件库控件 -->
|
||||||
<controls:FusedDesktopComponentLibraryControl x:Name="LibraryControl"
|
<controls:FusedDesktopComponentLibraryControl x:Name="LibraryControl"
|
||||||
Grid.Row="1" />
|
Grid.Row="1" />
|
||||||
|
|
||||||
|
<!-- 底部查找更多组件链接 -->
|
||||||
|
<Border Grid.Row="2"
|
||||||
|
Background="Transparent"
|
||||||
|
Padding="20,12">
|
||||||
|
<Button Classes="hyperlink"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Click="OnFindMoreComponentsClick">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||||
|
<fi:SymbolIcon Symbol="Globe" FontSize="14" />
|
||||||
|
<TextBlock Text="查找更多组件" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Panel>
|
</Panel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -102,6 +102,26 @@ public partial class FusedDesktopComponentLibraryWindow : Window
|
|||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找更多组件链接点击处理 - 打开设置窗口的插件目录页面
|
||||||
|
/// </summary>
|
||||||
|
private void OnFindMoreComponentsClick(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 关闭当前窗口
|
||||||
|
Close();
|
||||||
|
|
||||||
|
// 打开设置窗口并导航到插件目录页面
|
||||||
|
if (Application.Current is App app && app.SettingsWindowService is { } settingsWindowService)
|
||||||
|
{
|
||||||
|
var mainWindow = (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow as MainWindow;
|
||||||
|
var request = new SettingsWindowOpenRequest(
|
||||||
|
Source: "FusedDesktopComponentLibrary",
|
||||||
|
Owner: mainWindow,
|
||||||
|
PageId: "plugin-catalog");
|
||||||
|
settingsWindowService.Open(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
protected override void OnClosed(EventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,6 +20,14 @@
|
|||||||
#define MyAppArch "x64"
|
#define MyAppArch "x64"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MyAppSuffix
|
||||||
|
#define MyAppSuffix ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IsSelfContained
|
||||||
|
#define IsSelfContained "true"
|
||||||
|
#endif
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={#MyAppId}
|
AppId={#MyAppId}
|
||||||
AppName={#MyAppName}
|
AppName={#MyAppName}
|
||||||
@@ -34,7 +42,7 @@ LanguageDetectionMethod=uilanguage
|
|||||||
DefaultGroupName={cm:AppShortcutName}
|
DefaultGroupName={cm:AppShortcutName}
|
||||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||||
OutputDir={#MyOutputDir}
|
OutputDir={#MyOutputDir}
|
||||||
OutputBaseFilename={#MyAppName}-Setup-{#MyAppVersion}-{#MyAppArch}
|
OutputBaseFilename={#MyAppName}-Setup-{#MyAppVersion}-{#MyAppArch}{#MyAppSuffix}
|
||||||
Compression=lzma2/ultra64
|
Compression=lzma2/ultra64
|
||||||
SolidCompression=yes
|
SolidCompression=yes
|
||||||
WizardStyle=modern
|
WizardStyle=modern
|
||||||
@@ -93,7 +101,17 @@ chinesesimplified.UpgradeCleanupMissingUninstaller=安装程序发现了现有
|
|||||||
english.UpgradeCleanupFailedPrefix=Setup could not remove the existing installation automatically. Error code:
|
english.UpgradeCleanupFailedPrefix=Setup could not remove the existing installation automatically. Error code:
|
||||||
chinesesimplified.UpgradeCleanupFailedPrefix=安装程序无法自动移除现有安装。错误代码:
|
chinesesimplified.UpgradeCleanupFailedPrefix=安装程序无法自动移除现有安装。错误代码:
|
||||||
english.UpgradeCleanupFailedSuffix=Please close LanMountainDesktop, uninstall the current version manually, and then run this installer again.
|
english.UpgradeCleanupFailedSuffix=Please close LanMountainDesktop, uninstall the current version manually, and then run this installer again.
|
||||||
chinesesimplified.UpgradeCleanupFailedSuffix=请关闭 LanMountainDesktop,手动卸载当前版本,然后重新运行此安装程序。
|
chinesesimplified.UpgradeCleanupFailedSuffix=请关闭 LanMountain Desktop,手动卸载当前版本,然后重新运行此安装程序。
|
||||||
|
english.DotNetRuntimeMissingTitle=.NET Desktop Runtime Required
|
||||||
|
chinesesimplified.DotNetRuntimeMissingTitle=需要 .NET Desktop Runtime
|
||||||
|
english.DotNetRuntimeMissingMessage=This application requires .NET 10.0 Desktop Runtime to run.
|
||||||
|
chinesesimplified.DotNetRuntimeMissingMessage=此应用程序需要 .NET 10.0 Desktop Runtime 才能运行。
|
||||||
|
english.DotNetRuntimeMissingAction=Click "Yes" to open the official download page. Install it first, then run this installer again.
|
||||||
|
chinesesimplified.DotNetRuntimeMissingAction=单击"是"打开官方下载页面。请先完成安装,然后重新运行此安装程序。
|
||||||
|
english.DotNetRuntimeOpenFailedMessage=Unable to open the download page automatically.
|
||||||
|
chinesesimplified.DotNetRuntimeOpenFailedMessage=无法自动打开下载页面。
|
||||||
|
english.DotNetRuntimeOpenFailedAction=Please open this URL manually:
|
||||||
|
chinesesimplified.DotNetRuntimeOpenFailedAction=请手动打开以下链接:
|
||||||
|
|
||||||
[Tasks]
|
[Tasks]
|
||||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
|
||||||
@@ -127,6 +145,7 @@ const
|
|||||||
UninstallRegSubkey = 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppRegistryId}_is1';
|
UninstallRegSubkey = 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppRegistryId}_is1';
|
||||||
WebView2RuntimeKeyPath = 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}';
|
WebView2RuntimeKeyPath = 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}';
|
||||||
WebView2RuntimeDownloadUrl = 'https://go.microsoft.com/fwlink/p/?LinkId=2124703';
|
WebView2RuntimeDownloadUrl = 'https://go.microsoft.com/fwlink/p/?LinkId=2124703';
|
||||||
|
DotNetRuntimeDownloadUrl = 'https://dotnet.microsoft.com/download/dotnet/10.0';
|
||||||
UpgradeChoiceInPlace = 0;
|
UpgradeChoiceInPlace = 0;
|
||||||
UpgradeChoiceRelocate = 1;
|
UpgradeChoiceRelocate = 1;
|
||||||
|
|
||||||
@@ -435,10 +454,58 @@ begin
|
|||||||
RegQueryStringValue(HKCU32, WebView2RuntimeKeyPath, 'pv', VersionValue);
|
RegQueryStringValue(HKCU32, WebView2RuntimeKeyPath, 'pv', VersionValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function IsDotNetDesktopRuntimeInstalled(): Boolean;
|
||||||
|
var
|
||||||
|
RuntimePath: String;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
RuntimePath := ExpandConstant('{commonpf64}\dotnet\shared\Microsoft.WindowsDesktop.App');
|
||||||
|
if DirExists(RuntimePath) then
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
RuntimePath := ExpandConstant('{commonpf}\dotnet\shared\Microsoft.WindowsDesktop.App');
|
||||||
|
if DirExists(RuntimePath) then
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function InitializeSetup(): Boolean;
|
function InitializeSetup(): Boolean;
|
||||||
var
|
var
|
||||||
ErrorCode: Integer;
|
ErrorCode: Integer;
|
||||||
|
IsSelfContainedBuild: Boolean;
|
||||||
begin
|
begin
|
||||||
|
IsSelfContainedBuild := ('{#IsSelfContained}' = 'true');
|
||||||
|
|
||||||
|
if not IsSelfContainedBuild then
|
||||||
|
begin
|
||||||
|
if not IsDotNetDesktopRuntimeInstalled() then
|
||||||
|
begin
|
||||||
|
if MsgBox(
|
||||||
|
CustomMessage('DotNetRuntimeMissingMessage') + #13#10#13#10 +
|
||||||
|
CustomMessage('DotNetRuntimeMissingAction'),
|
||||||
|
mbConfirmation,
|
||||||
|
MB_YESNO) = IDYES then
|
||||||
|
begin
|
||||||
|
if not ShellExec('open', DotNetRuntimeDownloadUrl, '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode) then
|
||||||
|
begin
|
||||||
|
MsgBox(
|
||||||
|
CustomMessage('DotNetRuntimeOpenFailedMessage') + #13#10 +
|
||||||
|
CustomMessage('DotNetRuntimeOpenFailedAction') + #13#10 + DotNetRuntimeDownloadUrl,
|
||||||
|
mbError,
|
||||||
|
MB_OK);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result := False;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
if IsWebView2RuntimeInstalled() then
|
if IsWebView2RuntimeInstalled() then
|
||||||
begin
|
begin
|
||||||
Result := True;
|
Result := True;
|
||||||
|
|||||||
Reference in New Issue
Block a user