mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
fix.修智教hub组件
This commit is contained in:
@@ -481,9 +481,9 @@ public partial class App : Application
|
|||||||
RestoreOrCreateMainWindow(showSingleInstanceNotice: true, source: "SingleInstance");
|
RestoreOrCreateMainWindow(showSingleInstanceNotice: true, source: "SingleInstance");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreOrCreateMainWindow(bool showSingleInstanceNotice, string source)
|
private async void RestoreOrCreateMainWindow(bool showSingleInstanceNotice, string source)
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
|
if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
@@ -498,6 +498,13 @@ public partial class App : Application
|
|||||||
if (!mainWindow.IsVisible)
|
if (!mainWindow.IsVisible)
|
||||||
{
|
{
|
||||||
mainWindow.Show();
|
mainWindow.Show();
|
||||||
|
if (mainWindow._isFirstLaunchAfterOpen)
|
||||||
|
{
|
||||||
|
mainWindow._isFirstLaunchAfterOpen = false;
|
||||||
|
mainWindow.ForceDesktopPageToFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
await mainWindow.SlideInAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mainWindow.WindowState == WindowState.Minimized)
|
if (mainWindow.WindowState == WindowState.Minimized)
|
||||||
@@ -879,10 +886,11 @@ public partial class App : Application
|
|||||||
SetDesktopShellState(DesktopShellState.ForegroundDesktop, "MainWindowRestored");
|
SetDesktopShellState(DesktopShellState.ForegroundDesktop, "MainWindowRestored");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HideMainWindowToTray(MainWindow mainWindow, string source)
|
private async void HideMainWindowToTray(MainWindow mainWindow, string source)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
await mainWindow.SlideOutAsync();
|
||||||
mainWindow.ShowInTaskbar = false;
|
mainWindow.ShowInTaskbar = false;
|
||||||
mainWindow.Hide();
|
mainWindow.Hide();
|
||||||
SetDesktopShellState(DesktopShellState.TrayOnly, source);
|
SetDesktopShellState(DesktopShellState.TrayOnly, source);
|
||||||
|
|||||||
147
LanMountainDesktop/Behaviors/WindowSlideAnimationBehavior.cs
Normal file
147
LanMountainDesktop/Behaviors/WindowSlideAnimationBehavior.cs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Animation;
|
||||||
|
using Avalonia.Animation.Easings;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Styling;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using LanMountainDesktop.Theme;
|
||||||
|
|
||||||
|
namespace LanMountainDesktop.Behaviors;
|
||||||
|
|
||||||
|
public static class WindowSlideAnimationBehavior
|
||||||
|
{
|
||||||
|
private static readonly Easing DecelerateEasing = Easing.Parse(FluttermotionToken.StandardBezier);
|
||||||
|
private static readonly Easing AccelerateEasing = new CubicEaseIn();
|
||||||
|
|
||||||
|
public static readonly TimeSpan SlideInDuration = TimeSpan.FromMilliseconds(350);
|
||||||
|
public static readonly TimeSpan SlideOutDuration = TimeSpan.FromMilliseconds(280);
|
||||||
|
|
||||||
|
public static async Task SlideInAsync(Window window, Border desktopHost)
|
||||||
|
{
|
||||||
|
if (window is null || desktopHost is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var screenWidth = Math.Max(1, window.Bounds.Width > 1 ? window.Bounds.Width : PrimaryScreenWidth(window));
|
||||||
|
var transform = EnsureTranslateTransform(desktopHost);
|
||||||
|
|
||||||
|
transform.X = screenWidth;
|
||||||
|
desktopHost.Opacity = 1;
|
||||||
|
window.Show();
|
||||||
|
|
||||||
|
if (screenWidth <= 1)
|
||||||
|
{
|
||||||
|
transform.X = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var animation = new Animation
|
||||||
|
{
|
||||||
|
Duration = SlideInDuration,
|
||||||
|
Easing = DecelerateEasing,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new KeyFrame
|
||||||
|
{
|
||||||
|
Cue = new Cue(0d),
|
||||||
|
Setters = { new Setter(TranslateTransform.XProperty, screenWidth) }
|
||||||
|
},
|
||||||
|
new KeyFrame
|
||||||
|
{
|
||||||
|
Cue = new Cue(1d),
|
||||||
|
Setters = { new Setter(TranslateTransform.XProperty, 0d) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await animation.RunAsync(desktopHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task SlideOutAsync(Window window, Border desktopHost, Action? onCompleted = null)
|
||||||
|
{
|
||||||
|
if (window is null || desktopHost is null)
|
||||||
|
{
|
||||||
|
onCompleted?.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var screenWidth = Math.Max(1, window.Bounds.Width > 1 ? window.Bounds.Width : PrimaryScreenWidth(window));
|
||||||
|
var transform = EnsureTranslateTransform(desktopHost);
|
||||||
|
|
||||||
|
if (screenWidth <= 1)
|
||||||
|
{
|
||||||
|
onCompleted?.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var animation = new Animation
|
||||||
|
{
|
||||||
|
Duration = SlideOutDuration,
|
||||||
|
Easing = AccelerateEasing,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new KeyFrame
|
||||||
|
{
|
||||||
|
Cue = new Cue(0d),
|
||||||
|
Setters = { new Setter(TranslateTransform.XProperty, 0d) }
|
||||||
|
},
|
||||||
|
new KeyFrame
|
||||||
|
{
|
||||||
|
Cue = new Cue(1d),
|
||||||
|
Setters = { new Setter(TranslateTransform.XProperty, screenWidth) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await animation.RunAsync(desktopHost);
|
||||||
|
onCompleted?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ResetSlidePosition(Border desktopHost)
|
||||||
|
{
|
||||||
|
if (desktopHost is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var transform = desktopHost.RenderTransform as TranslateTransform;
|
||||||
|
if (transform is not null)
|
||||||
|
{
|
||||||
|
transform.X = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
desktopHost.Opacity = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TranslateTransform EnsureTranslateTransform(Border desktopHost)
|
||||||
|
{
|
||||||
|
if (desktopHost.RenderTransform is TranslateTransform existingTransform)
|
||||||
|
{
|
||||||
|
return existingTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newTransform = new TranslateTransform();
|
||||||
|
desktopHost.RenderTransform = newTransform;
|
||||||
|
return newTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double PrimaryScreenWidth(Window window)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (window.Screens?.Primary is { } screen)
|
||||||
|
{
|
||||||
|
return screen.WorkingArea.Width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1920;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,10 @@ public partial class ZhiJiaoHubWidget : UserControl,
|
|||||||
private bool _autoRefreshEnabled = true;
|
private bool _autoRefreshEnabled = true;
|
||||||
private int _pendingImageIndex = 0;
|
private int _pendingImageIndex = 0;
|
||||||
|
|
||||||
|
private string _lastLoadedSource = string.Empty;
|
||||||
|
private bool _lastLoadedAutoRefreshEnabled = true;
|
||||||
|
private int _lastLoadedRefreshIntervalMinutes = 30;
|
||||||
|
|
||||||
private IReadOnlyList<ZhiJiaoHubHybridImageItem> _images = [];
|
private IReadOnlyList<ZhiJiaoHubHybridImageItem> _images = [];
|
||||||
private int _currentImageIndex = 0;
|
private int _currentImageIndex = 0;
|
||||||
|
|
||||||
@@ -147,11 +151,39 @@ public partial class ZhiJiaoHubWidget : UserControl,
|
|||||||
_placementId = context.PlacementId ?? string.Empty;
|
_placementId = context.PlacementId ?? string.Empty;
|
||||||
_componentSettingsAccessor = context.ComponentSettingsAccessor;
|
_componentSettingsAccessor = context.ComponentSettingsAccessor;
|
||||||
|
|
||||||
LoadSettings();
|
try
|
||||||
|
|
||||||
if (_isAttached)
|
|
||||||
{
|
{
|
||||||
_ = InitializeAsync();
|
var snapshot = _componentSettingsAccessor?.LoadSnapshot<ComponentSettingsSnapshot>();
|
||||||
|
LoadSettings();
|
||||||
|
|
||||||
|
if (_isAttached)
|
||||||
|
{
|
||||||
|
if (snapshot is not null && NeedsReinitialization(snapshot))
|
||||||
|
{
|
||||||
|
_ = InitializeAsync();
|
||||||
|
}
|
||||||
|
else if (_images.Count > 0)
|
||||||
|
{
|
||||||
|
_pendingImageIndex = snapshot?.ZhiJiaoHubCurrentImageIndex ?? 0;
|
||||||
|
_currentImageIndex = Math.Clamp(_pendingImageIndex, 0, Math.Max(0, _images.Count - 1));
|
||||||
|
_pendingImageIndex = 0;
|
||||||
|
if (TryDisplayCachedImage(_currentImageIndex))
|
||||||
|
{
|
||||||
|
UpdateIndicators();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ = InitializeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (_isAttached)
|
||||||
|
{
|
||||||
|
_ = InitializeAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +195,28 @@ public partial class ZhiJiaoHubWidget : UserControl,
|
|||||||
|
|
||||||
public void RefreshFromSettings()
|
public void RefreshFromSettings()
|
||||||
{
|
{
|
||||||
LoadSettings();
|
try
|
||||||
UpdateTimers();
|
{
|
||||||
if (_isAttached)
|
var snapshot = _componentSettingsAccessor?.LoadSnapshot<ComponentSettingsSnapshot>();
|
||||||
|
if (snapshot is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadSettings();
|
||||||
|
UpdateTimers();
|
||||||
|
|
||||||
|
if (_isAttached && NeedsReinitialization(snapshot))
|
||||||
|
{
|
||||||
|
_ = InitializeAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pendingImageIndex = snapshot.ZhiJiaoHubCurrentImageIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
{
|
{
|
||||||
_ = InitializeAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,6 +241,24 @@ public partial class ZhiJiaoHubWidget : UserControl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool NeedsReinitialization(ComponentSettingsSnapshot snapshot)
|
||||||
|
{
|
||||||
|
var newSource = ZhiJiaoHubSources.Normalize(snapshot.ZhiJiaoHubSource);
|
||||||
|
var newAutoRefreshEnabled = snapshot.ZhiJiaoHubAutoRefreshEnabled;
|
||||||
|
var newRefreshIntervalMinutes = Math.Clamp(snapshot.ZhiJiaoHubAutoRefreshIntervalMinutes, 5, 1440);
|
||||||
|
|
||||||
|
return newSource != _lastLoadedSource ||
|
||||||
|
newAutoRefreshEnabled != _lastLoadedAutoRefreshEnabled ||
|
||||||
|
newRefreshIntervalMinutes != _lastLoadedRefreshIntervalMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLastLoadedSettings(ComponentSettingsSnapshot snapshot)
|
||||||
|
{
|
||||||
|
_lastLoadedSource = ZhiJiaoHubSources.Normalize(snapshot.ZhiJiaoHubSource);
|
||||||
|
_lastLoadedAutoRefreshEnabled = snapshot.ZhiJiaoHubAutoRefreshEnabled;
|
||||||
|
_lastLoadedRefreshIntervalMinutes = Math.Clamp(snapshot.ZhiJiaoHubAutoRefreshIntervalMinutes, 5, 1440);
|
||||||
|
}
|
||||||
|
|
||||||
private void SaveCurrentImageIndex()
|
private void SaveCurrentImageIndex()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -259,6 +326,12 @@ public partial class ZhiJiaoHubWidget : UserControl,
|
|||||||
_currentImageIndex = Math.Clamp(_pendingImageIndex, 0, Math.Max(0, _images.Count - 1));
|
_currentImageIndex = Math.Clamp(_pendingImageIndex, 0, Math.Max(0, _images.Count - 1));
|
||||||
_pendingImageIndex = 0;
|
_pendingImageIndex = 0;
|
||||||
|
|
||||||
|
var snapshot = _componentSettingsAccessor?.LoadSnapshot<ComponentSettingsSnapshot>();
|
||||||
|
if (snapshot is not null)
|
||||||
|
{
|
||||||
|
UpdateLastLoadedSettings(snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
UpdateIndicators();
|
UpdateIndicators();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -375,6 +375,18 @@ public partial class MainWindow
|
|||||||
UpdateDesktopPageAwareComponentContext();
|
UpdateDesktopPageAwareComponentContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ForceDesktopPageToFirst()
|
||||||
|
{
|
||||||
|
if (_currentDesktopSurfaceIndex == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentDesktopSurfaceIndex = 0;
|
||||||
|
ApplyDesktopSurfaceOffset();
|
||||||
|
SchedulePersistSettings(delayMs: 120);
|
||||||
|
}
|
||||||
|
|
||||||
private void SetDesktopPagesHostSnapAnimationEnabled(bool enabled)
|
private void SetDesktopPagesHostSnapAnimationEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
if (_desktopPagesHostTransform is null)
|
if (_desktopPagesHostTransform is null)
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ public partial class MainWindow
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 组件实例范围的设置变更不应触发整个桌面重新加载(比如翻页保存图片索引)
|
||||||
|
if (e.Scope == SettingsScope.ComponentInstance)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (e.Scope == SettingsScope.App && e.ChangedKeys is { Count: > 0 })
|
if (e.Scope == SettingsScope.App && e.ChangedKeys is { Count: > 0 })
|
||||||
{
|
{
|
||||||
var changedKeys = e.ChangedKeys.ToArray();
|
var changedKeys = e.ChangedKeys.ToArray();
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ using Avalonia.Styling;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Avalonia.VisualTree;
|
using Avalonia.VisualTree;
|
||||||
using FluentAvalonia.Styling;
|
using FluentAvalonia.Styling;
|
||||||
|
using LanMountainDesktop.Behaviors;
|
||||||
using LanMountainDesktop.ComponentSystem;
|
using LanMountainDesktop.ComponentSystem;
|
||||||
using LanMountainDesktop.Models;
|
using LanMountainDesktop.Models;
|
||||||
using LanMountainDesktop.PluginSdk;
|
using LanMountainDesktop.PluginSdk;
|
||||||
@@ -108,6 +109,9 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
|
|||||||
private bool _suppressWeatherLocationEvents;
|
private bool _suppressWeatherLocationEvents;
|
||||||
private bool _suppressSettingsPersistence;
|
private bool _suppressSettingsPersistence;
|
||||||
private bool _isComponentLibraryOpen;
|
private bool _isComponentLibraryOpen;
|
||||||
|
private bool _isSlideAnimating;
|
||||||
|
private int _slideAnimationGuard;
|
||||||
|
internal bool _isFirstLaunchAfterOpen = true;
|
||||||
private Border? _selectedDesktopComponentHost;
|
private Border? _selectedDesktopComponentHost;
|
||||||
private bool _reopenSettingsAfterComponentLibraryClose;
|
private bool _reopenSettingsAfterComponentLibraryClose;
|
||||||
private TranslateTransform? _settingsContentPanelTransform;
|
private TranslateTransform? _settingsContentPanelTransform;
|
||||||
@@ -785,9 +789,60 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
|
|||||||
_ = cellSize;
|
_ = cellSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMinimizeClick(object? sender, RoutedEventArgs e)
|
private async void OnMinimizeClick(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
WindowState = WindowState.Minimized;
|
if (_isSlideAnimating)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await SlideOutAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SlideInAsync()
|
||||||
|
{
|
||||||
|
if (_isSlideAnimating || DesktopHost is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var guard = System.Threading.Interlocked.Increment(ref _slideAnimationGuard);
|
||||||
|
_isSlideAnimating = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await WindowSlideAnimationBehavior.SlideInAsync(this, DesktopHost);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isSlideAnimating = false;
|
||||||
|
System.Threading.Interlocked.Decrement(ref _slideAnimationGuard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SlideOutAsync()
|
||||||
|
{
|
||||||
|
if (_isSlideAnimating || DesktopHost is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var guard = System.Threading.Interlocked.Increment(ref _slideAnimationGuard);
|
||||||
|
_isSlideAnimating = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await WindowSlideAnimationBehavior.SlideOutAsync(this, DesktopHost, () =>
|
||||||
|
{
|
||||||
|
WindowState = WindowState.Minimized;
|
||||||
|
WindowSlideAnimationBehavior.ResetSlidePosition(DesktopHost!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isSlideAnimating = false;
|
||||||
|
System.Threading.Interlocked.Decrement(ref _slideAnimationGuard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnWindowPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
private void OnWindowPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
||||||
|
|||||||
Reference in New Issue
Block a user