Compare commits

..

4 Commits

Author SHA1 Message Date
Shawn Yuan
4e0ebfd6db Update src/settings-ui/QuickAccess.UI/QuickAccessXAML/MainWindow.xaml.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-13 14:38:10 +08:00
Shawn Yuan (from Dev Box)
3d510dc382 update 2026-01-13 14:14:24 +08:00
Shawn Yuan (from Dev Box)
8ffd88fdf3 memory optimization 2026-01-13 13:58:23 +08:00
Shawn Yuan (from Dev Box)
097cf7414b init 2026-01-13 12:27:21 +08:00
9 changed files with 79 additions and 32 deletions

View File

@@ -2,7 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.CommandPalette.Extensions;
@@ -42,19 +41,15 @@ internal sealed partial class FancyZonesMonitorListItem : ListItem
public static Details BuildMonitorDetails(FancyZonesMonitorDescriptor monitor)
{
var currentVirtualDesktop = FancyZonesVirtualDesktop.GetCurrentVirtualDesktopIdString();
// Calculate physical resolution from logical pixels and DPI
var scaleFactor = monitor.Data.Dpi > 0 ? monitor.Data.Dpi / 96.0 : 1.0;
var physicalWidth = (int)Math.Round(monitor.Data.MonitorWidth * scaleFactor);
var physicalHeight = (int)Math.Round(monitor.Data.MonitorHeight * scaleFactor);
var resolution = $"{physicalWidth}\u00D7{physicalHeight}";
var tags = new List<IDetailsElement>
{
DetailTag(Resources.FancyZones_Monitor, monitor.Data.Monitor),
DetailTag(Resources.FancyZones_Instance, monitor.Data.MonitorInstanceId),
DetailTag(Resources.FancyZones_Serial, monitor.Data.MonitorSerialNumber),
DetailTag(Resources.FancyZones_Number, monitor.Data.MonitorNumber.ToString(CultureInfo.InvariantCulture)),
DetailTag(Resources.FancyZones_VirtualDesktop, currentVirtualDesktop),
DetailTag(Resources.FancyZones_Resolution, resolution),
DetailTag(Resources.FancyZones_WorkArea, $"{monitor.Data.LeftCoordinate},{monitor.Data.TopCoordinate} {monitor.Data.WorkAreaWidth}\u00D7{monitor.Data.WorkAreaHeight}"),
DetailTag(Resources.FancyZones_Resolution, $"{monitor.Data.MonitorWidth}\u00D7{monitor.Data.MonitorHeight}"),
DetailTag(Resources.FancyZones_DPI, monitor.Data.Dpi.ToString(CultureInfo.InvariantCulture)),
};

View File

@@ -19,12 +19,8 @@ internal readonly record struct FancyZonesMonitorDescriptor(
{
get
{
// MonitorWidth/Height are logical (DPI-scaled) pixels, calculate physical resolution
var scaleFactor = Data.Dpi > 0 ? Data.Dpi / 96.0 : 1.0;
var physicalWidth = (int)Math.Round(Data.MonitorWidth * scaleFactor);
var physicalHeight = (int)Math.Round(Data.MonitorHeight * scaleFactor);
var size = $"{physicalWidth}×{physicalHeight}";
var scaling = Data.Dpi > 0 ? string.Format(CultureInfo.InvariantCulture, "{0}%", (int)Math.Round(scaleFactor * 100)) : "n/a";
var size = $"{Data.MonitorWidth}×{Data.MonitorHeight}";
var scaling = Data.Dpi > 0 ? string.Format(CultureInfo.InvariantCulture, "{0}%", (int)Math.Round(Data.Dpi * 100 / 96.0)) : "n/a";
return $"{size} \u2022 {scaling}";
}
}

View File

@@ -485,21 +485,12 @@ internal static class FancyZonesThumbnailRenderer
private static List<NormalizedRect> GetFocusRects(int zoneCount)
{
// Focus layout parameters from FancyZonesEditor CanvasLayoutModel:
// - DefaultOffset = 100px from top-left (normalized: ~0.05 for typical screen)
// - OffsetShift = 50px per zone (normalized: ~0.025)
// - ZoneSizeMultiplier = 0.4 (zones are 40% of screen)
zoneCount = Math.Clamp(zoneCount, 1, 8);
var rects = new List<NormalizedRect>(zoneCount);
const float defaultOffset = 0.05f; // ~100px on 1920px screen
const float offsetShift = 0.025f; // ~50px on 1920px screen
const float zoneSize = 0.4f; // 40% of screen
for (var i = 0; i < zoneCount; i++)
{
var offset = i * offsetShift;
rects.Add(new NormalizedRect(defaultOffset + offset, defaultOffset + offset, zoneSize, zoneSize));
var offset = i * 0.06f;
rects.Add(new NormalizedRect(0.1f + offset, 0.1f + offset, 0.8f, 0.8f));
}
return rects;

View File

@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using static FancyZonesEditorCommon.Data.CustomLayouts;
@@ -24,10 +23,8 @@ namespace FancyZonesEditorCommon.Data
{
public struct CanvasZoneWrapper
{
[JsonPropertyName("X")]
public int X { get; set; }
[JsonPropertyName("Y")]
public int Y { get; set; }
public int Width { get; set; }

View File

@@ -19,6 +19,8 @@ public sealed partial class AppsListPage : Page
public AppsListPage()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Disabled;
Unloaded += OnUnloaded;
}
public AllAppsViewModel ViewModel { get; private set; } = default!;
@@ -36,6 +38,30 @@ public sealed partial class AppsListPage : Page
}
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
CleanupPage();
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
CleanupPage();
}
private void CleanupPage()
{
// Clear the collection before cleaning up to release all item references
if (ViewModel != null)
{
ViewModel.FlyoutMenuItems.Clear();
}
DataContext = null;
ViewModel = null!;
_context = null;
}
private void BackButton_Click(object sender, RoutedEventArgs e)
{
if (_context == null || Frame == null)

View File

@@ -27,6 +27,7 @@ public sealed partial class LaunchPage : Page
public LaunchPage()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Disabled;
}
public LauncherViewModel ViewModel { get; private set; } = default!;
@@ -44,6 +45,12 @@ public sealed partial class LaunchPage : Page
}
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
DataContext = null;
}
private void SettingsBtn_Click(object sender, RoutedEventArgs e)
{
_coordinator?.OpenSettings();

View File

@@ -65,4 +65,16 @@ public sealed partial class ShellPage : Page
appsListPage.ViewModel?.RefreshSettings();
}
}
internal void NavigateToLaunchIfNeeded()
{
// Always clear FlyoutMenuItems to release memory
_allAppsViewModel?.FlyoutMenuItems.Clear();
// Navigate back to LaunchPage if on AppsListPage
if (ContentFrame.Content is AppsListPage)
{
NavigateToLaunch();
}
}
}

View File

@@ -143,8 +143,11 @@ public sealed partial class MainWindow : WindowEx, IDisposable
_trimCts = new CancellationTokenSource();
var token = _trimCts.Token;
// Delay the trim to avoid aggressive GC during quick toggles
Task.Delay(2000, token).ContinueWith(
// Delay memory trim for 5 seconds to avoid aggressive GC during quick toggles.
// A shorter delay (previously 2 seconds) caused heavy UI (e.g. AppsListPage) to be
// torn down and rebuilt when users quickly reopened the window, which hurt perceived
// responsiveness more than the extra few seconds of retained memory.
Task.Delay(5000, token).ContinueWith(
_ =>
{
if (token.IsCancellationRequested)
@@ -152,7 +155,24 @@ public sealed partial class MainWindow : WindowEx, IDisposable
return;
}
TrimMemory();
_dispatcherQueue.TryEnqueue(() =>
{
// Navigate back to LaunchPage before memory trim to release AppsListPage resources
ShellHost.NavigateToLaunchIfNeeded();
// Give UI time to complete cleanup before forcing GC
Task.Delay(500, token).ContinueWith(
__ =>
{
if (!token.IsCancellationRequested)
{
_dispatcherQueue.TryEnqueue(TrimMemory);
}
},
token,
TaskContinuationOptions.None,
TaskScheduler.Default);
});
},
token,
TaskContinuationOptions.None,

View File

@@ -154,6 +154,9 @@ public sealed class AllAppsViewModel : Observable
if (_coordinator.UpdateModuleEnabled(flyoutItem.Tag, flyoutItem.IsEnabled))
{
_coordinator.NotifyUserSettingsInteraction();
// Trigger re-sort immediately when status changes on UI
RefreshFlyoutMenuItems();
}
}