Skip to content

CmdPal: Add slideshow background mode and rotation settings#46452

Open
Error0229 wants to merge 5 commits intomicrosoft:mainfrom
Error0229:feature/cmdpal-background-slideshow-45879
Open

CmdPal: Add slideshow background mode and rotation settings#46452
Error0229 wants to merge 5 commits intomicrosoft:mainfrom
Error0229:feature/cmdpal-background-slideshow-45879

Conversation

@Error0229
Copy link
Copy Markdown

@Error0229 Error0229 commented Mar 24, 2026

Summary of the Pull Request

  • Add a dedicated Slideshow background mode in CmdPal appearance settings
  • Add slideshow folder path, change interval (on activation / 1 / 10 / 30 / 60 min), and shuffle settings
  • Add slideshow rotation engine in ThemeService — rotates on hide so next activation shows new image
  • Shuffle uses Fisher-Yates algorithm to guarantee every image is shown before any repeats
  • Add BackgroundImagePathResolver utility with 13 unit tests
  • Fix a settings crash by guarding against empty preview image paths

PR Checklist

Detailed Description of the Pull Request / Additional comments

New mode: Slideshow

ColorizationMode.Slideshow is added alongside the existing Image mode. Both modes share tint/opacity/blur/fit controls, but have separate path controls — single-image uses a file picker (BackgroundImagePath), slideshow uses a folder picker (BackgroundImageSlideshowFolderPath).

Rotation engine

ThemeService maintains internal state to track the current slideshow image. Rotation triggers on: folder changed, current file deleted, or activation after the configured interval elapsed. Supports both shuffle and sequential (alphabetical wrap-around) ordering.

Shuffle algorithm

Uses Fisher-Yates to pre-shuffle the full index array, then walks through it with a cursor. When the deck is exhausted, reshuffles — with the last-shown image swapped away from position 0 to avoid repeats at deck boundaries. This guarantees every image is shown exactly once before any image repeats.

Rotation timing

MainWindow.HideWindow() calls RefreshThemeForActivation() before hiding, so the image swaps while invisible — no flicker on next activation.

Settings

New JSON keys (additive, no migration needed):

  • BackgroundImageSlideshowFolderPath (string)
  • BackgroundImageChangeIntervalMinutes (int, default 0 = on activation only)
  • BackgroundImageShuffle (bool, default true)

Validation Steps Performed

  • Built src/modules/cmdpal/Microsoft.CmdPal.UI with tools/build/build.cmd (Debug/x64) — 0 errors
  • Built and ran BackgroundImagePathResolverTests (13/13 passed)
  • Manually validated CmdPal settings flow for Image vs Slideshow modes
  • Validated on-hide rotation behavior
  • Verified shuffle covers all images before repeating

catol-abacus and others added 3 commits March 23, 2026 17:13
…t#45879)

Add a dedicated Slideshow background mode in CmdPal appearance settings
with folder-based image rotation, configurable interval, and shuffle.

- Add ColorizationMode.Slideshow enum value
- Add slideshow folder path, change interval, and shuffle settings
- Add slideshow rotation engine in ThemeService (sequential/shuffle,
  interval-based, rotate-on-hide so next activation shows new image)
- Add BackgroundImagePathResolver utility with unit tests (13 tests)
- Add folder picker and slideshow controls to AppearancePage
- Fix settings crash on empty preview image paths
- Add localized strings for all new UI elements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Single-button StackPanel wrappers around the image picker and folder picker
buttons serve no purpose. Use the Button directly as the SettingsCard content.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eImageUri

Move the relative-path-to-absolute-URI logic out of the view model ternary
chains into a dedicated helper. Both AppearanceSettingsViewModel and
DockAppearanceSettingsViewModel now read as a simple null-check chain.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Error0229
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@github-actions

This comment has been minimized.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Error0229 Error0229 force-pushed the feature/cmdpal-background-slideshow-45879 branch from f715528 to 1d6734e Compare March 24, 2026 01:18
@michaeljolley
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@michaeljolley michaeljolley added the Product-Command Palette Refers to the Command Palette utility label Mar 24, 2026
@michaeljolley michaeljolley requested a review from Copilot March 24, 2026 18:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Slideshow background mode to CmdPal’s appearance settings, including folder selection and rotation behavior, so users can rotate background images from a directory instead of a single file.

Changes:

  • Introduces ColorizationMode.Slideshow plus new persisted settings for slideshow folder, change interval, and shuffle.
  • Updates settings UI to support slideshow selection (folder picker + interval/shuffle controls).
  • Adds BackgroundImagePathResolver utility (with unit tests) and wires it into theme/image preview paths.

Reviewed changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ColorizationMode.cs Adds Slideshow mode to the colorization enum.
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/SettingsModel.cs Persists slideshow folder, interval minutes, and shuffle flag.
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Services/IThemeService.cs Adds RefreshThemeForActivation() hook for summon-time refresh behavior.
src/modules/cmdpal/Microsoft.CmdPal.UI/Services/ThemeService.cs Implements slideshow rotation/selection logic and integrates slideshow into theme snapshot generation.
src/modules/cmdpal/Microsoft.CmdPal.UI/MainWindow.xaml.cs Triggers slideshow refresh before hiding to avoid visible swaps on next activation.
src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/AppearancePage.xaml Adds Slideshow option and slideshow-specific settings cards/controls.
src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/AppearancePage.xaml.cs Implements folder picker and forces mode switch when picking file/folder.
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/AppearanceSettingsViewModel.cs Adds slideshow settings bindings and preview image resolution logic.
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DockAppearanceSettingsViewModel.cs Uses resolver-based URI creation for safer image preview resolution.
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/MainWindowViewModel.cs Applies theme snapshots on UI thread without always dispatching.
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/BackgroundImagePathResolver.cs New helper to resolve folder-vs-file paths, supported images, and safe image URIs.
src/modules/cmdpal/Tests/Microsoft.CmdPal.UI.ViewModels.UnitTests/BackgroundImagePathResolverTests.cs Adds unit tests covering resolver behaviors (folder/file/URI cases).
src/modules/cmdpal/Microsoft.CmdPal.UI/Strings/en-us/Resources.resw Adds localized strings for slideshow UI and interval/shuffle labels.
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Properties/Resources.resx Adds localized string used by folder picker commit button.
src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Properties/Resources.Designer.cs Regenerates strongly-typed accessor for the new resx string.
.github/actions/spell-check/expect.txt Adds “slideshow” to spelling allow-list and removes an unused entry.
Files not reviewed (1)
  • src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Properties/Resources.Designer.cs: Language not supported

…trings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.

Files not reviewed (1)
  • src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Properties/Resources.Designer.cs: Language not supported

Comment on lines +118 to +122
public void TryGetLocalFolderPath_WithNull_ReturnsFalse()
{
var ok = BackgroundImagePathResolver.TryGetLocalFolderPath(null, out var resolved);

Assert.IsFalse(ok);
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a unit test that passes an invalid/malformed path (illegal characters or malformed URI) into TryGetLocalFolderPath and asserts it returns false without throwing. This matters because the resolver is invoked from UI-bound properties and theme reload code paths.

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +68
var localCandidate = Path.GetFullPath(candidate);
if (!Directory.Exists(localCandidate))
{
return false;
}

folderPath = localCandidate;
return true;
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TryGetLocalFolderPath uses Path.GetFullPath(candidate) without guarding for ArgumentException / NotSupportedException (e.g., settings.json contains an invalid path). That will throw and can crash theme reload/settings UI. Wrap GetFullPath in a try/catch and return false on invalid paths.

Suggested change
var localCandidate = Path.GetFullPath(candidate);
if (!Directory.Exists(localCandidate))
{
return false;
}
folderPath = localCandidate;
return true;
try
{
var localCandidate = Path.GetFullPath(candidate);
if (!Directory.Exists(localCandidate))
{
return false;
}
folderPath = localCandidate;
return true;
}
catch (ArgumentException)
{
return false;
}
catch (NotSupportedException)
{
return false;
}

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +14
public static readonly HashSet<string> SupportedImageExtensions = new(StringComparer.OrdinalIgnoreCase)
{
".png",
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SupportedImageExtensions is exposed as a public mutable HashSet<string>, so external callers can add/remove extensions at runtime and break filtering. Consider exposing an immutable view (e.g., IReadOnlyCollection<string> / string[]) and keeping the HashSet private for membership checks.

Copilot uses AI. Check for mistakes.
/// Requests an immediate refresh for summon-time visuals.
/// </summary>
/// <remarks>
/// Used for activation-driven updates such as background slideshow rotation.
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RefreshThemeForActivation() is a new public interface member but doesn’t document thread-affinity. Since the implementation calls Reload() (which touches XAML/BitmapImage), please document that it must be invoked on the UI thread (or enforce via an assert/dispatcher marshal) to prevent future off-thread callers from causing crashes.

Suggested change
/// Used for activation-driven updates such as background slideshow rotation.
/// Used for activation-driven updates such as background slideshow rotation.
/// This method is UI-thread-affine and must be invoked on the UI thread.
/// Callers are responsible for marshalling to the UI thread (for example, via a dispatcher)
/// before invoking this method.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Merge conflict 🙀 Product-Command Palette Refers to the Command Palette utility

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CmdPal: Support background image rotation from a folder

4 participants