Repository: huynhsontung/Screenbox
Pull request #562: style: update system caption button colors
Author: login: United600
Labels: name: enhancement
description: New feature or request
name: size:L
description: This PR changes 100-499 lines, ignoring generated files.
Created: 2025-02-10T21:58:40Z | Merged: 2025-04-18T23:12:00Z

Changes the caption button colors according to the design specifications. Uses subtle brushes for the hover and pressed background colors.
Fixes the caption buttons colors in light mode with the "Show accent color on title bars and windows borders" setting enabled
Fixes the dialogs not respecting the user's selected theme

Old|New
-|-
![Shows the hover color of the current minimize caption button](https://github.com/user-attachments/assets/1eb246c8-5f47-4449-ae90-14ee5c309698)|![Shows the hover color of the new minimize caption button](https://github.com/user-attachments/assets/1b636b68-7640-46da-8e4d-98ac7bef68a5)

### Task list

- [x] Fix the transition between video and audio content in light mode
- [x] Trigger the color change with the app theme setting


Diff:
diff --git a/Screenbox/App.xaml.cs b/Screenbox/App.xaml.cs
index 88df89f5e..6caef3f8f 100644
--- a/Screenbox/App.xaml.cs
+++ b/Screenbox/App.xaml.cs
@@ -1,5 +1,10 @@
 ﻿#nullable enable
 
+using System;
+using System.Collections.Generic;
+using System.Runtime.ExceptionServices;
+using System.Security;
+using System.Threading.Tasks;
 using CommunityToolkit.Mvvm.Messaging;
 using CommunityToolkit.WinUI.Helpers;
 using Microsoft.AppCenter;
@@ -12,15 +17,11 @@
 using Screenbox.Core.Messages;
 using Screenbox.Core.Services;
 using Screenbox.Core.ViewModels;
+using Screenbox.Helpers;
 using Screenbox.Pages;
 using Screenbox.Services;
 using Sentry;
 using Sentry.Protocol;
-using System;
-using System.Collections.Generic;
-using System.Runtime.ExceptionServices;
-using System.Security;
-using System.Threading.Tasks;
 using Windows.ApplicationModel;
 using Windows.ApplicationModel.Activation;
 using Windows.ApplicationModel.Resources.Core;
@@ -304,9 +305,19 @@ private Frame InitRootFrame()
 
                 var settings = CommunityToolkit.Mvvm.DependencyInjection.Ioc.Default.GetRequiredService<ISettingsService>();
                 rootFrame.RequestedTheme = settings.Theme.ToElementTheme();
+
+                // Register a handler for when the theme mode changes
+                rootFrame.ActualThemeChanged += OnActualThemeChanged;
+
+                TitleBarHelper.SetCaptionButtonColors(rootFrame);
             }
 
             return rootFrame;
         }
+
+        private void OnActualThemeChanged(FrameworkElement sender, object args)
+        {
+            TitleBarHelper.SetCaptionButtonColors(sender);
+        }
     }
 }
diff --git a/Screenbox/Controls/OpenUrlDialog.xaml.cs b/Screenbox/Controls/OpenUrlDialog.xaml.cs
index b122ab3c1..21779f614 100644
--- a/Screenbox/Controls/OpenUrlDialog.xaml.cs
+++ b/Screenbox/Controls/OpenUrlDialog.xaml.cs
@@ -2,6 +2,7 @@
 
 using System;
 using System.Threading.Tasks;
+using Windows.UI.Xaml;
 using Windows.UI.Xaml.Controls;
 
 // The Content Dialog item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
@@ -15,6 +16,7 @@ public OpenUrlDialog()
             this.DefaultStyleKey = typeof(ContentDialog);
             this.InitializeComponent();
             FlowDirection = App.GetFlowDirection();
+            RequestedTheme = ((FrameworkElement)Window.Current.Content).RequestedTheme;
         }
 
         public static async Task<Uri?> GetUrlAsync()
@@ -32,4 +34,4 @@ private bool CanOpen(string url)
             return Uri.TryCreate(url, UriKind.Absolute, out Uri _);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Screenbox/Controls/PropertiesDialog.xaml.cs b/Screenbox/Controls/PropertiesDialog.xaml.cs
index 3fa9d6be8..c50362266 100644
--- a/Screenbox/Controls/PropertiesDialog.xaml.cs
+++ b/Screenbox/Controls/PropertiesDialog.xaml.cs
@@ -27,6 +27,7 @@ public PropertiesDialog()
         {
             this.InitializeComponent();
             FlowDirection = App.GetFlowDirection();
+            RequestedTheme = ((FrameworkElement)Window.Current.Content).RequestedTheme;
         }
     }
 }
diff --git a/Screenbox/Controls/PropertiesView.xaml b/Screenbox/Controls/PropertiesView.xaml
index 0cabee6cc..10ca81ac2 100644
--- a/Screenbox/Controls/PropertiesView.xaml
+++ b/Screenbox/Controls/PropertiesView.xaml
@@ -29,7 +29,7 @@
                         Margin="0,0,8,0"
                         HorizontalAlignment="Left"
                         VerticalAlignment="Top"
-                        Foreground="{StaticResource SystemControlForegroundBaseMediumBrush}"
+                        Foreground="{ThemeResource TextFillColorSecondaryBrush}"
                         Style="{StaticResource CaptionTextBlockStyle}"
                         Text="{Binding Key}"
                         TextTrimming="CharacterEllipsis" />
@@ -121,7 +121,7 @@
                         Margin="0,10,0,0"
                         HorizontalAlignment="Left"
                         VerticalAlignment="Top"
-                        Foreground="{StaticResource SystemControlForegroundBaseMediumBrush}"
+                        Foreground="{ThemeResource TextFillColorSecondaryBrush}"
                         Style="{StaticResource CaptionTextBlockStyle}"
                         Text="{x:Bind strings:Resources.PropertyFileLocation}"
                         TextTrimming="CharacterEllipsis" />
diff --git a/Screenbox/Controls/SetOptionsDialog.xaml.cs b/Screenbox/Controls/SetOptionsDialog.xaml.cs
index 6e06a998a..15f942a3a 100644
--- a/Screenbox/Controls/SetOptionsDialog.xaml.cs
+++ b/Screenbox/Controls/SetOptionsDialog.xaml.cs
@@ -25,6 +25,7 @@ public SetOptionsDialog(string existingOptions, bool global = false)
     {
         this.InitializeComponent();
         FlowDirection = App.GetFlowDirection();
+        RequestedTheme = ((FrameworkElement)Window.Current.Content).RequestedTheme;
         OptionTextBoxPlaceholder = global ? "--option=value" : ":option=value";
         Options = existingOptions;
         OptionsTextBox.Text = Options;
diff --git a/Screenbox/Controls/VLCLoginDialog.xaml.cs b/Screenbox/Controls/VLCLoginDialog.xaml.cs
index d7349e4d3..0b2efe91f 100644
--- a/Screenbox/Controls/VLCLoginDialog.xaml.cs
+++ b/Screenbox/Controls/VLCLoginDialog.xaml.cs
@@ -44,6 +44,7 @@ public VLCLoginDialog()
         {
             this.InitializeComponent();
             FlowDirection = App.GetFlowDirection();
+            RequestedTheme = ((FrameworkElement)Window.Current.Content).RequestedTheme;
         }
     }
 }
diff --git a/Screenbox/Helpers/TitleBarHelper.cs b/Screenbox/Helpers/TitleBarHelper.cs
new file mode 100644
index 000000000..74c0ecdb3
--- /dev/null
+++ b/Screenbox/Helpers/TitleBarHelper.cs
@@ -0,0 +1,91 @@
+﻿using Windows.UI;
+using Windows.UI.Xaml;
+
+namespace Screenbox.Helpers;
+
+/// <summary>
+/// A helper that provides methods to customize the title bar.
+/// </summary>
+public static class TitleBarHelper
+{
+    /// <summary>
+    /// Extends the client area to fill the entire view and hides the default title bar.
+    /// </summary>
+    //public static void ExtendViewIntoTitleBar()
+    //{
+    //    var coreTitleBar = Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().TitleBar;
+    //    if (coreTitleBar != null)
+    //    {
+    //        coreTitleBar.ExtendViewIntoTitleBar = true;
+    //    }
+    //}
+
+    /// <summary>
+    /// Sets the subtle fill colors to the background, and the text fill colors to the
+    /// foreground of the title bar buttons (system caption buttons).
+    /// </summary>
+    /// <remarks>
+    /// Call this method only when the view is extended into the title bar.
+    /// </remarks>
+    /// <param name="element">The element to retrieve the requested theme property.</param>
+    public static void SetCaptionButtonColors(FrameworkElement element)
+    {
+        var buttonBackgroundColor = Colors.Transparent;
+
+        var titleBar = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().TitleBar;
+        if (titleBar != null)
+        {
+            titleBar.ButtonBackgroundColor = buttonBackgroundColor;
+            titleBar.ButtonInactiveBackgroundColor = buttonBackgroundColor;
+
+            // Only the background colors respect the alpha channel, the foreground colors are flattened
+            // by layering them over the SolidBackgroundFillColorBase and its corresponding background color.
+            if (element.ActualTheme == ElementTheme.Dark)
+            {
+                titleBar.ButtonForegroundColor = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF); // TextFillColorPrimary
+
+                titleBar.ButtonHoverBackgroundColor = Color.FromArgb(0x0F, 0xFF, 0xFF, 0xFF); // SubtleFillColorSecondary
+                titleBar.ButtonHoverForegroundColor = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF); // TextFillColorPrimary
+
+                titleBar.ButtonPressedBackgroundColor = Color.FromArgb(0x0A, 0xFF, 0xFF, 0xFF); // SubtleFillColorTertiary
+                titleBar.ButtonPressedForegroundColor = Color.FromArgb(0xFF, 0xD1, 0xD1, 0xD1); // TextFillColorSecondary
+
+                titleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, 0x71, 0x71, 0x71); // TextFillColorTertiary
+            }
+            else
+            {
+                titleBar.ButtonForegroundColor = Color.FromArgb(0xFF, 0x1A, 0x1A, 0x1A); // TextFillColorPrimary
+
+                titleBar.ButtonHoverBackgroundColor = Color.FromArgb(0x09, 0x00, 0x00, 0x00); // SubtleFillColorSecondary
+                titleBar.ButtonHoverForegroundColor = Color.FromArgb(0xFF, 0x19, 0x19, 0x19); // TextFillColorPrimary
+
+                titleBar.ButtonPressedBackgroundColor = Color.FromArgb(0x06, 0x00, 0x00, 0x00); // SubtleFillColorTertiary
+                titleBar.ButtonPressedForegroundColor = Color.FromArgb(0xFF, 0x5D, 0x5D, 0x5D); // TextFillColorSecondary
+
+                titleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, 0x9B, 0x9B, 0x9B); // TextFillColorTertiary
+            }
+        }
+    }
+
+    /// <summary>
+    /// Resets the title bar buttons colors back to the default settings.
+    /// </summary>
+    //public static void ResetCaptionButtonColors()
+    //{
+    //    var titleBar = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().TitleBar;
+    //    if (titleBar != null)
+    //    {
+    //        titleBar.ButtonBackgroundColor = null;
+    //        titleBar.ButtonForegroundColor = null;
+
+    //        titleBar.ButtonHoverBackgroundColor = null;
+    //        titleBar.ButtonHoverForegroundColor = null;
+
+    //        titleBar.ButtonPressedBackgroundColor = null;
+    //        titleBar.ButtonPressedForegroundColor = null;
+
+    //        titleBar.ButtonInactiveBackgroundColor = null;
+    //        titleBar.ButtonInactiveForegroundColor = null;
+    //    }
+    //}
+}
diff --git a/Screenbox/Pages/MainPage.xaml.cs b/Screenbox/Pages/MainPage.xaml.cs
index 74e9a2fce..a8dbae963 100644
--- a/Screenbox/Pages/MainPage.xaml.cs
+++ b/Screenbox/Pages/MainPage.xaml.cs
@@ -51,7 +51,7 @@ public MainPage()
             // For example, when the app moves to a screen with a different DPI.
             coreTitleBar.LayoutMetricsChanged += CoreTitleBar_LayoutMetricsChanged;
 
-            //Register a handler for when the window changes focus
+            // Register a handler for when the window changes focus
             Window.Current.CoreWindow.Activated += CoreWindow_Activated;
 
             NotificationView.Translation = new Vector3(0, 0, 16);
@@ -134,10 +134,6 @@ public void NavigateContent(Type pageType, object? parameter)
         private void SetTitleBar()
         {
             Window.Current.SetTitleBar(TitleBarElement);
-            if (ApplicationView.GetForCurrentView()?.TitleBar is { } titleBar)
-            {
-                titleBar.ButtonForegroundColor = null;
-            }
         }
 
         private void MainPage_Loaded(object sender, RoutedEventArgs e)
@@ -152,13 +148,6 @@ private void MainPage_Loaded(object sender, RoutedEventArgs e)
                 NavView.SelectedItem = NavView.MenuItems[0];
                 _ = ViewModel.FetchLibraries();
             }
-
-            if (ApplicationView.GetForCurrentView()?.TitleBar is { } titleBar)
-            {
-                titleBar.ButtonBackgroundColor = Colors.Transparent;
-                titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
-                titleBar.InactiveBackgroundColor = Colors.Transparent;
-            }
         }
 
         private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
diff --git a/Screenbox/Pages/PlayerPage.xaml b/Screenbox/Pages/PlayerPage.xaml
index 816a98669..057978a00 100644
--- a/Screenbox/Pages/PlayerPage.xaml
+++ b/Screenbox/Pages/PlayerPage.xaml
@@ -641,7 +641,6 @@
             <VisualStateGroup x:Name="ContentStates">
                 <VisualState x:Name="Video">
                     <VisualState.Setters>
-                        <Setter Target="LayoutRoot.RequestedTheme" Value="Dark" />
                         <Setter Target="HeaderBackground.Opacity" Value="1" />
                         <!--<Setter Target="LivelyOptionsButton.Visibility" Value="Collapsed" />-->
                         <Setter Target="BackgroundElement.Visibility" Value="Collapsed" />
@@ -653,7 +652,6 @@
 
                 <VisualState x:Name="AudioOnly">
                     <VisualState.Setters>
-                        <Setter Target="LayoutRoot.RequestedTheme" Value="Default" />
                         <Setter Target="HeaderBackground.Opacity" Value="0" />
                         <Setter Target="BackgroundElement.Visibility" Value="Visible" />
                         <Setter Target="VideoView.Opacity" Value="0" />
@@ -703,7 +701,6 @@
 
                 <VisualState x:Name="AudioWithVisualizer">
                     <VisualState.Setters>
-                        <Setter Target="LayoutRoot.RequestedTheme" Value="Default" />
                         <Setter Target="HeaderBackground.Opacity" Value="1" />
                         <Setter Target="BackgroundElement.Visibility" Value="Collapsed" />
                         <Setter Target="LivelyWallpaperPlayer.Visibility" Value="Visible" />
@@ -716,9 +713,6 @@
                 <VisualStateGroup.Transitions>
                     <VisualTransition GeneratedDuration="0:0:0.5" To="Video">
                         <Storyboard>
-                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="RequestedTheme">
-                                <DiscreteObjectKeyFrame KeyTime="0" Value="Dark" />
-                            </ObjectAnimationUsingKeyFrames>
                             <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AlbumArtPanel" Storyboard.TargetProperty="Visibility">
                                 <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
                             </ObjectAnimationUsingKeyFrames>
@@ -741,9 +735,6 @@
 
                     <VisualTransition GeneratedDuration="0:0:0.24" To="AudioOnly">
                         <Storyboard>
-                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="RequestedTheme">
-                                <DiscreteObjectKeyFrame KeyTime="0" Value="Default" />
-                            </ObjectAnimationUsingKeyFrames>
                             <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AlbumArtPanel" Storyboard.TargetProperty="Visibility">
                                 <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                             </ObjectAnimationUsingKeyFrames>
@@ -760,9 +751,6 @@
 
                     <VisualTransition GeneratedDuration="0:0:0.24" To="AudioWithVisualizer">
                         <Storyboard>
-                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="RequestedTheme">
-                                <DiscreteObjectKeyFrame KeyTime="0" Value="Default" />
-                            </ObjectAnimationUsingKeyFrames>
                             <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AlbumArtPanel" Storyboard.TargetProperty="Visibility">
                                 <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
                             </ObjectAnimationUsingKeyFrames>
diff --git a/Screenbox/Pages/PlayerPage.xaml.cs b/Screenbox/Pages/PlayerPage.xaml.cs
index 7c1c57acc..4715a721e 100644
--- a/Screenbox/Pages/PlayerPage.xaml.cs
+++ b/Screenbox/Pages/PlayerPage.xaml.cs
@@ -10,12 +10,11 @@
 using Screenbox.Core.Enums;
 using Screenbox.Core.Services;
 using Screenbox.Core.ViewModels;
+using Screenbox.Helpers;
 using Windows.ApplicationModel.Core;
 using Windows.ApplicationModel.DataTransfer;
 using Windows.System;
-using Windows.UI;
 using Windows.UI.Core;
-using Windows.UI.ViewManagement;
 using Windows.UI.Xaml;
 using Windows.UI.Xaml.Controls;
 using Windows.UI.Xaml.Controls.Primitives;
@@ -124,7 +123,6 @@ protected override void OnKeyDown(KeyRoutedEventArgs e)
         private void SetTitleBar()
         {
             Window.Current.SetTitleBar(TitleBarDragRegion);
-            UpdateSystemCaptionButtonForeground();
         }
 
         private void AlbumArtImageOnSourceChanged(DependencyObject sender, DependencyProperty dp)
@@ -210,6 +208,7 @@ private void OnLayoutVisualStateChanged(object _, VisualStateChangedEventArgs ar
             bool collapsing = args.OldState?.Name == nameof(Normal) && args.NewState?.Name == nameof(MiniPlayer);
 
             if (expanding || collapsing) PlayerControls.FocusFirstButton();
+            UpdateRootTheme();
         }
 
         private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -247,7 +246,7 @@ private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs
                     break;
                 case nameof(PlayerPageViewModel.AudioOnly):
                     UpdateContentState();
-                    UpdateSystemCaptionButtonForeground();
+                    UpdateRootTheme();
                     UpdatePreviewType();
                     break;
                 case nameof(PlayerPageViewModel.PlayerVisibility):
@@ -269,6 +268,7 @@ private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs
                     }
 
                     UpdateContentState();
+                    UpdateRootTheme();
                     UpdatePreviewType();
                     UpdateMiniPlayerMargin();
                     break;
@@ -343,14 +343,6 @@ private async void PlayBackgroundArtChangeCrossFadeAnimation()
                 _animationCancellationTokenSource = null;
         }
 
-        private void UpdateSystemCaptionButtonForeground()
-        {
-            if (ApplicationView.GetForCurrentView()?.TitleBar is { } titleBar)
-            {
-                titleBar.ButtonForegroundColor = ViewModel.AudioOnly ? null : Colors.White;
-            }
-        }
-
         private void UpdateContentState()
         {
             var contentVisualStateName = ViewModel.AudioOnly
@@ -411,6 +403,14 @@ private void UpdateMiniPlayerMargin()
             }
         }
 
+        private void UpdateRootTheme()
+        {
+            LayoutRoot.RequestedTheme = !ViewModel.AudioOnly && ViewModel.PlayerVisibility == PlayerVisibilityState.Visible
+                ? ElementTheme.Dark
+                : ElementTheme.Default;
+            TitleBarHelper.SetCaptionButtonColors(LayoutRoot);
+        }
+
         private void PlayQueueFlyout_OnOpening(object sender, object e)
         {
             // Delay load PlaylistView until flyout is opening
diff --git a/Screenbox/Screenbox.csproj b/Screenbox/Screenbox.csproj
index 5b0d48655..2b0bf813a 100644
--- a/Screenbox/Screenbox.csproj
+++ b/Screenbox/Screenbox.csproj
@@ -237,6 +237,7 @@
     <Compile Include="Converters\SearchItemGlyphConverter.cs" />
     <Compile Include="Converters\ThicknessFilterConverter.cs" />
     <Compile Include="Converters\ToggleButtonCheckToRepeatModeConverter.cs" />
+    <Compile Include="Helpers\TitleBarHelper.cs" />
     <Compile Include="Pages\AlbumDetailsPage.xaml.cs">
       <DependentUpon>AlbumDetailsPage.xaml</DependentUpon>
     </Compile>


Reviews:
user: login: huynhsontung
state: COMMENTED
author_association: OWNER
submitted_at: 2025-02-28T03:03:06Z
user: login: United600
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T17:44:38Z
user: login: huynhsontung
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-14T08:21:14Z
user: login: copilot-pull-request-reviewer[bot]
body: 

Copilot reviewed 8 out of 10 changed files in this pull request and generated no comments.

<details>
<summary>Files not reviewed (2)</summary>

* **Screenbox.Core/Screenbox.Core.csproj**: Language not supported
* **Screenbox/Controls/PropertiesView.xaml**: Language not supported
</details>



state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T21:26:01Z

Review comments:
diff_hunk: @@ -54,6 +57,10 @@ public MainPage()
             //Register a handler for when the window changes focus
             Window.Current.CoreWindow.Activated += CoreWindow_Activated;
 
+            //Register a handler for when the theme mode changes
+            _themeListener = new ThemeListener();
+            _themeListener.ThemeChanged += ThemeListener_OnThemeChanged;
path: Screenbox/Pages/MainPage.xaml.cs
user: login: huynhsontung
body: There is an `ActualThemeChanged` event in the `FrameworkElement` class. I think this listener is a legacy code.

https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.frameworkelement.actualthemechanged?view=winrt-26100#windows-ui-xaml-frameworkelement-actualthemechanged
created_at: 2025-02-28T03:03:00Z
author_association: OWNER
diff_hunk: @@ -54,6 +57,10 @@ public MainPage()
             //Register a handler for when the window changes focus
             Window.Current.CoreWindow.Activated += CoreWindow_Activated;
 
+            //Register a handler for when the theme mode changes
+            _themeListener = new ThemeListener();
+            _themeListener.ThemeChanged += ThemeListener_OnThemeChanged;
path: Screenbox/Pages/MainPage.xaml.cs
user: login: United600
body: Thanks, didn't knew about it.
created_at: 2025-02-28T17:44:37Z
author_association: COLLABORATOR
diff_hunk: @@ -131,12 +134,55 @@ public void NavigateContent(Type pageType, object? parameter)
             ContentFrame.Navigate(pageType, parameter, new SuppressNavigationTransitionInfo());
         }
 
+        private void OnActualThemeChanged(FrameworkElement sender, object args)
+        {
+            UpdateSystemCaptionButton();
+        }
+
         private void SetTitleBar()
         {
             Window.Current.SetTitleBar(TitleBarElement);
             if (ApplicationView.GetForCurrentView()?.TitleBar is { } titleBar)
             {
+                // Restore colors upon returning to the page
                 titleBar.ButtonForegroundColor = null;
+                titleBar.ButtonHoverBackgroundColor = null;
+                titleBar.ButtonHoverForegroundColor = null;
+                titleBar.ButtonPressedBackgroundColor = null;
+                titleBar.ButtonPressedForegroundColor = null;
+                titleBar.ButtonInactiveForegroundColor = null;
+
+                UpdateSystemCaptionButton();
+            }
+        }
+
+        private void UpdateSystemCaptionButton()
+        {
+            var titleBar = ApplicationView.GetForCurrentView().TitleBar;
+            if (titleBar != null)
+            {
+                // Rest
+                var buttonBackgroundColor = (Color)Application.Current.Resources["CaptionButtonBackground"];
+                var buttonForegroundColor = (Color)Application.Current.Resources["CaptionButtonForeground"];
path: Screenbox/Pages/MainPage.xaml.cs
user: login: huynhsontung
body: Since the application theme never actually changes, you can't rely on application theme resources to get the color values for the active theme. If the system theme is Dark and the user changes the theme to Light in the app, these lines will still return values for Dark theme.
created_at: 2025-04-14T08:19:29Z
author_association: OWNER
diff_hunk: @@ -17,12 +17,49 @@
                     <ResourceDictionary.ThemeDictionaries>
                         <ResourceDictionary x:Key="Default">
                             <StaticResource x:Key="AccentFillColorCustomBrush" ResourceKey="SystemAccentColorLight2" />
+
+                            <!--  Caption button  -->
+                            <StaticResource x:Key="CaptionButtonBackground" ResourceKey="SubtleFillColorTransparent" />
+                            <StaticResource x:Key="CaptionButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
+                            <StaticResource x:Key="CaptionButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
+                            <!--  Foreground colors ignore the alpha channel, so we flattened them by layering them over the SolidBackgroundFillColorBase and its associated subtle color  -->
+                            <!--  TextFillColorPrimary  -->
+                            <Color x:Key="CaptionButtonForeground">#FFFFFF</Color>
+                            <!--  TextFillColorPrimary  -->
+                            <Color x:Key="CaptionButtonForegroundPointerOver">#FFFFFF</Color>
+                            <!--  TextFillColorSecondary  -->
+                            <Color x:Key="CaptionButtonForegroundPressed">#D1D1D1</Color>
+                            <!--  TextFillColorDisabled  -->
+                            <Color x:Key="CaptionButtonForegroundInactive">#717171</Color>
path: Screenbox/App.xaml
user: login: huynhsontung
body: There is no way to explicitly get a theme-specific value from a theme resource, so you may need to convert these into static resources with names specific to the Dark and Light themes.
created_at: 2025-04-14T08:21:09Z
author_association: OWNER

PR comments:
user: login: huynhsontung
created_at: 2025-02-23T23:35:46Z
body: Is this PR ready to merge, btw? I see there are incomplete tasks on the task list.
author_association: OWNER
user: login: United600
created_at: 2025-02-24T00:45:54Z
body: > Is this PR ready to merge, btw? I see there are incomplete tasks on the task list.

Not really. AFAIK it's not regressing anything, but there's room for improvement. Maybe moving the logic to `App.xaml.cs` to consolidate both the main page and player page implementation? Do we need some sort of a theme helper?
I also believe addressing the in-app theme change is imperative.
author_association: COLLABORATOR
user: login: huynhsontung
created_at: 2025-04-18T18:06:59Z
body: This PR is getting out of scope. Please keep the PR related to the caption button colors only.
author_association: OWNER
user: login: United600
created_at: 2025-04-18T18:54:25Z
body: > This PR is getting out of scope. Please keep the PR related to the caption button colors only.

Are you referring to changes in the content dialogs? During testing I noticed that it didn't followed the requested theme changes but you're right that it should be a separate PR.
author_association: COLLABORATOR
user: login: huynhsontung
created_at: 2025-04-18T20:56:57Z
body: I moved the player theme switching logic on the player page into code behind. The player page only switches to Dark theme active when the media is a video and the player is expanded. 
author_association: OWNER
user: login: United600
created_at: 2025-04-18T21:44:41Z
body: > I moved the player theme switching logic on the player page into code behind. The player page only switches to Dark theme active when the media is a video and the player is expanded.

Nice, I tried something similar but had issues with the transition between video and audio playback.
author_association: COLLABORATOR