diff --git a/CHANGELOG.md b/CHANGELOG.md index 6be3a53..67a1f27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 IL2104 on the WinAppSDK/WinRT/Jdenticon assemblies, which aren't trim-safe. ### Added +- **Change the storage location.** A "Change…" button on Settings → Storage + location lets you pick a new folder for your snips. If the folder already + contains a Snipdeck store it's adopted (your current snips are left where + they are); otherwise your store and icons are copied there (the old folder + is kept as a backup). The choice is confirmed first, and Snipdeck restarts + to apply it — the storage path is read at startup, so restarting keeps + everything consistent and avoids writing to the old location after the + switch. If the automatic restart can't run, you're prompted to restart + manually. - **Rebindable global hotkey.** The global hotkey is now editable from Settings: click the capture box and press a shortcut (at least one of Ctrl/Alt/Shift plus a key). The new binding registers and persists diff --git a/src/Snipdeck.App/Bootstrap.cs b/src/Snipdeck.App/Bootstrap.cs index 52bc1f4..d2e976b 100644 --- a/src/Snipdeck.App/Bootstrap.cs +++ b/src/Snipdeck.App/Bootstrap.cs @@ -42,6 +42,9 @@ public static IServiceProvider Build() .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(new StorageRelocationService(_snipStoreFileName)) .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/Snipdeck.App/Services/WindowsAppRestartService.cs b/src/Snipdeck.App/Services/WindowsAppRestartService.cs new file mode 100644 index 0000000..4084942 --- /dev/null +++ b/src/Snipdeck.App/Services/WindowsAppRestartService.cs @@ -0,0 +1,18 @@ +using Snipdeck.Core.Abstractions; + +using Microsoft.Windows.AppLifecycle; + +namespace Snipdeck.App.Services +{ + internal sealed class WindowsAppRestartService : IAppRestartService + { + public bool Restart() + { + // On success Windows App SDK terminates the process and this never + // returns. If it returns, it failed (it yields a failure reason + // rather than throwing), so report that to the caller. + _ = AppInstance.Restart(string.Empty); + return false; + } + } +} diff --git a/src/Snipdeck.App/Services/WindowsFolderPickerService.cs b/src/Snipdeck.App/Services/WindowsFolderPickerService.cs new file mode 100644 index 0000000..3a7116f --- /dev/null +++ b/src/Snipdeck.App/Services/WindowsFolderPickerService.cs @@ -0,0 +1,33 @@ +using Snipdeck.Core.Abstractions; + +using Windows.Storage.Pickers; + +namespace Snipdeck.App.Services +{ + internal sealed class WindowsFolderPickerService : IFolderPickerService + { + private readonly IServiceProvider _services; + + public WindowsFolderPickerService(IServiceProvider services) + { + ArgumentNullException.ThrowIfNull(services); + _services = services; + } + + public async Task PickFolderAsync() + { + var picker = new FolderPicker + { + SuggestedStartLocation = PickerLocationId.DocumentsLibrary, + }; + picker.FileTypeFilter.Add("*"); + + var mainWindow = (MainWindow)_services.GetService(typeof(MainWindow))!; + var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(mainWindow); + WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd); + + var folder = await picker.PickSingleFolderAsync(); + return folder?.Path; + } + } +} diff --git a/src/Snipdeck.App/Views/ShellPage.xaml b/src/Snipdeck.App/Views/ShellPage.xaml index 55bd998..e4f81df 100644 --- a/src/Snipdeck.App/Views/ShellPage.xaml +++ b/src/Snipdeck.App/Views/ShellPage.xaml @@ -187,11 +187,16 @@ - + Description="Where your snips live. Changing it restarts Snipdeck to load the new location."> + + +