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");
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -498,6 +498,13 @@ public partial class App : Application
|
||||
if (!mainWindow.IsVisible)
|
||||
{
|
||||
mainWindow.Show();
|
||||
if (mainWindow._isFirstLaunchAfterOpen)
|
||||
{
|
||||
mainWindow._isFirstLaunchAfterOpen = false;
|
||||
mainWindow.ForceDesktopPageToFirst();
|
||||
}
|
||||
|
||||
await mainWindow.SlideInAsync();
|
||||
}
|
||||
|
||||
if (mainWindow.WindowState == WindowState.Minimized)
|
||||
@@ -879,10 +886,11 @@ public partial class App : Application
|
||||
SetDesktopShellState(DesktopShellState.ForegroundDesktop, "MainWindowRestored");
|
||||
}
|
||||
|
||||
private void HideMainWindowToTray(MainWindow mainWindow, string source)
|
||||
private async void HideMainWindowToTray(MainWindow mainWindow, string source)
|
||||
{
|
||||
try
|
||||
{
|
||||
await mainWindow.SlideOutAsync();
|
||||
mainWindow.ShowInTaskbar = false;
|
||||
mainWindow.Hide();
|
||||
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 int _pendingImageIndex = 0;
|
||||
|
||||
private string _lastLoadedSource = string.Empty;
|
||||
private bool _lastLoadedAutoRefreshEnabled = true;
|
||||
private int _lastLoadedRefreshIntervalMinutes = 30;
|
||||
|
||||
private IReadOnlyList<ZhiJiaoHubHybridImageItem> _images = [];
|
||||
private int _currentImageIndex = 0;
|
||||
|
||||
@@ -147,11 +151,39 @@ public partial class ZhiJiaoHubWidget : UserControl,
|
||||
_placementId = context.PlacementId ?? string.Empty;
|
||||
_componentSettingsAccessor = context.ComponentSettingsAccessor;
|
||||
|
||||
LoadSettings();
|
||||
|
||||
if (_isAttached)
|
||||
try
|
||||
{
|
||||
_ = 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()
|
||||
{
|
||||
LoadSettings();
|
||||
UpdateTimers();
|
||||
if (_isAttached)
|
||||
try
|
||||
{
|
||||
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()
|
||||
{
|
||||
try
|
||||
@@ -259,6 +326,12 @@ public partial class ZhiJiaoHubWidget : UserControl,
|
||||
_currentImageIndex = Math.Clamp(_pendingImageIndex, 0, Math.Max(0, _images.Count - 1));
|
||||
_pendingImageIndex = 0;
|
||||
|
||||
var snapshot = _componentSettingsAccessor?.LoadSnapshot<ComponentSettingsSnapshot>();
|
||||
if (snapshot is not null)
|
||||
{
|
||||
UpdateLastLoadedSettings(snapshot);
|
||||
}
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
UpdateIndicators();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@@ -375,6 +375,18 @@ public partial class MainWindow
|
||||
UpdateDesktopPageAwareComponentContext();
|
||||
}
|
||||
|
||||
public void ForceDesktopPageToFirst()
|
||||
{
|
||||
if (_currentDesktopSurfaceIndex == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentDesktopSurfaceIndex = 0;
|
||||
ApplyDesktopSurfaceOffset();
|
||||
SchedulePersistSettings(delayMs: 120);
|
||||
}
|
||||
|
||||
private void SetDesktopPagesHostSnapAnimationEnabled(bool enabled)
|
||||
{
|
||||
if (_desktopPagesHostTransform is null)
|
||||
|
||||
@@ -38,6 +38,12 @@ public partial class MainWindow
|
||||
return;
|
||||
}
|
||||
|
||||
// 组件实例范围的设置变更不应触发整个桌面重新加载(比如翻页保存图片索引)
|
||||
if (e.Scope == SettingsScope.ComponentInstance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Scope == SettingsScope.App && e.ChangedKeys is { Count: > 0 })
|
||||
{
|
||||
var changedKeys = e.ChangedKeys.ToArray();
|
||||
|
||||
@@ -18,6 +18,7 @@ using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
using Avalonia.VisualTree;
|
||||
using FluentAvalonia.Styling;
|
||||
using LanMountainDesktop.Behaviors;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
@@ -108,6 +109,9 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
|
||||
private bool _suppressWeatherLocationEvents;
|
||||
private bool _suppressSettingsPersistence;
|
||||
private bool _isComponentLibraryOpen;
|
||||
private bool _isSlideAnimating;
|
||||
private int _slideAnimationGuard;
|
||||
internal bool _isFirstLaunchAfterOpen = true;
|
||||
private Border? _selectedDesktopComponentHost;
|
||||
private bool _reopenSettingsAfterComponentLibraryClose;
|
||||
private TranslateTransform? _settingsContentPanelTransform;
|
||||
@@ -785,9 +789,60 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
|
||||
_ = 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)
|
||||
|
||||
Reference in New Issue
Block a user