Skip to content
Merged
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
143 changes: 141 additions & 2 deletions Ra3.BattleNet.Downloader/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
using System.Windows;
using System;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using Microsoft.Win32;

namespace Ra3.BattleNet.Downloader;

Expand All @@ -7,18 +15,34 @@ namespace Ra3.BattleNet.Downloader;
/// </summary>
public partial class MainWindow : Window
{
private const string PersonalizeRegistryKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
private const int DarkModeRegistryValue = 0; // 0 indicates dark mode is enabled (AppsUseLightTheme registry value is 0)
private static readonly Brush DarkBackgroundBrush = new SolidColorBrush(Color.FromRgb(0x19, 0x19, 0x19));
private static readonly Brush DarkForegroundBrush = Brushes.White;

public MainWindow()
{
InitializeComponent();
ApplySystemTheme();
ChangeLanguage(chinese: true);
}

protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
if (IsSystemInDarkMode())
{
TrySetDarkTitleBar();
}
}

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
await Download.BitTorrentDownload((ViewModel)DataContext);
}

private void ChineseCheckbox_Checked(object sender, RoutedEventArgs e) => ChangeLanguage(chinese: true);

private void EnglishCheckbox_Checked(object sender, RoutedEventArgs e) => ChangeLanguage(chinese: false);

private void ChangeLanguage(bool chinese)
Expand All @@ -35,4 +59,119 @@ private void Hyperlink_Click(object sender, RoutedEventArgs e)
{
Download.OpenAndLocateFile(Download.DownloadPath);
}
}

private void ApplySystemTheme()
{
if (!IsSystemInDarkMode())
{
return;
}

Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

Setting only the Background property of the ProgressBar to black will not provide proper dark mode styling. In dark mode, the ProgressBar's foreground (the filled portion) should remain visible against the black background. Consider setting the Foreground property of DownloadProgressBar to a light color or adjusting other styling properties to ensure the progress indicator remains visible in dark mode.

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +69
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

Setting only the window's Background and Foreground properties won't automatically apply dark mode styling to all child controls. The Hyperlink, TextBlocks, and RadioButtons will retain their default styling and may not be readable in dark mode. Consider applying dark theme colors to these controls as well, or use a comprehensive WPF theming solution.

Copilot uses AI. Check for mistakes.
try
{
Background = DarkBackgroundBrush;
Foreground = DarkForegroundBrush;
DownloadProgressBar.Background = DarkBackgroundBrush;
ChineseCheckbox.Foreground = DarkForegroundBrush;
EnglishCheckbox.Foreground = DarkForegroundBrush;
}
catch
{
// If dark mode application fails, just continue with default colors
}
}

private static bool IsSystemInDarkMode()
{
try
{
using var personalize = Registry.CurrentUser.OpenSubKey(PersonalizeRegistryKeyPath);
if (personalize is null)
{
return false;
}

var appsUseLightTheme = personalize.GetValue("AppsUseLightTheme");
return appsUseLightTheme is int value && value == DarkModeRegistryValue;
}
catch (Exception ex) when (ex is SecurityException
or UnauthorizedAccessException
or ArgumentException
or ObjectDisposedException
or IOException)
{
#if DEBUG
Debug.WriteLine($"Failed to read dark mode registry setting from {PersonalizeRegistryKeyPath}, falling back to light mode: {ex}");
#endif
return false;
}
}

// Enable dark title bar (non-client area) for Windows 10 1809+ when dark mode is active.
// Returns true if dark title bar was successfully applied, false otherwise.
private bool TrySetDarkTitleBar()
{
try
{
var handle = new WindowInteropHelper(this).Handle;
if (handle == IntPtr.Zero)
{
return false;
}

// Get real Windows build from registry (Environment.OSVersion.Build may return compatibility version)
int build = GetWindowsBuild();
if (build == -1)
{
return false;
}

// Detect Windows build: 17763 (1809) supports attribute 19, 18362+ (1903) supports 20
var attribute = build >= 18362 ? DWMWA_USE_IMMERSIVE_DARK_MODE : (build >= 17763 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_1903 : -1);
if (attribute == -1)
{
return false;
}

int useDark = 1;
int result = DwmSetWindowAttribute(handle, attribute, ref useDark, sizeof(int));

// S_OK = 0, anything else is failure
return result == 0;
}
catch
{
return false;
}
}

private static int GetWindowsBuild()
{
try
{
using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
if (key is null)
{
return -1;
}

var buildValue = key.GetValue("CurrentBuildNumber");
if (buildValue is string buildStr && int.TryParse(buildStr, out int build))
{
return build;
}

return -1;
}
catch
{
return -1;
}
}

private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
private const int DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_1903 = 19;

[DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, ref int pvAttribute, int cbAttribute);
}
Loading