稳定性提升
This commit is contained in:
lincube
2026-03-03 11:10:57 +08:00
parent 5dc2d680fb
commit 2d09c1aca2
22 changed files with 346 additions and 146 deletions

View File

@@ -92,7 +92,8 @@ public sealed class ComponentRegistry
MinWidthCells: 2,
MinHeightCells: 4,
AllowStatusBarPlacement: false,
AllowDesktopPlacement: true),
AllowDesktopPlacement: true,
ResizeMode: DesktopComponentResizeMode.Free),
new DesktopComponentDefinition(
BuiltInComponentIds.DesktopBlackboardLandscape,
"Blackboard Landscape",
@@ -101,7 +102,8 @@ public sealed class ComponentRegistry
MinWidthCells: 4,
MinHeightCells: 2,
AllowStatusBarPlacement: false,
AllowDesktopPlacement: true),
AllowDesktopPlacement: true,
ResizeMode: DesktopComponentResizeMode.Free),
new DesktopComponentDefinition(
BuiltInComponentIds.Date,
"Calendar",

View File

@@ -8,4 +8,5 @@ public sealed record DesktopComponentDefinition(
int MinWidthCells,
int MinHeightCells,
bool AllowStatusBarPlacement,
bool AllowDesktopPlacement);
bool AllowDesktopPlacement,
DesktopComponentResizeMode ResizeMode = DesktopComponentResizeMode.Proportional);

View File

@@ -0,0 +1,7 @@
namespace LanMontainDesktop.ComponentSystem;
public enum DesktopComponentResizeMode
{
Proportional = 0,
Free = 1
}

View File

@@ -69,7 +69,7 @@ public sealed class TimeZoneService
/// </summary>
public string GetTimeZoneDisplayName(TimeZoneInfo timeZone)
{
var offset = timeZone.BaseUtcOffset;
var offset = timeZone.GetUtcOffset(DateTime.UtcNow);
var sign = offset >= TimeSpan.Zero ? "+" : "-";
var hours = Math.Abs(offset.Hours);
var minutes = Math.Abs(offset.Minutes);

View File

@@ -82,7 +82,7 @@ public sealed class WindowsStartMenuService
nameOverride ?? Path.GetFileName(folderPath),
relativePath);
foreach (var subFolderPath in Directory.EnumerateDirectories(folderPath))
foreach (var subFolderPath in EnumerateDirectoriesSafe(folderPath))
{
var folderName = Path.GetFileName(subFolderPath);
if (folderName.StartsWith(".", StringComparison.Ordinal))
@@ -90,38 +90,76 @@ public sealed class WindowsStartMenuService
continue;
}
folder.Folders.Add(ScanFolder(subFolderPath, rootPath));
try
{
folder.Folders.Add(ScanFolder(subFolderPath, rootPath));
}
catch
{
// Skip unreadable branches but continue scanning siblings.
}
}
foreach (var filePath in Directory.EnumerateFiles(folderPath))
foreach (var filePath in EnumerateFilesSafe(folderPath))
{
var extension = Path.GetExtension(filePath);
if (!SupportedEntryExtensions.Contains(extension))
try
{
continue;
}
var extension = Path.GetExtension(filePath);
if (!SupportedEntryExtensions.Contains(extension))
{
continue;
}
var fileName = Path.GetFileNameWithoutExtension(filePath);
if (string.IsNullOrWhiteSpace(fileName))
{
continue;
}
var fileName = Path.GetFileNameWithoutExtension(filePath);
if (string.IsNullOrWhiteSpace(fileName))
{
continue;
}
var normalizedName = fileName.Replace('_', ' ').Trim();
folder.Apps.Add(new StartMenuAppEntry
var normalizedName = fileName.Replace('_', ' ').Trim();
folder.Apps.Add(new StartMenuAppEntry
{
DisplayName = normalizedName,
FilePath = filePath,
RelativePath = Path.GetRelativePath(rootPath, filePath),
IconPngBytes = OperatingSystem.IsWindows()
? WindowsIconService.TryGetIconPngBytes(filePath)
: null
});
}
catch
{
DisplayName = normalizedName,
FilePath = filePath,
RelativePath = Path.GetRelativePath(rootPath, filePath),
IconPngBytes = OperatingSystem.IsWindows()
? WindowsIconService.TryGetIconPngBytes(filePath)
: null
});
// Skip unreadable or invalid entries and continue.
}
}
return folder;
}
private static IEnumerable<string> EnumerateDirectoriesSafe(string folderPath)
{
try
{
return Directory.EnumerateDirectories(folderPath);
}
catch
{
return Array.Empty<string>();
}
}
private static IEnumerable<string> EnumerateFilesSafe(string folderPath)
{
try
{
return Directory.EnumerateFiles(folderPath);
}
catch
{
return Array.Empty<string>();
}
}
private static void MergeFolder(StartMenuFolderNode target, StartMenuFolderNode source)
{
var appPathSet = new HashSet<string>(

View File

@@ -45,16 +45,23 @@ public partial class AnalogClockWidget : UserControl, IDesktopComponentWidget, I
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
UpdateClock();
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
InitializeDialIfNeeded();

View File

@@ -51,16 +51,23 @@ public partial class ClockWidget : UserControl, IDesktopComponentWidget, ITimeZo
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService != null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
UpdateClock();
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
UpdateClock();

View File

@@ -109,16 +109,23 @@ public partial class DateWidget : UserControl, IDesktopComponentWidget, ITimeZon
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
UpdateDate();
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
UpdateDate();

View File

@@ -10,11 +10,11 @@
<Border Background="{DynamicResource AdaptiveBackgroundBrush}"
Padding="24">
<StackPanel Spacing="16">
<TextBlock Text="日历组件设置"
<TextBlock Text="Date Widget Settings"
FontSize="20"
FontWeight="SemiBold"
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
</StackPanel>
</Border>
</UserControl>
</UserControl>

View File

@@ -37,16 +37,23 @@ public partial class HolidayCalendarWidget : UserControl, IDesktopComponentWidge
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
TriggerContentRefresh();
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
TriggerContentRefresh();

View File

@@ -195,15 +195,22 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
public void SetWeatherInfoService(IWeatherInfoService weatherInfoService)
{
_weatherInfoService = weatherInfoService ?? DefaultWeatherInfoService;

View File

@@ -10,6 +10,7 @@ public interface IDesktopComponentWidget
public interface ITimeZoneAwareComponentWidget
{
void SetTimeZoneService(TimeZoneService timeZoneService);
void ClearTimeZoneService();
}
public interface IWeatherInfoAwareComponentWidget

View File

@@ -99,16 +99,23 @@ public partial class LunarCalendarWidget : UserControl, IDesktopComponentWidget,
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
UpdateContent();
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
UpdateContent();

View File

@@ -40,16 +40,23 @@ public partial class MonthCalendarWidget : UserControl, IDesktopComponentWidget,
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
UpdateCalendar();
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
UpdateCalendar();

View File

@@ -195,15 +195,22 @@ public partial class MultiDayWeatherWidget : UserControl, IDesktopComponentWidge
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
public void SetWeatherInfoService(IWeatherInfoService weatherInfoService)
{
_weatherInfoService = weatherInfoService ?? DefaultWeatherInfoService;

View File

@@ -75,16 +75,23 @@ public partial class WeatherClockWidget : UserControl, IDesktopComponentWidget,
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
UpdateClockVisual();
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
public void SetWeatherInfoService(IWeatherInfoService weatherInfoService)
{
_weatherInfoService = weatherInfoService ?? DefaultWeatherInfoService;

View File

@@ -137,15 +137,22 @@ public partial class WeatherWidget : UserControl, IDesktopComponentWidget, ITime
public void SetTimeZoneService(TimeZoneService timeZoneService)
{
if (_timeZoneService is not null)
{
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
}
ClearTimeZoneService();
_timeZoneService = timeZoneService;
_timeZoneService.TimeZoneChanged += OnTimeZoneChanged;
}
public void ClearTimeZoneService()
{
if (_timeZoneService is null)
{
return;
}
_timeZoneService.TimeZoneChanged -= OnTimeZoneChanged;
_timeZoneService = null;
}
public void SetWeatherInfoService(IWeatherInfoService weatherInfoService)
{
_weatherInfoService = weatherInfoService ?? DefaultWeatherInfoService;

View File

@@ -400,6 +400,7 @@ public partial class MainWindow
}
ComponentLibraryWindow.IsVisible = false;
ClearComponentLibraryPreviewControls();
var shouldReopenSettings = reopenSettings && _reopenSettingsAfterComponentLibraryClose;
_reopenSettingsAfterComponentLibraryClose = false;
@@ -661,7 +662,8 @@ public partial class MainWindow
return;
}
// 娴犲海缍夐弽闂磋厬缁夊娅庣紒鍕
ClearTimeZoneServiceBindings(_selectedDesktopComponentHost);
if (_desktopPageComponentGrids.TryGetValue(placement.PageIndex, out var pageGrid))
{
pageGrid.Children.Remove(_selectedDesktopComponentHost);
@@ -748,7 +750,7 @@ public partial class MainWindow
RebuildDesktopGrid();
PersistSettings();
// 閺囧瓨鏌婇崝銊︹偓浣锋崲閸斺剝鐖弰鍓с仛
// Refresh taskbar actions after page count changes.
ApplyTaskbarActionVisibility(GetCurrentTaskbarContext());
}
@@ -762,6 +764,11 @@ public partial class MainWindow
var placementsToRemove = _desktopComponentPlacements
.Where(p => p.PageIndex == _currentDesktopSurfaceIndex)
.ToList();
if (_desktopPageComponentGrids.TryGetValue(_currentDesktopSurfaceIndex, out var pageGrid))
{
ClearTimeZoneServiceBindings(pageGrid.Children.OfType<Control>().ToList());
}
foreach (var placement in placementsToRemove)
{
@@ -770,7 +777,7 @@ public partial class MainWindow
_desktopPageCount = Math.Clamp(_desktopPageCount - 1, MinDesktopPageCount, MaxDesktopPageCount);
// 鐠嬪啯鏆hぐ鎾冲妞ょ敻娼扮槐銏犵穿
// Clamp current page index to valid range after deletion.
_currentDesktopSurfaceIndex = Math.Clamp(_currentDesktopSurfaceIndex, 0, _desktopPageCount - 1);
// Update remaining page indices after deletion.
@@ -785,7 +792,7 @@ public partial class MainWindow
RebuildDesktopGrid();
PersistSettings();
// 閺囧瓨鏌婇崝銊︹偓浣锋崲閸斺剝鐖弰鍓с仛
// Refresh taskbar actions after page count changes.
ApplyTaskbarActionVisibility(GetCurrentTaskbarContext());
}
@@ -842,6 +849,7 @@ public partial class MainWindow
return;
}
ClearTimeZoneServiceBindings(pageGrid.Children.OfType<Control>().ToList());
pageGrid.Children.Clear();
var maxColumns = pageGrid.ColumnDefinitions.Count;
@@ -1062,6 +1070,11 @@ public partial class MainWindow
runtimeDescriptor.Definition,
span.WidthCells,
span.HeightCells);
if (runtimeDescriptor.Definition.ResizeMode == DesktopComponentResizeMode.Free)
{
return normalized;
}
return NormalizeAspectRatioForComponent(componentId, normalized);
}
@@ -1070,6 +1083,16 @@ public partial class MainWindow
(Math.Max(1, span.WidthCells), Math.Max(1, span.HeightCells)));
}
private DesktopComponentResizeMode GetComponentResizeMode(string componentId)
{
if (_componentRuntimeRegistry.TryGetDescriptor(componentId, out var runtimeDescriptor))
{
return runtimeDescriptor.Definition.ResizeMode;
}
return DesktopComponentResizeMode.Proportional;
}
private static (int WidthCells, int HeightCells) NormalizeAspectRatioForComponent(
string componentId,
(int WidthCells, int HeightCells) span)
@@ -1196,6 +1219,30 @@ public partial class MainWindow
return null;
}
private static void ClearTimeZoneServiceBindings(IEnumerable<Control> roots)
{
foreach (var root in roots)
{
ClearTimeZoneServiceBindings(root);
}
}
private static void ClearTimeZoneServiceBindings(Control root)
{
if (root is ITimeZoneAwareComponentWidget timeZoneAwareRoot)
{
timeZoneAwareRoot.ClearTimeZoneService();
}
foreach (var descendant in root.GetVisualDescendants())
{
if (descendant is ITimeZoneAwareComponentWidget timeZoneAwareChild)
{
timeZoneAwareChild.ClearTimeZoneService();
}
}
}
private static Border? TryGetResizeHandle(Border host)
{
if (host.Child is Grid hostChrome)
@@ -1257,6 +1304,7 @@ public partial class MainWindow
CancelDesktopComponentResize(restoreOriginalSpan: true);
ClearDesktopComponentSelection();
UpdateDesktopComponentHostEditState();
ClearComponentLibraryPreviewControls();
UpdateComponentLibraryLayout(_currentDesktopCellSize);
}
@@ -1615,36 +1663,52 @@ public partial class MainWindow
var deltaX = pointerInViewport.X - _desktopComponentResize.StartPointerInViewport.X;
var deltaY = pointerInViewport.Y - _desktopComponentResize.StartPointerInViewport.Y;
var widthScale = (_desktopComponentResize.StartWidthCells + deltaX / pitch) / _desktopComponentResize.StartWidthCells;
var heightScale = (_desktopComponentResize.StartHeightCells + deltaY / pitch) / _desktopComponentResize.StartHeightCells;
var proposedScale = Math.Max(widthScale, heightScale);
var minScale = Math.Max(
(double)_desktopComponentResize.MinWidthCells / _desktopComponentResize.StartWidthCells,
(double)_desktopComponentResize.MinHeightCells / _desktopComponentResize.StartHeightCells);
var maxScale = Math.Min(
(double)_desktopComponentResize.MaxWidthCells / _desktopComponentResize.StartWidthCells,
(double)_desktopComponentResize.MaxHeightCells / _desktopComponentResize.StartHeightCells);
if (double.IsNaN(proposedScale) || double.IsInfinity(proposedScale))
int widthCells;
int heightCells;
if (GetComponentResizeMode(_desktopComponentResize.ComponentId) == DesktopComponentResizeMode.Free)
{
proposedScale = minScale;
widthCells = Math.Clamp(
(int)Math.Round(_desktopComponentResize.StartWidthCells + deltaX / pitch),
_desktopComponentResize.MinWidthCells,
_desktopComponentResize.MaxWidthCells);
heightCells = Math.Clamp(
(int)Math.Round(_desktopComponentResize.StartHeightCells + deltaY / pitch),
_desktopComponentResize.MinHeightCells,
_desktopComponentResize.MaxHeightCells);
}
if (maxScale < minScale)
else
{
maxScale = minScale;
}
var widthScale = (_desktopComponentResize.StartWidthCells + deltaX / pitch) / _desktopComponentResize.StartWidthCells;
var heightScale = (_desktopComponentResize.StartHeightCells + deltaY / pitch) / _desktopComponentResize.StartHeightCells;
var scale = Math.Clamp(proposedScale, minScale, maxScale);
var widthCells = Math.Clamp(
(int)Math.Round(_desktopComponentResize.StartWidthCells * scale),
_desktopComponentResize.MinWidthCells,
_desktopComponentResize.MaxWidthCells);
var heightCells = Math.Clamp(
(int)Math.Round(_desktopComponentResize.StartHeightCells * scale),
_desktopComponentResize.MinHeightCells,
_desktopComponentResize.MaxHeightCells);
var proposedScale = Math.Max(widthScale, heightScale);
var minScale = Math.Max(
(double)_desktopComponentResize.MinWidthCells / _desktopComponentResize.StartWidthCells,
(double)_desktopComponentResize.MinHeightCells / _desktopComponentResize.StartHeightCells);
var maxScale = Math.Min(
(double)_desktopComponentResize.MaxWidthCells / _desktopComponentResize.StartWidthCells,
(double)_desktopComponentResize.MaxHeightCells / _desktopComponentResize.StartHeightCells);
if (double.IsNaN(proposedScale) || double.IsInfinity(proposedScale))
{
proposedScale = minScale;
}
if (maxScale < minScale)
{
maxScale = minScale;
}
var scale = Math.Clamp(proposedScale, minScale, maxScale);
widthCells = Math.Clamp(
(int)Math.Round(_desktopComponentResize.StartWidthCells * scale),
_desktopComponentResize.MinWidthCells,
_desktopComponentResize.MaxWidthCells);
heightCells = Math.Clamp(
(int)Math.Round(_desktopComponentResize.StartHeightCells * scale),
_desktopComponentResize.MinHeightCells,
_desktopComponentResize.MaxHeightCells);
}
var normalized = NormalizeComponentCellSpan(_desktopComponentResize.ComponentId, (widthCells, heightCells));
widthCells = Math.Clamp(normalized.WidthCells, _desktopComponentResize.MinWidthCells, _desktopComponentResize.MaxWidthCells);
@@ -2213,6 +2277,7 @@ public partial class MainWindow
_componentLibraryActiveComponents = category.Components;
var componentCount = _componentLibraryActiveComponents.Count;
ClearTimeZoneServiceBindings(ComponentLibraryComponentPagesContainer.Children.OfType<Control>().ToList());
ComponentLibraryComponentPagesContainer.Children.Clear();
ComponentLibraryComponentPagesContainer.RowDefinitions.Clear();
ComponentLibraryComponentPagesContainer.ColumnDefinitions.Clear();
@@ -2374,6 +2439,19 @@ public partial class MainWindow
UpdateComponentLibraryComponentNavigationButtons();
}
private void ClearComponentLibraryPreviewControls()
{
if (ComponentLibraryComponentPagesContainer is null)
{
return;
}
ClearTimeZoneServiceBindings(ComponentLibraryComponentPagesContainer.Children.OfType<Control>().ToList());
ComponentLibraryComponentPagesContainer.Children.Clear();
ComponentLibraryComponentPagesContainer.RowDefinitions.Clear();
ComponentLibraryComponentPagesContainer.ColumnDefinitions.Clear();
}
private string GetLocalizedComponentDisplayName(DesktopComponentRuntimeDescriptor descriptor)
{
return L(descriptor.DisplayNameLocalizationKey, descriptor.Definition.DisplayName);

View File

@@ -127,6 +127,7 @@ public partial class MainWindow
DesktopPagesContainer.RowDefinitions.Clear();
DesktopPagesContainer.RowDefinitions.Add(new RowDefinition(new GridLength(pageHeight, GridUnitType.Pixel)));
DesktopPagesContainer.ColumnDefinitions.Clear();
ClearTimeZoneServiceBindings(DesktopPagesContainer.Children.OfType<Control>().ToList());
DesktopPagesContainer.Children.Clear();
DesktopPagesContainer.Width = pageWidth * _desktopPageCount;
DesktopPagesContainer.Height = pageHeight;

View File

@@ -86,20 +86,22 @@ public partial class MainWindow
WallpaperPreviewBackButtonTextBlock.Text = L("button.back_to_windows", "Back to Windows");
ToolTip.SetTip(BackToWindowsButton, L("tooltip.back_to_windows", "Back to Windows"));
OpenComponentLibraryTextBlock.Text = L("button.component_library", "编辑桌面");
WallpaperPreviewComponentLibraryTextBlock.Text = L("button.component_library", "编辑桌面");
GridPreviewComponentLibraryTextBlock.Text = L("button.component_library", "编辑桌面");
ToolTip.SetTip(OpenComponentLibraryButton, L("tooltip.component_library", "编辑桌面"));
ComponentLibraryTitleTextBlock.Text = L("component_library.title", "小组件");
OpenComponentLibraryTextBlock.Text = L("button.component_library", "Edit Desktop");
WallpaperPreviewComponentLibraryTextBlock.Text = L("button.component_library", "Edit Desktop");
GridPreviewComponentLibraryTextBlock.Text = L("button.component_library", "Edit Desktop");
ToolTip.SetTip(OpenComponentLibraryButton, L("tooltip.component_library", "Edit Desktop"));
ComponentLibraryTitleTextBlock.Text = L("component_library.title", "Widgets");
ToolTip.SetTip(CloseComponentLibraryButton, L("common.close", "Close"));
ComponentLibraryEmptyTextBlock.Text = L(
"component_library.empty",
"Swipe to pick a category, tap to open, then drag a widget onto the desktop.");
LauncherTitleTextBlock.Text = L("launcher.title", "应用启动台");
LauncherSubtitleTextBlock.Text = L("launcher.subtitle", "按 Windows 开始菜单结构显示所有应用与文件夹");
ToolTip.SetTip(LauncherFolderBackButton, L("common.back", "返回"));
ToolTip.SetTip(LauncherFolderCloseButton, L("common.close", "关闭"));
LauncherTitleTextBlock.Text = L("launcher.title", "App Launcher");
LauncherSubtitleTextBlock.Text = L(
"launcher.subtitle",
"Displays all apps and folders based on the Windows Start menu structure.");
ToolTip.SetTip(LauncherFolderBackButton, L("common.back", "Back"));
ToolTip.SetTip(LauncherFolderCloseButton, L("common.close", "Close"));
SettingsNavHeaderTextBlock.Text = L("settings.nav_header", "Settings");
SettingsNavWallpaperTextBlock.Text = L("settings.nav.wallpaper", "Wallpaper");
@@ -109,11 +111,13 @@ public partial class MainWindow
SettingsNavWeatherTextBlock.Text = L("settings.nav.weather", "Weather");
SettingsNavRegionTextBlock.Text = L("settings.nav.region", "Region");
WallpaperPanelTitleTextBlock.Text = L("settings.wallpaper.title", "个性化我们的背景");
WallpaperPlacementSettingsExpander.Header = L("settings.wallpaper.placement_label", "选择契合度");
WallpaperPlacementSettingsExpander.Description = L("settings.wallpaper.placement_desc", "调整图像在桌面上的填充方式。");
PickWallpaperButton.Content = L("settings.wallpaper.pick_button", "浏览照片");
ClearWallpaperButton.Content = L("settings.wallpaper.clear_button", "重置");
WallpaperPanelTitleTextBlock.Text = L("settings.wallpaper.title", "Personalize your wallpaper");
WallpaperPlacementSettingsExpander.Header = L("settings.wallpaper.placement_label", "Placement");
WallpaperPlacementSettingsExpander.Description = L(
"settings.wallpaper.placement_desc",
"Adjust how the image fits on the desktop.");
PickWallpaperButton.Content = L("settings.wallpaper.pick_button", "Browse");
ClearWallpaperButton.Content = L("settings.wallpaper.clear_button", "Reset");
GridPanelTitleTextBlock.Text = L("settings.grid.title", "Grid Layout");
GridSpacingPresetLabelTextBlock.Text = L("settings.grid.spacing_label", "Grid Spacing");
@@ -265,7 +269,7 @@ public partial class MainWindow
private string GetLocalizedTimeZoneDisplayName(TimeZoneInfo timeZone)
{
var offset = timeZone.BaseUtcOffset;
var offset = timeZone.GetUtcOffset(DateTime.UtcNow);
var sign = offset >= TimeSpan.Zero ? "+" : "-";
var hours = Math.Abs(offset.Hours);
var minutes = Math.Abs(offset.Minutes);

View File

@@ -476,7 +476,7 @@
FontWeight="SemiBold"
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"
Margin="0,0,0,24"
Text="涓€у寲鎮ㄧ殑鑳屾櫙" />
Text="Personalize Wallpaper" />
<!-- Left Column: Monitor Preview -->
<Border x:Name="WallpaperPreviewHost"
@@ -563,11 +563,11 @@
FontWeight="Medium"
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}"
TextTrimming="CharacterEllipsis"
Text="鏈€夋嫨鏂囦欢" />
Text="No file selected" />
<TextBlock x:Name="WallpaperStatusTextBlock"
FontSize="12"
Foreground="{DynamicResource AdaptiveTextMutedBrush}"
Text="灏辩华" />
Text="Ready" />
</StackPanel>
<Separator Background="{DynamicResource SurfaceStrokeColorDefaultBrush}" Height="1" Margin="0,8" />
@@ -581,13 +581,13 @@
HorizontalAlignment="Stretch"
Padding="0,10"
Click="OnPickWallpaperClick"
Content="娴忚鐓х墖" />
Content="Browse" />
<Button x:Name="ClearWallpaperButton"
Grid.Column="1"
HorizontalAlignment="Stretch"
Padding="0,10"
Click="OnClearWallpaperClick"
Content="閲嶇疆" />
Content="Reset" />
</Grid>
<Border Classes="settings-expander-shell">
@@ -695,7 +695,7 @@
<StackPanel Grid.Row="1" Grid.Column="1"
Margin="16,0,0,0"
Spacing="16">
<TextBlock Text="绔栨帓鏍兼暟" FontSize="16" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
<TextBlock Text="Rows" FontSize="16" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="12">
<Slider x:Name="GridSizeSlider"
@@ -754,7 +754,7 @@
<TextBlock x:Name="GridEdgeInsetComputedPxTextBlock"
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"
Text="鈮?0 px" />
Text=">= 0 px" />
<Button x:Name="ApplyGridButton"
HorizontalAlignment="Stretch"
@@ -1005,15 +1005,15 @@
Unchecked="OnStatusBarClockUnchecked" />
</ui:SettingsExpander.Footer>
<StackPanel Margin="0,8,0,0" Spacing="12">
<TextBlock Text="鏄剧ず鏍煎紡" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
<TextBlock Text="Display Format" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
<StackPanel Orientation="Horizontal" Spacing="8">
<RadioButton x:Name="ClockFormatHMSSRadio"
Content="鏃跺垎绉?(HH:mm:ss)"
Content="Time with seconds (HH:mm:ss)"
GroupName="ClockFormat"
Checked="OnClockFormatChanged"
Tag="Hms" />
<RadioButton x:Name="ClockFormatHMRadio"
Content="鏃跺垎 (HH:mm)"
Content="Time (HH:mm)"
GroupName="ClockFormat"
Checked="OnClockFormatChanged"
Tag="Hm" />
@@ -1070,7 +1070,7 @@
<TextBlock x:Name="StatusBarSpacingComputedPxTextBlock"
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}"
Text="鈮?0 px" />
Text=">= 0 px" />
</StackPanel>
</ui:SettingsExpander>
</Border>
@@ -1274,19 +1274,19 @@
</Border>
</StackPanel>
<StackPanel x:Name="AboutSettingsPanel" IsVisible="False" Spacing="20">
<TextBlock x:Name="AboutPanelTitleTextBlock" FontSize="24" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" Text="鍏充簬" />
<StackPanel x:Name="AboutSettingsPanel" IsVisible="False" Spacing="20">
<TextBlock x:Name="AboutPanelTitleTextBlock" FontSize="24" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" Text="About" />
<Border Background="{DynamicResource AdaptiveSurfaceRaisedBrush}" CornerRadius="{DynamicResource DesignCornerRadiusMd}" Padding="20">
<StackPanel Spacing="12">
<TextBlock Text="LanMontainDesktop" FontSize="20" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
<TextBlock Text="Modern desktop shell experience." FontSize="13" Foreground="{DynamicResource AdaptiveTextSecondaryBrush}" />
<Separator Background="{DynamicResource AdaptiveButtonBorderBrush}" Margin="0,8" />
<TextBlock x:Name="VersionTextBlock" Text="鐗堟湰鍙? 1.0.0" FontSize="13" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
<TextBlock x:Name="CodeNameTextBlock" Text="鐗堟湰浠e彿: Administrate" FontSize="13" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveAccentBrush}" />
<TextBlock x:Name="FontInfoTextBlock" Text="字体: MiSans" FontSize="12" Foreground="{DynamicResource AdaptiveTextSecondaryBrush}" />
<TextBlock x:Name="VersionTextBlock" Text="Version: 1.0.0" FontSize="13" Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
<TextBlock x:Name="CodeNameTextBlock" Text="Code Name: Administrate" FontSize="13" FontWeight="SemiBold" Foreground="{DynamicResource AdaptiveAccentBrush}" />
<TextBlock x:Name="FontInfoTextBlock" Text="Font: MiSans" FontSize="12" Foreground="{DynamicResource AdaptiveTextSecondaryBrush}" />
</StackPanel>
</Border>
</StackPanel>
</StackPanel>
</Grid>
</Border>
</Grid>
@@ -1314,7 +1314,7 @@
CornerRadius="36,36,0,0"
Padding="16,12">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Text="缁勪欢璁剧疆"
<TextBlock Text="Component Settings"
FontSize="16"
FontWeight="SemiBold"
Foreground="White"

View File

@@ -795,7 +795,7 @@ public partial class MainWindow : Window
var spacingPx = Math.Max(0, cellSize) * (percent / 100d);
StatusBarSpacingComputedPxTextBlock.Text = Lf(
"settings.status_bar.spacing_custom_px_format",
"鈮?{0:F1}px",
">= {0:F1}px",
spacingPx);
}
@@ -863,13 +863,11 @@ public partial class MainWindow : Window
var shortSidePx = Math.Max(1, Math.Min(hostWidth, hostHeight));
var baseCell = shortSidePx / cells;
// --- 姣斾緥鍖栫暀鐧?(Proportional Inset) ---
// 鍏佽鐢ㄦ埛鐧惧垎姣旇皟鑺傦紝浣嗚瀹氭洿鍚堢悊鐨勫熀鍑嗗拰闄愬埗
// Proportional inset based on user percentage selection.
var clampedPercent = Math.Clamp(insetPercent, MinEdgeInsetPercent, MaxEdgeInsetPercent);
var insetRatio = clampedPercent / 100d;
// 纭繚鏈€灏忕暀鐧借兘瀹圭撼涓€瀹氱殑闃村奖鎵╁睍
// 鍏佽 0 杈硅窛锛屾渶澶т笂闄愮淮鎸?80px
// Keep inset within a practical visual range.
return Math.Clamp(baseCell * insetRatio, 0, 80);
}
@@ -1282,7 +1280,7 @@ public partial class MainWindow : Window
};
TimeZoneComboBox.Items.Add(item);
// 閫変腑褰撳墠鏃跺尯
// Select current time zone.
if (tz.Id == _timeZoneService.CurrentTimeZone.Id)
{
TimeZoneComboBox.SelectedItem = item;