mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-23 18:04:26 +08:00
Add startup visual modes and attempt registry
Implement startup visual behavior, de-duplicate startup attempts, and improve failure UX. Key changes: - Add spec and docs for startup visuals and timing contract (.trae/specs and docs/LAUNCHER_STARTUP_VISUALS.md). - Introduce StartupVisualPreferences contract and resolver; create SplashWindow via resolved mode. - Add StartupAttemptRecord model and a file-backed StartupAttemptRegistry to persist and coordinate in-progress startup attempts (attach/adopt, soft/hard timeouts, IPC/connect state, lifecycle updates). - Update LauncherFlowCoordinator to: adopt/attach to existing attempts, track IPC connection and soft/hard timeouts (30s/120s), show delayed UI state, attempt foreground recovery via public IPC, compose detailed launch result metadata, and mark registry states (soft timeout, detached waiting, succeeded, failed). - Add TryActivateExistingInstanceAsync to attempt activating an existing desktop via IPC. - Change failure flow: ShowFailureWindowAsync now returns user choice; ErrorWindow updated to present Activate/Wait/Open Logs/Exit semantics and new layouts/styles; improved button wiring and debug/dev mode handling. - Add UI and resource tweaks (ErrorWindow and SplashWindow changes), project asset link for nightly logo, and unit tests for StartupVisualPreferences. These changes prevent duplicate desktop processes during slow startups, provide clearer UX for delayed startups, and persist startup attempt state across Launcher invocations for safer recovery/attach behavior.
This commit is contained in:
@@ -719,7 +719,10 @@ public partial class App : Application
|
||||
mainWindow.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
if (mainWindow.WindowState != WindowState.FullScreen)
|
||||
mainWindow.EnsureForegroundWindowLayout();
|
||||
|
||||
if (mainWindow.ShouldUseFullscreenWindow() &&
|
||||
mainWindow.WindowState != WindowState.FullScreen)
|
||||
{
|
||||
mainWindow.WindowState = WindowState.FullScreen;
|
||||
}
|
||||
@@ -1359,7 +1362,10 @@ public partial class App : Application
|
||||
mainWindow.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
if (mainWindow.WindowState != WindowState.FullScreen)
|
||||
mainWindow.EnsureForegroundWindowLayout();
|
||||
|
||||
if (mainWindow.ShouldUseFullscreenWindow() &&
|
||||
mainWindow.WindowState != WindowState.FullScreen)
|
||||
{
|
||||
mainWindow.WindowState = WindowState.FullScreen;
|
||||
}
|
||||
|
||||
@@ -152,6 +152,8 @@ public sealed class AppSettingsSnapshot
|
||||
|
||||
public bool EnableThreeFingerSwipe { get; set; } = false;
|
||||
|
||||
public bool EnableFadeTransition { get; set; } = true;
|
||||
|
||||
public bool EnableSlideTransition { get; set; } = false;
|
||||
|
||||
public bool ShowInTaskbar { get; set; } = false;
|
||||
|
||||
@@ -13,6 +13,7 @@ using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
using LanMountainDesktop.Settings.Core;
|
||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||
|
||||
namespace LanMountainDesktop.ViewModels;
|
||||
|
||||
@@ -201,7 +202,7 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo
|
||||
SelectedRenderMode = RenderModes.FirstOrDefault(option =>
|
||||
string.Equals(option.Value, normalizedRenderMode, StringComparison.OrdinalIgnoreCase))
|
||||
?? RenderModes[0];
|
||||
EnableSlideTransition = appSnapshot.EnableSlideTransition;
|
||||
ApplyTransitionPreferences(appSnapshot.EnableFadeTransition, appSnapshot.EnableSlideTransition);
|
||||
ShowInTaskbar = appSnapshot.ShowInTaskbar;
|
||||
_isInitializing = false;
|
||||
|
||||
@@ -235,9 +236,11 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo
|
||||
return;
|
||||
}
|
||||
|
||||
if (changedKeys.Contains(nameof(AppSettingsSnapshot.EnableSlideTransition)))
|
||||
if (changedKeys.Contains(nameof(AppSettingsSnapshot.EnableSlideTransition)) ||
|
||||
changedKeys.Contains(nameof(AppSettingsSnapshot.EnableFadeTransition)))
|
||||
{
|
||||
EnableSlideTransition = _settingsFacade.Settings.LoadSnapshot<AppSettingsSnapshot>(SettingsScope.App).EnableSlideTransition;
|
||||
var snapshot = _settingsFacade.Settings.LoadSnapshot<AppSettingsSnapshot>(SettingsScope.App);
|
||||
ApplyTransitionPreferences(snapshot.EnableFadeTransition, snapshot.EnableSlideTransition);
|
||||
}
|
||||
|
||||
if (changedKeys.Contains(nameof(AppSettingsSnapshot.ShowInTaskbar)))
|
||||
@@ -263,6 +266,9 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo
|
||||
[ObservableProperty]
|
||||
private SelectionOption _selectedRenderMode = new(AppRenderingModeHelper.Default, "Default");
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _enableFadeTransition = true;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _enableSlideTransition;
|
||||
|
||||
@@ -271,6 +277,12 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo
|
||||
|
||||
public bool IsSlideTransitionAvailable => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows);
|
||||
|
||||
public bool IsFadeTransitionToggleEnabled => !EnableSlideTransition;
|
||||
|
||||
public string FadeTransitionDescription => EnableSlideTransition
|
||||
? "滑动模式已启用,淡入淡出不可同时使用。"
|
||||
: "启用后,启动与恢复过程使用淡入淡出效果。";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _pageTitle = string.Empty;
|
||||
|
||||
@@ -372,8 +384,22 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo
|
||||
|
||||
partial void OnEnableSlideTransitionChanged(bool value)
|
||||
{
|
||||
if (_isInitializing) return;
|
||||
SaveField(nameof(AppSettingsSnapshot.EnableSlideTransition), value);
|
||||
if (_isInitializing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SaveTransitionPreferences(EnableFadeTransition, value);
|
||||
}
|
||||
|
||||
partial void OnEnableFadeTransitionChanged(bool value)
|
||||
{
|
||||
if (_isInitializing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SaveTransitionPreferences(value, EnableSlideTransition);
|
||||
}
|
||||
|
||||
partial void OnShowInTaskbarChanged(bool value)
|
||||
@@ -394,6 +420,35 @@ public sealed partial class GeneralSettingsPageViewModel : ViewModelBase, IDispo
|
||||
_settingsFacade.Settings.SaveSnapshot(SettingsScope.App, snapshot, changedKeys: [key]);
|
||||
}
|
||||
|
||||
private void SaveTransitionPreferences(bool enableFadeTransition, bool enableSlideTransition)
|
||||
{
|
||||
var normalized = StartupVisualPreferencesResolver.FromFlags(enableFadeTransition, enableSlideTransition);
|
||||
var snapshot = _settingsFacade.Settings.LoadSnapshot<AppSettingsSnapshot>(SettingsScope.App);
|
||||
snapshot.EnableFadeTransition = normalized.EnableFadeTransition;
|
||||
snapshot.EnableSlideTransition = normalized.EnableSlideTransition;
|
||||
ApplyTransitionPreferences(normalized.EnableFadeTransition, normalized.EnableSlideTransition);
|
||||
_settingsFacade.Settings.SaveSnapshot(
|
||||
SettingsScope.App,
|
||||
snapshot,
|
||||
changedKeys:
|
||||
[
|
||||
nameof(AppSettingsSnapshot.EnableFadeTransition),
|
||||
nameof(AppSettingsSnapshot.EnableSlideTransition)
|
||||
]);
|
||||
}
|
||||
|
||||
private void ApplyTransitionPreferences(bool enableFadeTransition, bool enableSlideTransition)
|
||||
{
|
||||
var normalized = StartupVisualPreferencesResolver.FromFlags(enableFadeTransition, enableSlideTransition);
|
||||
var wasInitializing = _isInitializing;
|
||||
_isInitializing = true;
|
||||
EnableFadeTransition = normalized.EnableFadeTransition;
|
||||
EnableSlideTransition = normalized.EnableSlideTransition;
|
||||
_isInitializing = wasInitializing;
|
||||
OnPropertyChanged(nameof(IsFadeTransitionToggleEnabled));
|
||||
OnPropertyChanged(nameof(FadeTransitionDescription));
|
||||
}
|
||||
|
||||
private IReadOnlyList<SelectionOption> CreateLanguageOptions()
|
||||
{
|
||||
return
|
||||
|
||||
@@ -79,6 +79,7 @@ public partial class MainWindow
|
||||
string.Equals(key, nameof(AppSettingsSnapshot.UpdateDownloadSource), StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(key, nameof(AppSettingsSnapshot.UpdateDownloadThreads), StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(key, nameof(AppSettingsSnapshot.EnableThreeFingerSwipe), StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(key, nameof(AppSettingsSnapshot.EnableFadeTransition), StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(key, nameof(AppSettingsSnapshot.ShowInTaskbar), StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(key, nameof(AppSettingsSnapshot.EnableSlideTransition), StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
@@ -690,6 +691,7 @@ public partial class MainWindow
|
||||
StatusBarShadowColor = _statusBarShadowColor,
|
||||
StatusBarShadowOpacity = _statusBarShadowOpacity,
|
||||
EnableThreeFingerSwipe = existingSnapshot.EnableThreeFingerSwipe,
|
||||
EnableFadeTransition = existingSnapshot.EnableFadeTransition,
|
||||
EnableSlideTransition = existingSnapshot.EnableSlideTransition,
|
||||
ShowInTaskbar = existingSnapshot.ShowInTaskbar,
|
||||
EnableFusedDesktop = existingSnapshot.EnableFusedDesktop,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -23,6 +24,7 @@ using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||
using LanMountainDesktop.Theme;
|
||||
using LanMountainDesktop.Views.Components;
|
||||
|
||||
@@ -134,6 +136,8 @@ public partial class MainWindow : Window
|
||||
private string _gridSpacingPreset = "Relaxed";
|
||||
private bool _isSlideAnimationActive;
|
||||
private TranslateTransform? _desktopPageSlideTransform;
|
||||
private PixelPoint? _preparedWindowTargetPosition;
|
||||
private PixelPoint? _preparedWindowHiddenPosition;
|
||||
private string _statusBarSpacingMode = "Relaxed";
|
||||
private int _statusBarCustomSpacingPercent = 12;
|
||||
private bool _statusBarClockTransparentBackground;
|
||||
@@ -862,24 +866,45 @@ public partial class MainWindow : Window
|
||||
return _desktopPageSlideTransform;
|
||||
}
|
||||
|
||||
internal bool ShouldUseFullscreenWindow()
|
||||
{
|
||||
return GetStartupVisualPreferences().Mode != StartupVisualMode.SlideSplash;
|
||||
}
|
||||
|
||||
internal void EnsureForegroundWindowLayout()
|
||||
{
|
||||
if (!IsSlideTransitionEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var layout = ResolveWindowAnimationLayout();
|
||||
ApplyWindowAnimationLayout(layout);
|
||||
Position = layout.VisiblePosition;
|
||||
}
|
||||
|
||||
private async void SlideOutAndMinimizeAsync()
|
||||
{
|
||||
_isSlideAnimationActive = true;
|
||||
DesktopPage.IsHitTestVisible = false;
|
||||
|
||||
var useSlide = IsSlideTransitionEnabled();
|
||||
var slideTransform = GetDesktopPageSlideTransform();
|
||||
var preferences = GetStartupVisualPreferences();
|
||||
WindowAnimationLayout? slideLayout = null;
|
||||
|
||||
if (useSlide)
|
||||
if (preferences.Mode == StartupVisualMode.SlideSplash)
|
||||
{
|
||||
slideTransform.X = Bounds.Width;
|
||||
slideLayout = ResolveWindowAnimationLayout();
|
||||
ApplyWindowAnimationLayout(slideLayout.Value);
|
||||
await AnimateWindowPositionAsync(
|
||||
Position,
|
||||
slideLayout.Value.HiddenPosition,
|
||||
FluttermotionToken.Intro).ConfigureAwait(false);
|
||||
}
|
||||
else if (preferences.Mode == StartupVisualMode.Fade)
|
||||
{
|
||||
DesktopPage.Opacity = 0;
|
||||
await Task.Delay(FluttermotionToken.Page);
|
||||
}
|
||||
|
||||
DesktopPage.Opacity = 0;
|
||||
|
||||
await Task.Delay(useSlide
|
||||
? FluttermotionToken.Intro
|
||||
: FluttermotionToken.Page);
|
||||
|
||||
if (!_isSlideAnimationActive)
|
||||
{
|
||||
@@ -900,44 +925,63 @@ public partial class MainWindow : Window
|
||||
WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
slideTransform.X = 0;
|
||||
DesktopPage.Opacity = 1;
|
||||
DesktopPage.IsHitTestVisible = true;
|
||||
_isSlideAnimationActive = false;
|
||||
if (slideLayout is { } layout)
|
||||
{
|
||||
Position = layout.VisiblePosition;
|
||||
}
|
||||
}
|
||||
|
||||
public void PrepareEnterAnimation()
|
||||
{
|
||||
_isSlideAnimationActive = false;
|
||||
|
||||
var useSlide = IsSlideTransitionEnabled();
|
||||
var slideTransform = GetDesktopPageSlideTransform();
|
||||
var preferences = GetStartupVisualPreferences();
|
||||
_preparedWindowTargetPosition = null;
|
||||
_preparedWindowHiddenPosition = null;
|
||||
|
||||
var savedTransitions = DesktopPage.Transitions;
|
||||
DesktopPage.Transitions = null;
|
||||
|
||||
DesktopPage.Opacity = 0;
|
||||
|
||||
if (useSlide)
|
||||
if (preferences.Mode == StartupVisualMode.SlideSplash)
|
||||
{
|
||||
var screen = Screens.ScreenFromVisual(this);
|
||||
var scale = screen?.Scaling ?? 1d;
|
||||
var screenWidthDip = screen is null
|
||||
? 1920d
|
||||
: screen.WorkingArea.Width / Math.Max(scale, 0.01d);
|
||||
slideTransform.X = Bounds.Width > 0 ? Bounds.Width : screenWidthDip;
|
||||
var layout = ResolveWindowAnimationLayout();
|
||||
_preparedWindowTargetPosition = layout.VisiblePosition;
|
||||
_preparedWindowHiddenPosition = layout.HiddenPosition;
|
||||
ApplyWindowAnimationLayout(layout);
|
||||
Position = layout.HiddenPosition;
|
||||
DesktopPage.Opacity = 1;
|
||||
DesktopPage.IsHitTestVisible = false;
|
||||
_isSlideAnimationActive = true;
|
||||
return;
|
||||
}
|
||||
|
||||
DesktopPage.Transitions = savedTransitions;
|
||||
DesktopPage.IsHitTestVisible = false;
|
||||
_isSlideAnimationActive = true;
|
||||
if (preferences.Mode == StartupVisualMode.Fade)
|
||||
{
|
||||
var savedTransitions = DesktopPage.Transitions;
|
||||
DesktopPage.Transitions = null;
|
||||
DesktopPage.Opacity = 0;
|
||||
DesktopPage.Transitions = savedTransitions;
|
||||
DesktopPage.IsHitTestVisible = false;
|
||||
_isSlideAnimationActive = true;
|
||||
return;
|
||||
}
|
||||
|
||||
DesktopPage.Opacity = 1;
|
||||
DesktopPage.IsHitTestVisible = true;
|
||||
}
|
||||
|
||||
public void PlayEnterAnimation()
|
||||
{
|
||||
var slideTransform = GetDesktopPageSlideTransform();
|
||||
var preferences = GetStartupVisualPreferences();
|
||||
if (preferences.Mode == StartupVisualMode.SlideSplash &&
|
||||
_preparedWindowTargetPosition is { } targetPosition &&
|
||||
_preparedWindowHiddenPosition is { } hiddenPosition)
|
||||
{
|
||||
_ = PlayWindowEnterAnimationAsync(hiddenPosition, targetPosition);
|
||||
return;
|
||||
}
|
||||
|
||||
DesktopPage.Opacity = 1;
|
||||
slideTransform.X = 0;
|
||||
DesktopPage.IsHitTestVisible = true;
|
||||
_isSlideAnimationActive = false;
|
||||
}
|
||||
@@ -949,10 +993,67 @@ public partial class MainWindow : Window
|
||||
return false;
|
||||
}
|
||||
|
||||
var snapshot = _settingsService.LoadSnapshot<AppSettingsSnapshot>(SettingsScope.App);
|
||||
return snapshot.EnableSlideTransition;
|
||||
return GetStartupVisualPreferences().Mode == StartupVisualMode.SlideSplash;
|
||||
}
|
||||
|
||||
private StartupVisualPreferences GetStartupVisualPreferences()
|
||||
{
|
||||
var snapshot = _settingsService.LoadSnapshot<AppSettingsSnapshot>(SettingsScope.App);
|
||||
return StartupVisualPreferencesResolver.FromFlags(
|
||||
snapshot.EnableFadeTransition,
|
||||
snapshot.EnableSlideTransition);
|
||||
}
|
||||
|
||||
private WindowAnimationLayout ResolveWindowAnimationLayout()
|
||||
{
|
||||
var screen = Screens.ScreenFromVisual(this) ?? Screens.Primary ?? Screens.All.FirstOrDefault();
|
||||
var workingArea = screen?.WorkingArea ?? new PixelRect(0, 0, 1920, 1080);
|
||||
var scaling = Math.Max(screen?.Scaling ?? 1d, 0.01d);
|
||||
|
||||
return new WindowAnimationLayout(
|
||||
new PixelPoint(workingArea.X, workingArea.Y),
|
||||
new PixelPoint(workingArea.X + workingArea.Width, workingArea.Y),
|
||||
new Size(workingArea.Width / scaling, workingArea.Height / scaling));
|
||||
}
|
||||
|
||||
private void ApplyWindowAnimationLayout(WindowAnimationLayout layout)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
Width = layout.WindowSize.Width;
|
||||
Height = layout.WindowSize.Height;
|
||||
}
|
||||
|
||||
private async Task PlayWindowEnterAnimationAsync(PixelPoint hiddenPosition, PixelPoint targetPosition)
|
||||
{
|
||||
Position = hiddenPosition;
|
||||
await AnimateWindowPositionAsync(hiddenPosition, targetPosition, FluttermotionToken.Intro);
|
||||
DesktopPage.IsHitTestVisible = true;
|
||||
_isSlideAnimationActive = false;
|
||||
}
|
||||
|
||||
private async Task AnimateWindowPositionAsync(PixelPoint from, PixelPoint to, TimeSpan duration)
|
||||
{
|
||||
var totalMilliseconds = Math.Max(duration.TotalMilliseconds, 1d);
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
|
||||
while (stopwatch.Elapsed < duration)
|
||||
{
|
||||
var progress = Math.Clamp(stopwatch.Elapsed.TotalMilliseconds / totalMilliseconds, 0d, 1d);
|
||||
var eased = 1d - Math.Pow(1d - progress, 3d);
|
||||
var x = (int)Math.Round(from.X + ((to.X - from.X) * eased));
|
||||
var y = (int)Math.Round(from.Y + ((to.Y - from.Y) * eased));
|
||||
Position = new PixelPoint(x, y);
|
||||
await Task.Delay(16).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Position = to;
|
||||
}
|
||||
|
||||
private readonly record struct WindowAnimationLayout(
|
||||
PixelPoint VisiblePosition,
|
||||
PixelPoint HiddenPosition,
|
||||
Size WindowSize);
|
||||
|
||||
private void OnWindowPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property != WindowStateProperty)
|
||||
@@ -966,10 +1067,17 @@ public partial class MainWindow : Window
|
||||
if (oldState == WindowState.Minimized && newState != WindowState.Minimized)
|
||||
{
|
||||
PrepareEnterAnimation();
|
||||
|
||||
if (newState != WindowState.FullScreen)
|
||||
|
||||
if (ShouldUseFullscreenWindow())
|
||||
{
|
||||
WindowState = WindowState.FullScreen;
|
||||
if (newState != WindowState.FullScreen)
|
||||
{
|
||||
WindowState = WindowState.FullScreen;
|
||||
}
|
||||
}
|
||||
else if (newState == WindowState.Minimized)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
@@ -980,7 +1088,8 @@ public partial class MainWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
if (newState is WindowState.Minimized or WindowState.FullScreen)
|
||||
if (newState == WindowState.Minimized ||
|
||||
(ShouldUseFullscreenWindow() && newState == WindowState.FullScreen))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -999,7 +1108,10 @@ public partial class MainWindow : Window
|
||||
|
||||
if (WindowState is not (WindowState.Minimized or WindowState.FullScreen))
|
||||
{
|
||||
WindowState = WindowState.FullScreen;
|
||||
if (ShouldUseFullscreenWindow())
|
||||
{
|
||||
WindowState = WindowState.FullScreen;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Classes="settings-page-container settings-page-animated">
|
||||
|
||||
<!-- 区域设置分组 -->
|
||||
<controls:IconText Icon="Globe"
|
||||
Text="{Binding BasicHeader}"
|
||||
Margin="0,0,0,4" />
|
||||
@@ -76,7 +75,6 @@
|
||||
|
||||
<Separator Classes="settings-separator" />
|
||||
|
||||
<!-- 运行时设置分组 -->
|
||||
<controls:IconText Icon="DeveloperBoard"
|
||||
Text="{Binding RuntimeHeader}"
|
||||
Margin="0,0,0,4" />
|
||||
@@ -106,8 +104,20 @@
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<ui:SettingsExpander Header="滑入滑出过渡效果"
|
||||
Description="启用后,进入和退出桌面时使用滑入滑出动画(仅 Windows)"
|
||||
<ui:SettingsExpander Header="淡入淡出效果"
|
||||
Description="{Binding FadeTransitionDescription}"
|
||||
IsVisible="{Binding IsSlideTransitionAvailable}">
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<fi:SymbolIconSource Symbol="ArrowUpload" />
|
||||
</ui:SettingsExpander.IconSource>
|
||||
<ui:SettingsExpander.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding EnableFadeTransition}"
|
||||
IsEnabled="{Binding IsFadeTransitionToggleEnabled}" />
|
||||
</ui:SettingsExpander.Footer>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<ui:SettingsExpander Header="启动滑入滑出效果"
|
||||
Description="启用后,启动和恢复时从屏幕右侧边缘滑入或滑出,仅 Windows 可用。"
|
||||
IsVisible="{Binding IsSlideTransitionAvailable}">
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<fi:SymbolIconSource Symbol="ArrowRight" />
|
||||
@@ -118,7 +128,7 @@
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<ui:SettingsExpander Header="桌面主窗口在任务栏显示图标"
|
||||
Description="仅控制桌面主窗口在系统任务栏中的图标显示;不会影响设置窗口,设置窗口打开时始终保留独立任务栏图标">
|
||||
Description="仅控制桌面主窗口在系统任务栏中的图标显示,不影响设置窗口。">
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<fi:SymbolIconSource Symbol="Window" />
|
||||
</ui:SettingsExpander.IconSource>
|
||||
|
||||
Reference in New Issue
Block a user