[Peek]Add Delete functionality (#35418)

* Add Delete functionality for Peek.

* Updated the "No More Files" text block to use a Uid to load its resource text. Also altered the text style to be consistent with the FailedFallbackPreviewControl error page.

* Revert "Delete Directory.Packages.props"

This reverts commit 3a10918c9f91de64785722e4bdb33c58d1c2daea.

* Attempt to appease the spell-checking bot by renaming flag const.

* Show error message InfoBar if file deletion failed.

* Resolve XAML styling.

* XAML styling fix.

* Settings app updates for new delete confirmation setting.

* Add delete confirmation dialog and settings to Peek. Add shell notification event after delete operation.

* Spelling updates.

* Spelling update.

* Remove permanent delete parameter, YAGNI. Add hwnd parameter to delete so warning dialogs are correctly parented. Fix flags to not hide permanent delete warning.

* Simplify delete confirmation dialog. Remove workaround for focus visual issue. Ensure delete confirmation dialog is closed when the main window visibility is toggled.

* Fix delete delay. Do not regard user cancellations of permanent deletes as an error, but log them as info anyway. More descriptive name for delete confirmation dialog checkbox.

* Fix multiple Content_KeyUp events being raised for MainWindow.

* Synchronise ConfirmFileDelete setting between Peek and Settings app.

* Update following review: split System usings from others; do not log deleted item name.

* Fix XAML style
This commit is contained in:
Dave Rayment
2025-03-18 08:59:20 +00:00
committed by GitHub
parent abd6314b2e
commit 8e90d8e4c5
21 changed files with 795 additions and 90 deletions

View File

@@ -4,63 +4,105 @@
using System;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Text.Json;
using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.PowerToys.Settings.UI.SerializationContext;
using Microsoft.UI.Dispatching;
using Settings.UI.Library;
namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
public partial class PeekViewModel : Observable
public class PeekViewModel : Observable, IDisposable
{
private bool _isEnabled;
private bool _settingsUpdating;
private GeneralSettings GeneralSettingsConfig { get; set; }
private readonly DispatcherQueue _dispatcherQueue;
private readonly ISettingsUtils _settingsUtils;
private readonly PeekSettings _peekSettings;
private readonly PeekPreviewSettings _peekPreviewSettings;
private PeekSettings _peekSettings;
private GpoRuleConfigured _enabledGpoRuleConfiguration;
private bool _enabledStateIsGPOConfigured;
private Func<string, int> SendConfigMSG { get; }
public PeekViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
private IFileSystemWatcher _watcher;
public PeekViewModel(
ISettingsUtils settingsUtils,
ISettingsRepository<GeneralSettings> settingsRepository,
Func<string, int> ipcMSGCallBackFunc,
DispatcherQueue dispatcherQueue)
{
// To obtain the general settings configurations of PowerToys Settings.
ArgumentNullException.ThrowIfNull(settingsRepository);
GeneralSettingsConfig = settingsRepository.SettingsConfig;
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
if (_settingsUtils.SettingsExists(PeekSettings.ModuleName))
{
_peekSettings = _settingsUtils.GetSettingsOrDefault<PeekSettings>(PeekSettings.ModuleName);
}
else
{
_peekSettings = new PeekSettings();
}
_dispatcherQueue = dispatcherQueue ?? throw new ArgumentNullException(nameof(dispatcherQueue));
if (_settingsUtils.SettingsExists(PeekSettings.ModuleName, PeekPreviewSettings.FileName))
{
_peekPreviewSettings = _settingsUtils.GetSettingsOrDefault<PeekPreviewSettings>(PeekSettings.ModuleName, PeekPreviewSettings.FileName);
}
else
{
_peekPreviewSettings = new PeekPreviewSettings();
}
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
// Load the application-specific settings, including preview items.
_peekSettings = _settingsUtils.GetSettingsOrDefault<PeekSettings>(PeekSettings.ModuleName);
_peekPreviewSettings = _settingsUtils.GetSettingsOrDefault<PeekPreviewSettings>(PeekSettings.ModuleName, PeekPreviewSettings.FileName);
SetupSettingsFileWatcher();
InitializeEnabledValue();
SendConfigMSG = ipcMSGCallBackFunc;
}
/// <summary>
/// Set up the file watcher for the settings file. Used to respond to updates to the
/// ConfirmFileDelete setting by the user within the Peek application itself.
/// </summary>
private void SetupSettingsFileWatcher()
{
string settingsPath = _settingsUtils.GetSettingsFilePath(PeekSettings.ModuleName);
_watcher = Helper.GetFileWatcher(PeekSettings.ModuleName, SettingsUtils.DefaultFileName, () =>
{
try
{
_settingsUpdating = true;
var newSettings = _settingsUtils.GetSettings<PeekSettings>(PeekSettings.ModuleName);
_dispatcherQueue.TryEnqueue(() =>
{
try
{
ConfirmFileDelete = newSettings.Properties.ConfirmFileDelete.Value;
_peekSettings = newSettings;
}
finally
{
// Only clear the flag once the UI update is complete.
_settingsUpdating = false;
}
});
}
catch (Exception ex)
{
Logger.LogError($"Failed to load Peek settings: {ex.Message}", ex);
_settingsUpdating = false;
}
});
}
private void InitializeEnabledValue()
{
_enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredPeekEnabledValue();
@@ -147,6 +189,20 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
public bool ConfirmFileDelete
{
get => _peekSettings.Properties.ConfirmFileDelete.Value;
set
{
if (_peekSettings.Properties.ConfirmFileDelete.Value != value)
{
_peekSettings.Properties.ConfirmFileDelete.Value = value;
OnPropertyChanged(nameof(ConfirmFileDelete));
NotifySettingsChanged();
}
}
}
public bool SourceCodeWrapText
{
get => _peekPreviewSettings.SourceCodeWrapText.Value;
@@ -219,7 +275,14 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private void NotifySettingsChanged()
{
// Using InvariantCulture as this is an IPC message
// Do not send IPC message if the settings file has been updated by Peek itself.
if (_settingsUpdating)
{
return;
}
// This message will be intercepted by the runner, which passes the serialized JSON to
// Peek.set_config() in the C++ Peek project, which then saves it to file.
SendConfigMSG(
string.Format(
CultureInfo.InvariantCulture,
@@ -238,5 +301,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
InitializeEnabledValue();
OnPropertyChanged(nameof(IsEnabled));
}
public void Dispose()
{
_watcher?.Dispose();
GC.SuppressFinalize(this);
}
}
}