mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-23 01:44:26 +08:00
0.6.7.2
文档组件优化
This commit is contained in:
@@ -64,6 +64,7 @@ public sealed class ComponentSettingsSnapshot
|
|||||||
|
|
||||||
public string Stcn24ForumSourceType { get; set; } = Stcn24ForumSourceTypes.LatestCreated;
|
public string Stcn24ForumSourceType { get; set; } = Stcn24ForumSourceTypes.LatestCreated;
|
||||||
|
|
||||||
|
|
||||||
public ComponentSettingsSnapshot Clone()
|
public ComponentSettingsSnapshot Clone()
|
||||||
{
|
{
|
||||||
var clone = (ComponentSettingsSnapshot)MemberwiseClone();
|
var clone = (ComponentSettingsSnapshot)MemberwiseClone();
|
||||||
@@ -91,6 +92,9 @@ public sealed class ComponentSettingsSnapshot
|
|||||||
clone.WorldClockTimeZoneIds = WorldClockTimeZoneIds is { Count: > 0 }
|
clone.WorldClockTimeZoneIds = WorldClockTimeZoneIds is { Count: > 0 }
|
||||||
? new List<string>(WorldClockTimeZoneIds)
|
? new List<string>(WorldClockTimeZoneIds)
|
||||||
: [];
|
: [];
|
||||||
|
clone.OfficeRecentDocumentsEnabledSources = OfficeRecentDocumentsEnabledSources is not null
|
||||||
|
? new List<string>(OfficeRecentDocumentsEnabledSources)
|
||||||
|
: null;
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|||||||
53
LanMountainDesktop/Models/OfficeRecentDocumentSourceTypes.cs
Normal file
53
LanMountainDesktop/Models/OfficeRecentDocumentSourceTypes.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace LanMountainDesktop.Models;
|
||||||
|
|
||||||
|
public static class OfficeRecentDocumentSourceTypes
|
||||||
|
{
|
||||||
|
public const string Registry = "registry";
|
||||||
|
public const string RecentFolders = "recent_folders";
|
||||||
|
public const string JumpLists = "jump_lists";
|
||||||
|
|
||||||
|
public static IReadOnlyList<string> SupportedValues { get; } =
|
||||||
|
[
|
||||||
|
Registry,
|
||||||
|
RecentFolders,
|
||||||
|
JumpLists
|
||||||
|
];
|
||||||
|
|
||||||
|
public static IReadOnlyList<string> DefaultValues => SupportedValues;
|
||||||
|
|
||||||
|
public static IReadOnlyList<string> NormalizeValues(IEnumerable<string>? values, bool useDefaultWhenEmpty)
|
||||||
|
{
|
||||||
|
if (values is null)
|
||||||
|
{
|
||||||
|
return useDefaultWhenEmpty ? DefaultValues : Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var normalized = values
|
||||||
|
.Select(NormalizeValue)
|
||||||
|
.OfType<string>()
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (normalized.Length == 0 && useDefaultWhenEmpty)
|
||||||
|
{
|
||||||
|
return DefaultValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? NormalizeValue(string? value)
|
||||||
|
{
|
||||||
|
return value?.Trim().ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
Registry => Registry,
|
||||||
|
RecentFolders => RecentFolders,
|
||||||
|
JumpLists => JumpLists,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,6 +75,9 @@ public static class DesktopComponentEditorRegistryFactory
|
|||||||
[BuiltInComponentIds.DesktopRemovableStorage] = new(
|
[BuiltInComponentIds.DesktopRemovableStorage] = new(
|
||||||
BuiltInComponentIds.DesktopRemovableStorage,
|
BuiltInComponentIds.DesktopRemovableStorage,
|
||||||
context => new RemovableStorageComponentEditor(context)),
|
context => new RemovableStorageComponentEditor(context)),
|
||||||
|
[BuiltInComponentIds.DesktopOfficeRecentDocuments] = new(
|
||||||
|
BuiltInComponentIds.DesktopOfficeRecentDocuments,
|
||||||
|
context => new OfficeRecentDocumentsComponentEditor(context)),
|
||||||
[BuiltInComponentIds.DesktopWeather] = CreateWeatherRegistration(BuiltInComponentIds.DesktopWeather),
|
[BuiltInComponentIds.DesktopWeather] = CreateWeatherRegistration(BuiltInComponentIds.DesktopWeather),
|
||||||
[BuiltInComponentIds.DesktopWeatherClock] = CreateWeatherRegistration(BuiltInComponentIds.DesktopWeatherClock),
|
[BuiltInComponentIds.DesktopWeatherClock] = CreateWeatherRegistration(BuiltInComponentIds.DesktopWeatherClock),
|
||||||
[BuiltInComponentIds.DesktopHourlyWeather] = CreateWeatherRegistration(BuiltInComponentIds.DesktopHourlyWeather),
|
[BuiltInComponentIds.DesktopHourlyWeather] = CreateWeatherRegistration(BuiltInComponentIds.DesktopHourlyWeather),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using System.Runtime.Versioning;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using LanMountainDesktop.Models;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using MudTools.OfficeInterop;
|
using MudTools.OfficeInterop;
|
||||||
using MudTools.OfficeInterop.Excel;
|
using MudTools.OfficeInterop.Excel;
|
||||||
@@ -18,7 +19,7 @@ namespace LanMountainDesktop.Services;
|
|||||||
|
|
||||||
public interface IOfficeRecentDocumentsService
|
public interface IOfficeRecentDocumentsService
|
||||||
{
|
{
|
||||||
List<OfficeRecentDocument> GetRecentDocuments(int maxCount = 20);
|
List<OfficeRecentDocument> GetRecentDocuments(int maxCount = 20, IReadOnlyCollection<string>? enabledSources = null);
|
||||||
void OpenDocument(string filePath);
|
void OpenDocument(string filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,20 +49,38 @@ public sealed class OfficeRecentDocumentsService : IOfficeRecentDocumentsService
|
|||||||
@"\[T(?<filetime>[0-9A-F]+)\]",
|
@"\[T(?<filetime>[0-9A-F]+)\]",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
public List<OfficeRecentDocument> GetRecentDocuments(int maxCount = 20)
|
public List<OfficeRecentDocument> GetRecentDocuments(int maxCount = 20, IReadOnlyCollection<string>? enabledSources = null)
|
||||||
{
|
{
|
||||||
var documents = new List<OfficeRecentDocument>();
|
var documents = new List<OfficeRecentDocument>();
|
||||||
|
var normalizedSources = OfficeRecentDocumentSourceTypes.NormalizeValues(
|
||||||
|
enabledSources,
|
||||||
|
useDefaultWhenEmpty: enabledSources is null);
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows())
|
if (!OperatingSystem.IsWindows() || normalizedSources.Count == 0)
|
||||||
{
|
{
|
||||||
return documents;
|
return documents;
|
||||||
}
|
}
|
||||||
|
|
||||||
TryGetFromRegistry(documents);
|
var useRegistry = normalizedSources.Contains(OfficeRecentDocumentSourceTypes.Registry, StringComparer.OrdinalIgnoreCase);
|
||||||
TryGetFromRecentFolders(documents);
|
var useRecentFolders = normalizedSources.Contains(OfficeRecentDocumentSourceTypes.RecentFolders, StringComparer.OrdinalIgnoreCase);
|
||||||
TryGetFromJumpLists(documents);
|
var useJumpLists = normalizedSources.Contains(OfficeRecentDocumentSourceTypes.JumpLists, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (documents.Count < maxCount)
|
if (useRegistry)
|
||||||
|
{
|
||||||
|
TryGetFromRegistry(documents);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useRecentFolders)
|
||||||
|
{
|
||||||
|
TryGetFromRecentFolders(documents);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useJumpLists)
|
||||||
|
{
|
||||||
|
TryGetFromJumpLists(documents);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useRegistry && documents.Count < maxCount)
|
||||||
{
|
{
|
||||||
TryGetFromMudToolsInterop(documents);
|
TryGetFromMudToolsInterop(documents);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:Class="LanMountainDesktop.Views.ComponentEditors.OfficeRecentDocumentsComponentEditor">
|
||||||
|
<StackPanel Spacing="16">
|
||||||
|
<Border Classes="component-editor-hero-card"
|
||||||
|
Padding="24">
|
||||||
|
<StackPanel Spacing="8">
|
||||||
|
<TextBlock x:Name="HeadlineTextBlock"
|
||||||
|
Classes="component-editor-headline"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<TextBlock x:Name="DescriptionTextBlock"
|
||||||
|
Classes="component-editor-secondary-text"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Classes="component-editor-card"
|
||||||
|
Padding="20">
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<TextBlock x:Name="SourcesHeaderTextBlock"
|
||||||
|
Classes="component-editor-section-title" />
|
||||||
|
<TextBlock x:Name="SourcesDescriptionTextBlock"
|
||||||
|
Classes="component-editor-secondary-text"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<CheckBox x:Name="RegistryCheckBox"
|
||||||
|
IsCheckedChanged="OnSourceSelectionChanged" />
|
||||||
|
<CheckBox x:Name="RecentFoldersCheckBox"
|
||||||
|
IsCheckedChanged="OnSourceSelectionChanged" />
|
||||||
|
<CheckBox x:Name="JumpListsCheckBox"
|
||||||
|
IsCheckedChanged="OnSourceSelectionChanged" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock x:Name="HintTextBlock"
|
||||||
|
Classes="component-editor-secondary-text"
|
||||||
|
Margin="12,0"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using LanMountainDesktop.ComponentSystem;
|
||||||
|
using LanMountainDesktop.Models;
|
||||||
|
|
||||||
|
namespace LanMountainDesktop.Views.ComponentEditors;
|
||||||
|
|
||||||
|
public partial class OfficeRecentDocumentsComponentEditor : ComponentEditorViewBase
|
||||||
|
{
|
||||||
|
private bool _suppressEvents;
|
||||||
|
|
||||||
|
public OfficeRecentDocumentsComponentEditor()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfficeRecentDocumentsComponentEditor(DesktopComponentEditorContext? context)
|
||||||
|
: base(context)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
ApplyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyState()
|
||||||
|
{
|
||||||
|
var snapshot = LoadSnapshot();
|
||||||
|
var enabledSources = OfficeRecentDocumentSourceTypes.NormalizeValues(
|
||||||
|
snapshot.OfficeRecentDocumentsEnabledSources,
|
||||||
|
useDefaultWhenEmpty: snapshot.OfficeRecentDocumentsEnabledSources is null);
|
||||||
|
|
||||||
|
HeadlineTextBlock.Text = Context?.Definition.DisplayName ?? "Office Recent Documents";
|
||||||
|
DescriptionTextBlock.Text = L(
|
||||||
|
"office_recent_documents.settings.desc",
|
||||||
|
"Choose which Windows and Office sources this widget should scan for recent documents.");
|
||||||
|
SourcesHeaderTextBlock.Text = L(
|
||||||
|
"office_recent_documents.settings.sources_title",
|
||||||
|
"Recent document sources");
|
||||||
|
SourcesDescriptionTextBlock.Text = L(
|
||||||
|
"office_recent_documents.settings.sources_desc",
|
||||||
|
"You can combine multiple sources. Registry selection also keeps the Office interop MRU fallback available.");
|
||||||
|
RegistryCheckBox.Content = L(
|
||||||
|
"office_recent_documents.settings.source.registry",
|
||||||
|
"Office registry MRU");
|
||||||
|
RecentFoldersCheckBox.Content = L(
|
||||||
|
"office_recent_documents.settings.source.recent_folders",
|
||||||
|
"Windows Recent folders");
|
||||||
|
JumpListsCheckBox.Content = L(
|
||||||
|
"office_recent_documents.settings.source.jump_lists",
|
||||||
|
"Windows Jump Lists");
|
||||||
|
HintTextBlock.Text = L(
|
||||||
|
"office_recent_documents.settings.hint",
|
||||||
|
"If you disable all sources, this widget will stay empty until at least one source is enabled again.");
|
||||||
|
|
||||||
|
_suppressEvents = true;
|
||||||
|
RegistryCheckBox.IsChecked = enabledSources.Contains(OfficeRecentDocumentSourceTypes.Registry, StringComparer.OrdinalIgnoreCase);
|
||||||
|
RecentFoldersCheckBox.IsChecked = enabledSources.Contains(OfficeRecentDocumentSourceTypes.RecentFolders, StringComparer.OrdinalIgnoreCase);
|
||||||
|
JumpListsCheckBox.IsChecked = enabledSources.Contains(OfficeRecentDocumentSourceTypes.JumpLists, StringComparer.OrdinalIgnoreCase);
|
||||||
|
_suppressEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSourceSelectionChanged(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_ = sender;
|
||||||
|
_ = e;
|
||||||
|
if (_suppressEvents)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedSources = new[]
|
||||||
|
{
|
||||||
|
RegistryCheckBox.IsChecked == true ? OfficeRecentDocumentSourceTypes.Registry : null,
|
||||||
|
RecentFoldersCheckBox.IsChecked == true ? OfficeRecentDocumentSourceTypes.RecentFolders : null,
|
||||||
|
JumpListsCheckBox.IsChecked == true ? OfficeRecentDocumentSourceTypes.JumpLists : null
|
||||||
|
}
|
||||||
|
.Where(static value => !string.IsNullOrWhiteSpace(value))
|
||||||
|
.Cast<string>()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var snapshot = LoadSnapshot();
|
||||||
|
snapshot.OfficeRecentDocumentsEnabledSources = selectedSources;
|
||||||
|
SaveSnapshot(snapshot, nameof(ComponentSettingsSnapshot.OfficeRecentDocumentsEnabledSources));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,14 +4,20 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
|
using LanMountainDesktop.ComponentSystem;
|
||||||
|
using LanMountainDesktop.Models;
|
||||||
using LanMountainDesktop.Services;
|
using LanMountainDesktop.Services;
|
||||||
|
|
||||||
namespace LanMountainDesktop.Views.Components;
|
namespace LanMountainDesktop.Views.Components;
|
||||||
|
|
||||||
public partial class OfficeRecentDocumentsWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget
|
public partial class OfficeRecentDocumentsWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, IComponentPlacementContextAware
|
||||||
{
|
{
|
||||||
private readonly IOfficeRecentDocumentsService _recentDocumentsService;
|
private readonly IOfficeRecentDocumentsService _recentDocumentsService;
|
||||||
|
private readonly IComponentInstanceSettingsStore _componentSettingsStore = HostComponentSettingsStoreProvider.GetOrCreate();
|
||||||
private List<OfficeRecentDocument> _documents = new();
|
private List<OfficeRecentDocument> _documents = new();
|
||||||
|
private string _componentId = BuiltInComponentIds.DesktopOfficeRecentDocuments;
|
||||||
|
private string _placementId = string.Empty;
|
||||||
|
private IReadOnlyList<string> _enabledSources = OfficeRecentDocumentSourceTypes.DefaultValues;
|
||||||
private bool _isOnActivePage;
|
private bool _isOnActivePage;
|
||||||
private bool _isEditMode;
|
private bool _isEditMode;
|
||||||
private bool _isLoading;
|
private bool _isLoading;
|
||||||
@@ -20,6 +26,7 @@ public partial class OfficeRecentDocumentsWidget : UserControl, IDesktopComponen
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_recentDocumentsService = new OfficeRecentDocumentsService();
|
_recentDocumentsService = new OfficeRecentDocumentsService();
|
||||||
|
ReloadSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyCellSize(double cellSize)
|
public void ApplyCellSize(double cellSize)
|
||||||
@@ -44,6 +51,15 @@ public partial class OfficeRecentDocumentsWidget : UserControl, IDesktopComponen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetComponentPlacementContext(string componentId, string? placementId)
|
||||||
|
{
|
||||||
|
_componentId = string.IsNullOrWhiteSpace(componentId)
|
||||||
|
? BuiltInComponentIds.DesktopOfficeRecentDocuments
|
||||||
|
: componentId.Trim();
|
||||||
|
_placementId = placementId?.Trim() ?? string.Empty;
|
||||||
|
ReloadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
private async void LoadDocuments()
|
private async void LoadDocuments()
|
||||||
{
|
{
|
||||||
if (_isLoading)
|
if (_isLoading)
|
||||||
@@ -54,10 +70,12 @@ public partial class OfficeRecentDocumentsWidget : UserControl, IDesktopComponen
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
|
ReloadSettings();
|
||||||
StatusTextBlock.IsVisible = false;
|
StatusTextBlock.IsVisible = false;
|
||||||
DocumentsItemsControl.ItemsSource = null;
|
DocumentsItemsControl.ItemsSource = null;
|
||||||
|
|
||||||
_documents = await Task.Run(() => _recentDocumentsService.GetRecentDocuments(20));
|
var enabledSources = _enabledSources.ToArray();
|
||||||
|
_documents = await Task.Run(() => _recentDocumentsService.GetRecentDocuments(20, enabledSources));
|
||||||
|
|
||||||
if (_documents.Count == 0)
|
if (_documents.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -80,6 +98,14 @@ public partial class OfficeRecentDocumentsWidget : UserControl, IDesktopComponen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReloadSettings()
|
||||||
|
{
|
||||||
|
var snapshot = _componentSettingsStore.LoadForComponent(_componentId, _placementId);
|
||||||
|
_enabledSources = OfficeRecentDocumentSourceTypes.NormalizeValues(
|
||||||
|
snapshot.OfficeRecentDocumentsEnabledSources,
|
||||||
|
useDefaultWhenEmpty: snapshot.OfficeRecentDocumentsEnabledSources is null);
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateDisplay()
|
private void UpdateDisplay()
|
||||||
{
|
{
|
||||||
var displayItems = _documents.Select(d => new OfficeRecentDocumentViewModel
|
var displayItems = _documents.Select(d => new OfficeRecentDocumentViewModel
|
||||||
|
|||||||
Reference in New Issue
Block a user