mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-22 00:54:26 +08:00
Convert the settings window into an independent top-level window with its own taskbar icon and open-or-focus semantics. Removed Owner/anchor/toggle semantics from SettingsWindowService and added ScreenReferenceWindow for centering; settings windows now ShowInTaskbar = true and are truly destroyed on close. Added SettingsWindowPlacementHelper and tests for placement/centering. Main window now respects an AppSettingsSnapshot.ShowInTaskbar flag (new setting exposed in GeneralSettings UI) and slide/visibility animations and "back to Windows" behavior no longer affect the independent settings window. Updated various callers to use OpenIndependentSettingsModule, adjusted window transitions/X offsets, and added/updated spec files documenting the feature and animation boundary.
148 lines
7.0 KiB
Markdown
148 lines
7.0 KiB
Markdown
# 窗口过渡动画 Spec
|
||
|
||
## Why
|
||
|
||
当前全屏窗口在"回到 Windows"(最小化)和"恢复应用"时存在严重的视觉问题:
|
||
1. 恢复时经历 `Minimized → Normal → FullScreen` 两步跳变,用户会短暂看到无框小窗口
|
||
2. 状态切换无任何过渡动画,体验生硬
|
||
3. `OnWindowPropertyChanged` 使用 `Dispatcher.UIThread.Post` 延迟纠正,进一步延长了 Normal 中间态的可见时间
|
||
|
||
## What Changes
|
||
|
||
- 在 `MainWindow.axaml` 的 `DesktopPage` 上添加 `TranslateTransform` 和 `TranslateTransform.X` 过渡动画
|
||
- 修改 `MainWindow.axaml.cs` 的 `OnMinimizeClick`,实现退场动画(滑出/淡出 → 最小化)
|
||
- 修改 `App.axaml.cs` 的 `RestoreOrCreateMainWindow`,实现入场动画(全屏 → 滑入/淡入)
|
||
- 修改 `MainWindow.axaml.cs` 的 `OnWindowPropertyChanged`,在动画期间暂停强制全屏逻辑
|
||
- 在 `AppSettingsSnapshot` 中添加 `EnableSlideTransition` 设置项(默认关闭)
|
||
- 在 `GeneralSettingsPageViewModel` 中添加对应 ViewModel 属性
|
||
- 在 `GeneralSettingsPage.axaml` 中添加开关 UI(仅 Windows 平台显示)
|
||
- 添加平台检测逻辑:Windows 且开启设置时使用滑入滑出,其他情况使用 Opacity 淡入淡出
|
||
|
||
## Impact
|
||
|
||
- Affected specs: 窗口生命周期过渡动画
|
||
- Affected code:
|
||
- `LanMountainDesktop/Views/MainWindow.axaml` - DesktopPage 添加 TranslateTransform
|
||
- `LanMountainDesktop/Views/MainWindow.axaml.cs` - OnMinimizeClick、OnWindowPropertyChanged、新增动画方法
|
||
- `LanMountainDesktop/App.axaml.cs` - RestoreOrCreateMainWindow、OnMainWindowPropertyChanged
|
||
- `LanMountainDesktop/Models/AppSettingsSnapshot.cs` - 新增 EnableSlideTransition 字段
|
||
- `LanMountainDesktop/ViewModels/SettingsViewModels.cs` - GeneralSettingsPageViewModel 新增属性
|
||
- `LanMountainDesktop/Views/SettingsPages/GeneralSettingsPage.axaml` - 新增开关 UI
|
||
|
||
---
|
||
|
||
## ADDED Requirements
|
||
|
||
### Requirement: 窗口退场过渡动画
|
||
|
||
系统 SHALL 在主窗口最小化/隐藏时播放退场过渡动画,消除窗口状态跳变的视觉闪烁。
|
||
|
||
#### Scenario: Opacity 淡出退场(所有平台默认)
|
||
- **WHEN** 用户点击"回到 Windows"或触发最小化
|
||
- **THEN** 系统将 `DesktopPage.Opacity` 设为 0,触发淡出动画
|
||
- **AND THEN** 动画完成后执行 `WindowState = Minimized`
|
||
- **AND THEN** 最小化完成后重置 `DesktopPage.Opacity = 1`(窗口已不可见)
|
||
|
||
#### Scenario: 滑出退场(Windows + 开启设置)
|
||
- **WHEN** 用户点击"回到 Windows"且运行在 Windows 平台且已开启滑入滑出设置
|
||
- **THEN** 系统同时将 `DesktopPage.Opacity` 设为 0 且 `DesktopPageSlideTransform.X` 设为屏幕宽度
|
||
- **AND THEN** 动画完成后执行 `WindowState = Minimized`
|
||
- **AND THEN** 最小化完成后重置 `DesktopPageSlideTransform.X = 0` 和 `DesktopPage.Opacity = 1`
|
||
|
||
### Requirement: 窗口入场过渡动画
|
||
|
||
系统 SHALL 在主窗口恢复时播放入场过渡动画,消除 Normal 中间态的视觉闪烁。
|
||
|
||
#### Scenario: Opacity 淡入入场(所有平台默认)
|
||
- **WHEN** 主窗口从最小化/隐藏状态恢复
|
||
- **THEN** 系统先将 `DesktopPage.Opacity` 设为 0(遮住 Normal 中间态)
|
||
- **AND THEN** 完成 `Minimized → Normal → FullScreen` 状态切换
|
||
- **AND THEN** 等 FullScreen 状态生效后将 `DesktopPage.Opacity` 设为 1,触发淡入动画
|
||
|
||
#### Scenario: 滑入入场(Windows + 开启设置)
|
||
- **WHEN** 主窗口从最小化/隐藏状态恢复且运行在 Windows 平台且已开启滑入滑出设置
|
||
- **THEN** 系统先将 `DesktopPage.Opacity` 设为 0 且 `DesktopPageSlideTransform.X` 设为屏幕宽度
|
||
- **AND THEN** 完成 `Minimized → Normal → FullScreen` 状态切换
|
||
- **AND THEN** 等 FullScreen 状态生效后同时将 `DesktopPage.Opacity` 设为 1 且 `DesktopPageSlideTransform.X` 设为 0,触发滑入+淡入组合动画
|
||
|
||
### Requirement: 动画期间交互保护
|
||
|
||
系统 SHALL 在过渡动画播放期间防止用户交互和状态冲突。
|
||
|
||
#### Scenario: 动画期间禁止交互
|
||
- **WHEN** 退场或入场动画正在播放
|
||
- **THEN** `DesktopPage.IsHitTestVisible` 设为 `false`
|
||
- **AND THEN** 动画完成后恢复为 `true`
|
||
|
||
#### Scenario: 动画期间暂停强制全屏
|
||
- **WHEN** 入场动画正在播放且窗口临时处于 Normal 状态
|
||
- **THEN** `OnWindowPropertyChanged` 不执行强制全屏纠正
|
||
- **AND THEN** 入场动画完成后恢复正常强制全屏逻辑
|
||
|
||
#### Scenario: 防止快速连续操作
|
||
- **WHEN** 用户在动画播放期间再次触发最小化或恢复
|
||
- **THEN** 系统忽略重复操作,避免动画冲突
|
||
|
||
### Requirement: 滑入滑出设置项
|
||
|
||
系统 SHALL 在基本设置页面提供"滑入滑出过渡效果"开关,仅 Windows 平台可见。
|
||
|
||
#### Scenario: 设置项可见性
|
||
- **WHEN** 用户在 Windows 平台打开基本设置页面
|
||
- **THEN** 显示"滑入滑出过渡效果"开关
|
||
- **WHEN** 用户在非 Windows 平台打开基本设置页面
|
||
- **THEN** 不显示该开关
|
||
|
||
#### Scenario: 设置项默认值
|
||
- **WHEN** 用户首次安装应用
|
||
- **THEN** `EnableSlideTransition` 默认为 `false`
|
||
|
||
#### Scenario: 设置持久化
|
||
- **WHEN** 用户切换"滑入滑出过渡效果"开关
|
||
- **THEN** 设置值立即持久化到 `AppSettingsSnapshot.EnableSlideTransition`
|
||
- **AND THEN** 下次窗口过渡时立即生效,无需重启
|
||
|
||
### Requirement: DesktopPage TranslateTransform 声明
|
||
|
||
系统 SHALL 在 `DesktopPage` 上声明 `TranslateTransform` 和对应的过渡动画。
|
||
|
||
#### Scenario: XAML 声明
|
||
- **WHEN** MainWindow 初始化
|
||
- **THEN** `DesktopPage` 拥有名为 `DesktopPageSlideTransform` 的 `TranslateTransform`
|
||
- **AND THEN** `DesktopPage.Transitions` 包含 `Opacity` 和 `TranslateTransform.X` 两个过渡
|
||
- **AND THEN** 过渡时长使用 `FluttermotionToken.Duration.Page`(320ms)和 `FluttermotionToken.Duration.Intro`(400ms)
|
||
- **AND THEN** 缓动函数使用 `0.05,0.75,0.10,1.00`(DecelerateBezier)
|
||
|
||
### Requirement: 设置窗口不参与桌面壳过渡动画
|
||
|
||
系统 SHALL 将桌面壳进出场动画限制在主窗口范围内,不影响独立设置窗口。
|
||
|
||
#### Scenario: 设置窗口在桌面动画期间保持独立
|
||
- **WHEN** 主窗口执行滑入、滑出、最小化或恢复动画
|
||
- **THEN** 设置窗口不参与该动画
|
||
- **AND THEN** 设置窗口不会跟随主窗口一起隐藏、最小化或重定位
|
||
|
||
## MODIFIED Requirements
|
||
|
||
### Requirement: OnMinimizeClick 行为
|
||
|
||
**当前**: 直接设置 `WindowState = WindowState.Minimized`,无动画
|
||
|
||
**修改后**: 先播放退场动画,动画完成后再设置 `WindowState = WindowState.Minimized`
|
||
|
||
### Requirement: RestoreOrCreateMainWindow 行为
|
||
|
||
**当前**: `Show() → Normal → FullScreen`,无过渡动画,用户可见 Normal 中间态
|
||
|
||
**修改后**: 先将 `DesktopPage` 设为不可见(Opacity=0 + 可选滑出位),再执行状态切换,最后播放入场动画
|
||
|
||
### Requirement: OnWindowPropertyChanged 强制全屏逻辑
|
||
|
||
**当前**: 任何非 Minimized/FullScreen 状态立即纠正为 FullScreen
|
||
|
||
**修改后**: 动画期间允许临时 Normal 状态存在,动画完成后恢复强制全屏逻辑
|
||
|
||
## REMOVED Requirements
|
||
|
||
无移除的需求。
|