Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
remove icons (the picker reflects the change the next time it opens), and your
edits survive app updates. Delete it to restore the default set.

### Fixed
- **Window caption buttons invisible in Light theme.** The minimise, maximise and
close glyphs were always white, leaving them barely visible against the light
title bar. They now take a theme-appropriate colour, update when you switch
theme, and follow the OS when the theme is set to System.

### Changed
- **Home, navigation and shared-parameters polish.** The Home page leads with a
full-bleed hero banner (drop `Assets/HomeHero.png` to supply the image), the
Expand Down
69 changes: 60 additions & 9 deletions src/Snipdeck.App/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ public MainWindow(AppConfig config, ShellPage shellPage)
ShellHost.Content = shellPage;

ApplyTheme(config.Theme);

// While on System theme, the caption buttons must follow an OS
// light/dark flip too — RequestedTheme stays Default, so only
// ActualTheme changes.
if (Content is FrameworkElement themedRoot)
{
themedRoot.ActualThemeChanged += (sender, _) => UpdateCaptionButtonColours(sender.ActualTheme);
}
}

// The title-bar switcher and snip search bind to the shell view model.
Expand Down Expand Up @@ -129,18 +137,61 @@ private void OnSearchQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySu
}
}

private void ApplyTheme(ThemePreference theme)
/// <summary>
/// Applies the chosen theme to the app content and the system caption
/// buttons. Public so the runtime theme applier routes through here,
/// keeping the window content and the min/max/close glyphs in step.
/// </summary>
public void ApplyTheme(ThemePreference theme)
{
if (Content is FrameworkElement root)
if (Content is not FrameworkElement root)
{
root.RequestedTheme = theme switch
{
ThemePreference.Light => ElementTheme.Light,
ThemePreference.Dark => ElementTheme.Dark,
ThemePreference.System => ElementTheme.Default,
_ => ElementTheme.Default,
};
return;
}

root.RequestedTheme = theme switch
{
ThemePreference.Light => ElementTheme.Light,
ThemePreference.Dark => ElementTheme.Dark,
ThemePreference.System => ElementTheme.Default,
_ => ElementTheme.Default,
};

// ActualTheme resolves Default to the OS light/dark choice, so the
// caption glyphs get a concrete theme to contrast against.
UpdateCaptionButtonColours(root.ActualTheme);
}

// The caption buttons are system-drawn chrome, not styled by the app's
// theme resources — so without this they keep their default (white)
// glyphs and vanish on a light background. Backgrounds stay transparent
// so the Mica backdrop shows through; only the glyph colours change.
private void UpdateCaptionButtonColours(ElementTheme actualTheme)
{
var dark = actualTheme == ElementTheme.Dark;

var foreground = dark
? Microsoft.UI.Colors.White
: Windows.UI.Color.FromArgb(0xFF, 0x1A, 0x1A, 0x1A);
var inactive = dark
? Windows.UI.Color.FromArgb(0xFF, 0x80, 0x80, 0x80)
: Windows.UI.Color.FromArgb(0xFF, 0x8A, 0x8A, 0x8A);
var hoverBackground = dark
? Windows.UI.Color.FromArgb(0x1F, 0xFF, 0xFF, 0xFF)
: Windows.UI.Color.FromArgb(0x14, 0x00, 0x00, 0x00);
var pressedBackground = dark
? Windows.UI.Color.FromArgb(0x12, 0xFF, 0xFF, 0xFF)
: Windows.UI.Color.FromArgb(0x0A, 0x00, 0x00, 0x00);

var titleBar = AppWindow.TitleBar;
titleBar.ButtonBackgroundColor = Microsoft.UI.Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Microsoft.UI.Colors.Transparent;
titleBar.ButtonForegroundColor = foreground;
titleBar.ButtonHoverForegroundColor = foreground;
titleBar.ButtonHoverBackgroundColor = hoverBackground;
titleBar.ButtonPressedForegroundColor = foreground;
titleBar.ButtonPressedBackgroundColor = pressedBackground;
titleBar.ButtonInactiveForegroundColor = inactive;
}
}
}
15 changes: 3 additions & 12 deletions src/Snipdeck.App/Services/WindowsThemeApplier.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Microsoft.UI.Xaml;

using Snipdeck.Core.Abstractions;
using Snipdeck.Core.Models;

Expand All @@ -17,17 +15,10 @@ public WindowsThemeApplier(IServiceProvider services)

public void Apply(ThemePreference theme)
{
// Route through the window so the content and the system caption
// buttons are themed together (see MainWindow.ApplyTheme).
var mainWindow = (MainWindow?)_services.GetService(typeof(MainWindow));
if (mainWindow?.Content is FrameworkElement root)
{
root.RequestedTheme = theme switch
{
ThemePreference.Light => ElementTheme.Light,
ThemePreference.Dark => ElementTheme.Dark,
ThemePreference.System => ElementTheme.Default,
_ => ElementTheme.Default,
};
}
mainWindow?.ApplyTheme(theme);
}
}
}
Loading