Skip to content

Commit

Permalink
[Peek]Add setting to close after losing focus (#26364)
Browse files Browse the repository at this point in the history
* [Peek] WindowActivationState checks are added for focus and close after losing focus.

* Add setting to activate the behavior

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
  • Loading branch information
gokcekantarci and jaimecbernardo authored May 30, 2023
1 parent 9786d08 commit 0c69e34
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/modules/peek/Peek.UI/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public App()
{
// Core Services
services.AddTransient<NeighboringItemsQuery>();
services.AddSingleton<IUserSettings, UserSettings>();

// Views and ViewModels
services.AddTransient<TitleBar>();
Expand Down
19 changes: 19 additions & 0 deletions src/modules/peek/Peek.UI/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using interop;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input;
using Peek.Common.Constants;
using Peek.FilePreviewer.Models;
Expand All @@ -28,6 +29,7 @@ public sealed partial class MainWindow : WindowEx
public MainWindow()
{
InitializeComponent();
this.Activated += PeekWindow_Activated;

ViewModel = App.GetService<MainWindowViewModel>();

Expand All @@ -38,6 +40,23 @@ public MainWindow()
AppWindow.Closing += AppWindow_Closing;
}

private void PeekWindow_Activated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args)
{
if (args.WindowActivationState == Microsoft.UI.Xaml.WindowActivationState.CodeActivated)
{
this.BringToForeground();
}

if (args.WindowActivationState == Microsoft.UI.Xaml.WindowActivationState.Deactivated)
{
var userSettings = App.GetService<IUserSettings>();
if (userSettings.CloseAfterLosingFocus)
{
Uninitialize();
}
}
}

/// <summary>
/// Handle Peek hotkey, by toggling the window visibility and querying files when necessary.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions src/modules/peek/Peek.UI/Services/IUserSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation
// 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;

namespace Peek.UI
{
public interface IUserSettings
{
public bool CloseAfterLosingFocus { get; }
}
}
85 changes: 85 additions & 0 deletions src/modules/peek/Peek.UI/Services/UserSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation
// 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.IO;
using System.IO.Abstractions;
using System.Threading;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;

namespace Peek.UI
{
public class UserSettings : IUserSettings
{
private const string PeekModuleName = "Peek";
private const int MaxNumberOfRetry = 5;

private readonly ISettingsUtils _settingsUtils;
private readonly IFileSystemWatcher _watcher;
private readonly object _loadingSettingsLock = new object();

public bool CloseAfterLosingFocus { get; private set; }

public UserSettings()
{
_settingsUtils = new SettingsUtils();
CloseAfterLosingFocus = false;

LoadSettingsFromJson();

_watcher = Helper.GetFileWatcher(PeekModuleName, "settings.json", () => LoadSettingsFromJson());
}

private void LoadSettingsFromJson()
{
lock (_loadingSettingsLock)
{
var retry = true;
var retryCount = 0;

while (retry)
{
try
{
retryCount++;

if (!_settingsUtils.SettingsExists(PeekModuleName))
{
Logger.LogInfo("Hosts settings.json was missing, creating a new one");
var defaultSettings = new PeekSettings();
defaultSettings.Save(_settingsUtils);
}

var settings = _settingsUtils.GetSettingsOrDefault<PeekSettings>(PeekModuleName);
if (settings != null)
{
CloseAfterLosingFocus = settings.Properties.CloseAfterLosingFocus.Value;
}

retry = false;
}
catch (IOException e)
{
if (retryCount > MaxNumberOfRetry)
{
retry = false;
Logger.LogError($"Failed to Deserialize PowerToys settings, Retrying {e.Message}", e);
}
else
{
Thread.Sleep(500);
}
}
catch (Exception ex)
{
retry = false;
Logger.LogError("Failed to read changed settings", ex);
}
}
}
}
}
}
3 changes: 3 additions & 0 deletions src/settings-ui/Settings.UI.Library/PeekProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ public PeekProperties()
{
ActivationShortcut = new HotkeySettings(false, true, false, false, 0x20);
AlwaysRunNotElevated = new BoolProperty(true);
CloseAfterLosingFocus = new BoolProperty(false);
}

public HotkeySettings ActivationShortcut { get; set; }

public BoolProperty AlwaysRunNotElevated { get; set; }

public BoolProperty CloseAfterLosingFocus { get; set; }

public override string ToString() => JsonSerializer.Serialize(this);
}
}
18 changes: 18 additions & 0 deletions src/settings-ui/Settings.UI.Library/PeekSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;

Expand Down Expand Up @@ -31,5 +33,21 @@ public bool UpgradeSettingsConfiguration()
{
return false;
}

public virtual void Save(ISettingsUtils settingsUtils)
{
// Save settings to file
var options = new JsonSerializerOptions
{
WriteIndented = true,
};

if (settingsUtils == null)
{
throw new ArgumentNullException(nameof(settingsUtils));
}

settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
}
}
}
4 changes: 4 additions & 0 deletions src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2843,6 +2843,10 @@ From there, simply click on one of the supported files in the File Explorer and
<value>Tries to run Peek without elevated permissions, to fix access to network shares. You need to disable and re-enable Peek for changes to this value to take effect.</value>
<comment>Peek is a product name, do not loc</comment>
</data>
<data name="Peek_CloseAfterLosingFocus.Header" xml:space="preserve">
<value>Automatically close the Peek window after it loses focus</value>
<comment>Peek is a product name, do not loc</comment>
</data>
<data name="FancyZones_DisableRoundCornersOnWindowSnap.Content" xml:space="preserve">
<value>Disable round corners when window is snapped</value>
</data>
Expand Down
14 changes: 14 additions & 0 deletions src/settings-ui/Settings.UI/ViewModels/PeekViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ public bool AlwaysRunNotElevated
}
}

public bool CloseAfterLosingFocus
{
get => _peekSettings.Properties.CloseAfterLosingFocus.Value;
set
{
if (_peekSettings.Properties.CloseAfterLosingFocus.Value != value)
{
_peekSettings.Properties.CloseAfterLosingFocus.Value = value;
OnPropertyChanged(nameof(CloseAfterLosingFocus));
NotifySettingsChanged();
}
}
}

private void NotifySettingsChanged()
{
// Using InvariantCulture as this is an IPC message
Expand Down
5 changes: 5 additions & 0 deletions src/settings-ui/Settings.UI/Views/PeekPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
x:Uid="ToggleSwitch"
IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.AlwaysRunNotElevated}" />
</labs:SettingsCard>
<labs:SettingsCard x:Uid="Peek_CloseAfterLosingFocus">
<ToggleSwitch
x:Uid="ToggleSwitch"
IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.CloseAfterLosingFocus}" />
</labs:SettingsCard>
</controls:SettingsGroup>

</StackPanel>
Expand Down

0 comments on commit 0c69e34

Please sign in to comment.