mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
* Add Windows system chrome patchers (Harmony) Introduce support for toggling the system chrome on Windows using Harmony patchers. Adds Lib.Harmony.Thin to package props and project, new patcher infrastructure (ChromePatchState, PatcherEntrance) and two Harmony patches that disable FluentAvalonia's Windows chrome when configured. Program.cs now loads the chrome setting and installs patchers conditionally on Windows/x86-x64. Settings viewmodel and view updated: expose IsWindowsOs, require restart on appearance changes, migrate SettingsWindow to FAAppWindow and adapt titlebar/layout (include Windows caption placeholder and footer menu items). Also add a .gitkeep and a build log file. * Refactor settings window UI and theming Improve theming and layout for the Settings window and related services. - MaterialSurfaceService: add special material parameters for SettingsWindowBackground (lower alpha, no blur) and avoid hot-switching real backdrops for non-settings windows. - GlassEffectService: add AdaptiveSettingsWindowTintBrush + ResolveSettingsWindowTintAlpha to provide optional content tinting tied to system material mode. - SettingsWindowService: refactor theme application into ApplyThemeVariantAndResources, ensure settings window material is applied at show/activate times, and tidy theme/resource application flow. - SettingsWindow.axaml / .axaml.cs: restructure title bar (separate Grid.Row=0 border) and FANavigationView host, add pane-footer toggle button for :minimal layout, use dynamic corner radius resource, and update toggle/visibility/icon logic and responsive layout code. - SettingsPages: remove some IconText usages and adjust margins; use DesignCornerRadiusLg for update card corner radius. - Add NuGet.Config to set local globalPackagesFolder and ignore .nuget/packages in .gitignore. These changes aim to improve visuals, avoid backdrop overdraw, and make the settings window behavior consistent across themes and layouts. * Add localization and localize settings pages Add many new localization keys (en-US and zh-CN) for notifications, developer tools, about page, status bar, and video wallpaper. Update Notification, Dev, About and StatusBar view models to use LocalizationService, expose localized ObservableProperties, and refresh localized text at construction. Localize selection options and test notification texts, and fix notification severity handling. Wire up XAML to the new localized properties (About/Dev/StatusBar pages) and update the settings page title for notifications. Also adjust copyright line generation and replace hardcoded placeholders with bound Watermark properties. * Redesign settings window with fluent shell & search Rebuild the settings window as a Fluent shell: adds a custom 48-DIP titlebar with Back, pane toggle, icon/title, search box, restart/more menu, and caption-button spacer; moves compact pane toggle into the titlebar and preserves FANavigationView as the primary navigation surface. Introduces a SettingsSearchService (with UI AutoComplete integration, search indexing, navigation-by-result, and search result highlighting) plus focused tests for search filtering and theme material normalization. Adds navigation history/back stack, updates SettingsViewModels for new bindings and localization keys, and updates General/Apearance pages to expose new strings and options. Implements an "auto" system material mode: default in AppSettingsSnapshot, new MaterialAuto constants and normalization/resolution logic in ThemeAppearanceValues, WindowMaterialService and MaterialSurfaceService adjustments to prefer Mica on Win11 and Acrylic on Win10 using TransparencyLevelHint. GlassEffectService and AppearanceThemeService updated to use effective material mode and to track live theme state changes. Adds localization entries (en-US, zh-CN), spec/tasks docs, and other UI/style tweaks to support the redesign. * fix.修折叠与展开按钮 * Add OOBE startup presentation and settings merge Introduce a new OOBE step for "Startup & Presentation" that exposes startup and UI preferences in OobeWindow (toggles for taskbar, slide/fade transitions, fused popup, and autostart). Add HostAppSettingsOobeMerger to read/write Host settings.json (PascalCase fields) and MergeStartupPresentation behavior, plus LauncherWindowsStartupService to sync the current Launcher into the Windows Run key on Windows. Wire UI handlers, persist choices on Next, and load defaults when entering the step. Include unit tests for the merger, adjust SettingsWindow navigation pane/toggle handling, and update docs/LAUNCHER.md to describe the new OOBE step and implementation files. * 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. * Introduce render gate and chart caching Replace UI DispatcherTimer polling with a StudySnapshotRenderGate across multiple widgets to queue and apply only the latest analytics snapshot; components updated include StudyDeductionReasonsWidget, StudyEnvironmentWidget, StudyInterruptDensityWidget, StudyNoiseCurveWidget. Add StudySnapshotRenderGate implementation to coordinate rendering and monitoring leases and update subscription/lease lifecycle handling (subscribe/unsubscribe, Acquire/Dispose leases, Clear/Dispose gate). Rewrite chart controls (StudyNoiseCurveChartControl and StudyNoiseDistributionScatterChartControl) to use stable logical-time origins, split series into static vs dynamic tails, add geometry/sample caching, stable jitter/coordinate mapping helpers, and expose internal helpers & counts for testing. Add unit tests (StudyComponentRenderingTests) covering the render gate and chart behaviors (layer counts, logical X mapping, stable jitter, cache rebuild). These changes improve rendering correctness and performance by avoiding redundant renders and enabling deterministic chart layout. * Use MaterialColorSnapshot in appearance flow Introduce unified material/color spec and tests, and refactor appearance plumbing to use MaterialColorSnapshot as the single source of truth. Add .trae material-color-service spec/checklist/tasks and integration/unit tests for plugin mapping and appearance VM behavior. AppearanceChangedEvent extended with new appearance change flags and HasChanged logic. ComponentEditorMaterialThemeAdapter rewritten to accept MaterialColorSnapshot and derive palette from snapshot data. Simplify AppearanceSettingsPageViewModel and related view code: remove legacy preview/custom-seed UI logic, preserve material/color fields when updating theme or corner radius, and update save calls to use with-expressions. Update ComponentEditorWindow to use adapter-provided OnPrimary brush and minor docs updates. * Add material color services, plugin DTOs, and tests Introduce IPC wire-format appearance DTOs (PluginIsolation.Contracts) and clarify they are distinct from the runtime PluginSdk snapshot. Update PluginSdk comments to document the runtime-facing snapshot shape. Change ComponentColorSchemeHelper to use the HostMaterialColorProvider and add an overload that accepts a MaterialColorSnapshot. Add new services and pipelines (MaterialColorService, MaterialSurfaceService, WindowMaterialService, WallpaperColorPipeline) and refactor AppearanceThemeService to depend on MaterialColorService while removing legacy internal implementations. Add multiple unit tests (ComponentColorSchemeHelper, PluginAppearanceBoundary, SettingsCatalogService, WallpaperSettingsPageViewModel) and update localization resources with new material_color and wallpaper keys. * Add CODE_WIKI and update localization Add a comprehensive CODE_WIKI.md documenting project architecture, modules, startup flow, plugin system, testing and developer workflows. Update localization resources (en-US.json, zh-CN.json) with new/translated keys for wallpaper controls (custom color UI), material & color settings (semantic roles, surfaces, refresh/polling state), appearance (corner radius), status bar font size options, privacy policy text, component library labels, clock settings, and new language entry (Korean). Also modify settings-related ViewModels and Settings page views to surface these new features and texts (MaterialColorSettingsPageViewModel.cs, SettingsViewModels.cs, WallpaperSettingsPageViewModel.cs, MainWindow.SettingsHardCut.Stubs.cs, ComponentsSettingsPage.axaml, WallpaperSettingsPage.axaml). * Add Data settings page and storage scanner Introduce a new "Data" settings page to visualize and manage local app storage. Adds DataStorageService (scanning, disk info, clean operations), DataSettingsPageViewModel, XAML view and code-behind, and HexToColor/HexToBrush converters; registers converters in App.axaml. Also update localization strings for the new page and add icon mapping so the settings entry uses the Database icon. Enables per-category and global cleaning workflows and formatted size display. * Add IPC backoff/retries and safer disposal Introduce exponential backoff, jitter and retry logic across IPC components to improve robustness and avoid tight retry loops; make disposal idempotent and add connection guards. Key changes: - LauncherCoordinatorIpcServer / LauncherIpcServer: add backoff constants, ComputeBackoff(), consecutive error tracking and delayed retries with jitter. - LanMountainDesktopIpcClient / LauncherIpcClient: add connect retry loops, timeouts, delayed retries, improved error logging, and use ArrayPool for buffered async writes; ensure proper cleanup on failures. - PublicIpcHostService: add disposed flag, guard OnPeerConnected and Dispose, and clear connected peers on dispose. - Add many auto-generated commit analysis docs under docs/auto_commit_md and new scripts for analyzing/generating commit docs. These changes aim to make IPC connection handling more resilient and resource-safe. * Add preview controls and settings UI tweaks Introduce GridPreviewControl and CornerRadiusPreviewControl for visual previews and wire them into the Components settings (add ScreenAspectRatio, CornerRadiusPreviewValue, and screen aspect init). Refactor ComponentsSettingsPage UI to show live previews. Improve DataSettingsPage layout and storage bar logic (use item percentages directly, include remaining segment, adjust visuals and visibility triggers). Simplify LauncherSettingsPage header/appearance layout. Add SECURITY_AUDIT_REPORT.md, analysis summary, mockup HTML, and a local .claude settings file. * Add install checkpoint/resume and DDSS workflows Introduce install checkpoint support and resume logic for updates, plus related locking and validation. Adds InstallCheckpoint model, AppJsonContext serialization, and UpdatePaths helpers for deployment lock, apply-in-progress lock and install-checkpoint path. UpdateEngineService gains checkpoint load/save/delete, incoming-state validation, resume logic for PLONDS and legacy updates, apply lock handling, and safer cleanup; ApplyPendingPlondsUpdateAsync and ApplyPendingUpdate flow updated accordingly. Add DeploymentLock contract and extend UpdateState with pause/resume/cancel helpers. Tests updated to cover stale/valid checkpoint resume and legacy/PLONDS flows. CI: enhance ddss-publish to detect release channel, validate S3 assets, prepare and atomically publish channel pointer; add ddss-rollback workflow to publish rollbacks; adjust plonds-build concurrency and release events. * changed.更了好多 * fix.消息盒子媒体播放器组件服务修复 * change.重做天气,为回到系统提供自定义功能。 * feat.airapp与融合桌面 * feat.动画优化与更新界面 * feat.数字时钟,白板功能修复 * feat.完善了时钟轻应用,为启动器提供了多语言支持 * feat.发布与打包优化 * changed.天气选项卡更新
13 KiB
13 KiB
StandBy Digital Clock - iPhone 待机风格大数字时钟组件
1. 需求场景与处理逻辑
1.1 需求描述
新增一个 4×2 尺寸的数字时钟桌面组件,视觉风格参考 iPhone 横屏充电时的 StandBy 待机显示——大面积、粗体、圆润的数字显示当前时间(HH:MM),数字采用不规则的自由排版(有微妙的垂直偏移,不在一条直线上),颜色使用 Monet 主题色而非纯黑/白,伴随数字切换时的流畅垂直滚动/翻转动画,下方显示日期信息。
1.2 用户体验目标
- 大字号、圆润粗体的数字时间,远距离一目了然
- 数字采用不规则自由排版(微妙垂直偏移),营造 iPhone StandBy 那种有机、散漫的视觉节奏
- 数字使用 Monet 主题色(跟随壁纸/用户选色的强调色),而非死板的纯黑/白
- 数字变化时执行垂直滑动动画(旧数字向上滑出,新数字从下方滑入),类似翻页时钟效果
- 冒号(:)有呼吸闪烁效果
- 支持夜间/日间模式自动切换
- 点击组件可打开世界时钟 AirApp
- 支持时区配置(与现有桌面时钟共享设置体系)
1.3 处理逻辑
- 组件加载时读取时区设置和秒针模式设置
DispatcherTimer每秒触发一次更新- 当检测到分钟数变化时,触发分钟数字的垂直滑动动画
- 当检测到小时数变化时,触发小时数字的垂直滑动动画
- 冒号以 1 秒周期做透明度脉冲动画
- 每 tick 检查是否需要切换日间/夜间视觉模式
2. 架构与技术方案
2.1 组件架构
遵循现有桌面组件架构模式:
- 继承
UserControl,实现IDesktopComponentWidget,ITimeZoneAwareComponentWidget,IComponentPlacementContextAware,IComponentRuntimeContextAware - AXAML 定义根布局结构,代码后置处理动画逻辑
- 通过
DesktopComponentDefinition注册到组件系统
2.2 数字滚动动画技术方案
采用 Avalonia RenderTransform + DoubleTransition 实现数字滚动:
核心思路:每个数位(共 4 位:H1, H2, M1, M2)使用 ClipToBounds 的容器,内含一个垂直排列的 StackPanel,包含当前数字和下一个数字。切换时通过 TranslateTransform.Y 的 DoubleTransition 实现平滑滚动。
每位数字的结构:
┌─ DigitClip (ClipToBounds=true) ──────────┐
│ ┌─ DigitStack (TranslateTransform.Y) ──┐ │
│ │ [当前数字 TextBlock] │ │
│ │ [新数字 TextBlock] │ │
│ └───────────────────────────────────────┘ │
└───────────────────────────────────────────┘
当数字变化时:
- 在 StackPanel 底部添加新数字的 TextBlock
- 将
TranslateTransform.Y从 0 动画过渡到-digitHeight - 动画完成后移除旧数字,重置 Y 为 0
2.3 动画参数
- 使用项目
FluttermotionToken体系:滚动动画时长FluttermotionToken.Standard(200ms) - 缓动函数:
CubicEaseOut(与项目现有动画风格一致) - 冒号呼吸动画:透明度 1.0 → 0.3 → 1.0,周期 2 秒,使用
DoubleTransition
2.4 尺寸与布局
- 组件定义:
MinWidthCells = 4, MinHeightCells = 2 - 缩放规则:2:1 比例(与 WorldClock 一致)
- 内部布局采用
Viewbox包裹,确保在不同 cellSize 下自适应缩放 - 数字字体大小:基准设计为 130px(在 Viewbox 内),实际显示由 Viewbox 缩放
2.5 布局风格——不规则自由排版(iPhone StandBy 风格)
iPhone StandBy 的数字不是规矩地排成一条直线,而是有微妙的垂直偏移和大小差异,营造出自由散漫、有机的视觉节奏:
H1 H2 : M1 M2
↗↘ ↘↗ ↗↘ ↘↗
↕+6 ↕+2 : ↕+4 ↕+2
↖ -3° ↗ +4° : ↖ -1° ↗ +5°
←+6,↑-10 ←-2,↓+10 →+4,↑-3 ←-2,↓+12
每个数字有三个自由度:
- 垂直偏移 (Y):H1=-10, H2=+10, 冒号=+8, M1=-3, M2=+12
- 水平偏移 (X):H1=+6, H2=-2, 冒号=0, M1=+4, M2=-2
- 旋转角度 (Z):H1=-4°, H2=+3°, 冒号=-1°, M1=-2°, M2=+5°
2.6 视觉风格——圆润粗体 + Monet 主题色
- 字体:
FontWeight.Bold,配合较大的字号,视觉上圆润饱满 - 颜色:使用项目 Monet 主题色系统,数字颜色跟随
AdaptiveAccentBrush/SystemAccentColor,而非纯黑/白- 数字颜色通过
ComponentColorSchemeHelper.ShouldUseMonetColor()判断:- 跟随系统:使用
AdaptiveAccentBrush(Monet 提取的强调色) - 原生模式:使用组件自带的特色色彩
- 跟随系统:使用
- 夜间模式:深色渐变背景 + 主题色数字(亮色调)
- 日间模式:浅色渐变背景 + 主题色数字(深色调)
- 夜间暗光环境:数字过渡到柔和的红色调(
#FF6B4A),模拟 iPhone StandBy 夜间红色调
- 数字颜色通过
- 冒号颜色:与数字同色,但有呼吸动画
- 日期行:使用
AdaptiveTextMutedBrush(跟随主题的弱化文字色),字号约 14-16px 基准 - 根容器圆角:
DesignCornerRadiusComponent(遵循圆角规范)
3. 受影响文件
3.1 新增文件
| 文件 | 类型 | 说明 |
|---|---|---|
LanMountainDesktop/Views/Components/StandbyDigitalClockWidget.axaml |
新增 | 组件 AXAML 布局 |
LanMountainDesktop/Views/Components/StandbyDigitalClockWidget.axaml.cs |
新增 | 组件代码后置(动画逻辑、时间更新、模式切换) |
3.2 修改文件
| 文件 | 修改类型 | 受影响函数/区域 |
|---|---|---|
LanMountainDesktop/ComponentSystem/BuiltInComponentIds.cs |
新增常量 | 新增 DesktopStandbyDigitalClock 常量 |
LanMountainDesktop/ComponentSystem/ComponentRegistry.cs |
新增定义 | CreateDefault() 中新增组件定义 |
LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs |
新增运行时注册 | GetDefaultRegistrations() 中新增运行时注册项 |
LanMountainDesktop/Views/MainWindow.ComponentSystem.cs |
新增缩放规则 | NormalizeAspectRatioForComponent() 中为 StandbyDigitalClock 添加 2:1 缩放规则 |
4. 实现细节
4.1 BuiltInComponentIds 新增常量
public const string DesktopStandbyDigitalClock = "DesktopStandbyDigitalClock";
4.2 ComponentRegistry 新增定义
new DesktopComponentDefinition(
BuiltInComponentIds.DesktopStandbyDigitalClock,
"StandBy Clock",
"Clock",
"Clock",
MinWidthCells: 4,
MinHeightCells: 2,
AllowStatusBarPlacement: false,
AllowDesktopPlacement: true),
4.3 DesktopComponentRuntimeRegistry 新增注册
new DesktopComponentRuntimeRegistration(
BuiltInComponentIds.DesktopStandbyDigitalClock,
"component.standby_digital_clock",
() => new StandbyDigitalClockWidget()),
4.4 NormalizeAspectRatioForComponent 缩放规则
在 case BuiltInComponentIds.DesktopWorldClock: 的同一分支中添加 BuiltInComponentIds.DesktopStandbyDigitalClock,使用 2:1 比例规则。
4.5 AXAML 布局结构
<UserControl x:Class="LanMountainDesktop.Views.Components.StandbyDigitalClockWidget">
<Border x:Name="RootBorder"
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
ClipToBounds="True"
Padding="14">
<!-- 背景在代码后置中设置(渐变,与AnalogClockWidget一致) -->
<Viewbox Stretch="Uniform">
<Grid Width="400" Height="200">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center"
Orientation="Horizontal">
<!-- H1 数位 -->
<Border x:Name="H1Clip" ClipToBounds="True" ...>
<Panel x:Name="H1Stack" ...>
<TextBlock x:Name="H1Text" Text="0" ... />
</Panel>
</Border>
<!-- H2 数位 -->
<Border x:Name="H2Clip" ClipToBounds="True" ...>
<Panel x:Name="H2Stack" ...>
<TextBlock x:Name="H2Text" Text="0" ... />
</Panel>
</Border>
<!-- 冒号 -->
<TextBlock x:Name="ColonText" Text=":" ... />
<!-- M1 数位 -->
<Border x:Name="M1Clip" ClipToBounds="True" ...>
<Panel x:Name="M1Stack" ...>
<TextBlock x:Name="M1Text" Text="0" ... />
</Panel>
</Border>
<!-- M2 数位 -->
<Border x:Name="M2Clip" ClipToBounds="True" ...>
<Panel x:Name="M2Stack" ...>
<TextBlock x:Name="M2Text" Text="0" ... />
</Panel>
</Border>
</StackPanel>
<!-- 日期行 -->
<TextBlock x:Name="DateTextBlock"
VerticalAlignment="Bottom"
HorizontalAlignment="Center" ... />
</Grid>
</Viewbox>
</Border>
</UserControl>
4.6 数字滚动动画核心代码(伪代码)
private void AnimateDigit(Border clip, Panel stack, TextBlock currentText, char newDigit, double digitHeight)
{
var oldText = currentText;
var newTextBlock = new TextBlock
{
Text = newDigit.ToString(),
FontSize = oldText.FontSize,
FontWeight = oldText.FontWeight,
Foreground = oldText.Foreground,
Width = oldText.Width,
Height = digitHeight,
// 复制旧文本的所有样式属性
};
stack.Children.Add(newTextBlock);
// 应用 TranslateTransform 过渡动画
var transform = new TranslateTransform { Y = 0 };
stack.RenderTransform = transform;
stack.Transitions = new Transitions
{
new DoubleTransition(TranslateTransform.YProperty, FluttermotionToken.Standard, new CubicEaseOut())
};
// 触发动画:从当前位置滑到 -digitHeight
transform.Y = -digitHeight;
// 动画完成后清理
_ = DispatcherTimer.RunOnce(() =>
{
stack.Children.Remove(oldText);
transform.Y = 0;
stack.Transitions = null; // 移除过渡,避免重置时再次动画
// 更新引用
UpdateCurrentTextReference(newTextBlock);
}, FluttermotionToken.Standard);
}
4.7 冒号呼吸动画
使用 DispatcherTimer 每秒切换冒号透明度:
private void ToggleColonOpacity()
{
_colonVisible = !_colonVisible;
ColonText.Opacity = _colonVisible ? 1.0 : 0.3;
}
配合 DoubleTransition 使透明度变化平滑过渡。
4.8 日间/夜间模式
与 AnalogClockWidget 使用完全相同的判断逻辑:
- 检查
ActualThemeVariant - 回退到
AdaptiveSurfaceBaseBrush亮度计算 - 夜间模式:深色渐变背景 + 浅色数字
- 日间模式:浅色渐变背景 + 深色数字
4.9 时区与设置
- 复用
AnalogClockWidget的时区解析和设置加载逻辑 - 使用
ComponentSettingsSnapshot.DesktopClockTimeZoneId读取时区配置 - 点击打开世界时钟 AirApp
5. 边界条件与异常处理
| 场景 | 处理方式 |
|---|---|
| 组件首次加载时数字尚未初始化 | 在构造函数中初始化所有数字为当前时间,不触发动画 |
| 快速连续触发数字变化(如时间同步导致跳变) | 在动画完成前忽略新的变化请求,或中断当前动画立即跳转到目标值 |
| cellSize 极小或极大 | ApplyCellSize 中 clamp 缩放因子(0.58-1.95,与 AnalogClockWidget 一致) |
| 时区切换 | 重新加载设置并更新所有数字(无动画,直接设置) |
| 主题切换 | 通过 ApplyModeVisualIfNeeded() 在下一个 tick 自动检测并切换 |
| 组件被销毁 | DetachedFromVisualTree 停止 timer,清理资源 |
| 冒号动画在组件不可见时 | timer 仍在运行但 Opacity 变化无性能开销;若需要可结合 IDesktopPageVisibilityAwareComponentWidget |
6. 数据流路径
DispatcherTimer (1s interval)
→ OnTimerTick
→ 计算当前时间 (TimeZoneInfo.ConvertTimeFromUtc)
→ 比较新旧时间数字
→ 若有变化: AnimateDigit() 执行滚动动画
→ ToggleColonOpacity() 切换冒号
→ ApplyModeVisualIfNeeded() 检查日/夜间切换
→ UpdateDateText() 更新日期文本
用户点击 → OnPointerReleased → AirAppLauncherServiceProvider.OpenWorldClock()
时区变更 → TimeZoneChanged event → RefreshFromSettings() → 无动画更新所有数字
7. 预期成果
- 在桌面组件选择器中新增 "StandBy Clock" 组件,位于 Clock 分类
- 拖放到桌面后显示 4×2 大数字时钟
- 数字切换时有流畅的垂直滑动动画
- 冒号有呼吸闪烁效果
- 支持日间/夜间自动切换
- 支持时区配置
- 支持组件缩放(2:1 比例规则)