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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Source/NETworkManager.Localization/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -3993,4 +3993,7 @@ Right-click for more options.</value>
<data name="CollapseAll" xml:space="preserve">
<value>Collapse all</value>
</data>
<data name="HelpMessage_UseCustomThemes" xml:space="preserve">
<value>Use custom themes to personalize the appearance of the application. You can edit or add theme in the "Program Folder &gt; Themes" directory. For more details, refer to the documentation.</value>
</data>
</root>
155 changes: 109 additions & 46 deletions Source/NETworkManager.Settings/AppearanceManager.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using ControlzEx.Theming;
using MahApps.Metro.Controls.Dialogs;
using MahApps.Metro.Theming;
using NETworkManager.Models.Appearance;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using ControlzEx.Theming;
using MahApps.Metro.Controls.Dialogs;
using MahApps.Metro.Theming;
using NETworkManager.Models.Appearance;

namespace NETworkManager.Settings;

Expand All @@ -16,6 +16,27 @@ namespace NETworkManager.Settings;
/// </summary>
public static class AppearanceManager
{
#region Variables
/// <summary>
/// Dictionary to override some brushes for the light theme.
/// </summary>
private static readonly ResourceDictionary LightThemeOverrideDictionary = new()
{
//["MahApps.Brushes.ThemeBackground"] = new SolidColorBrush(Color.FromRgb(248, 248, 255)),
//["MahApps.Brushes.Control.Background"] = new SolidColorBrush(Color.FromRgb(248, 248, 255)),
["MahApps.Brushes.Gray3"] = new SolidColorBrush(Color.FromRgb(104, 104, 104)),
["MahApps.Brushes.Gray5"] = new SolidColorBrush(Color.FromRgb(138, 138, 138)),
["MahApps.Brushes.Gray8"] = new SolidColorBrush(Color.FromRgb(190, 190, 190)),
};

/// <summary>
/// Dictionary to override some brushes for the dark theme.
/// </summary>
private static readonly ResourceDictionary DarkThemeOverrideDictionary = new()
{

};

/// <summary>
/// Name of the folder inside the application directory where the custom themes are stored.
/// </summary>
Expand All @@ -26,23 +47,40 @@ public static class AppearanceManager
/// </summary>
public static readonly MetroDialogSettings MetroDialog = new();

/// <summary>
/// List who contains all MahApps.Metro themes.
/// </summary>
public static List<ThemeColorInfo> Themes { get; set; }

/// <summary>
/// List who contains all MahApps.Metro custom themes.
/// </summary>
public static List<ThemeInfo> CustomThemes { get; private set; }

/// <summary>
/// List who contains all MahApps.Metro accents.
/// </summary>
public static List<AccentColorInfo> Accents { get; set; }
#endregion

#region Constructor
/// <summary>
/// Load the MahApps.Metro themes and accents when needed.
/// </summary>
static AppearanceManager()
{
Themes = ThemeManager.Current.Themes
Themes = [.. ThemeManager.Current.Themes
.GroupBy(x => x.BaseColorScheme)
.Select(x => x.First())
.Select(x => new ThemeColorInfo
{ Name = x.BaseColorScheme, Color = x.Resources["MahApps.Brushes.ThemeBackground"] as Brush })
.ToList();
{ Name = x.BaseColorScheme, Color = x.Resources["MahApps.Brushes.ThemeBackground"] as Brush })];

Accents = ThemeManager.Current.Themes
Accents = [.. ThemeManager.Current.Themes
.GroupBy(x => x.ColorScheme)
.OrderBy(x => x.Key)
.Select(x => new AccentColorInfo { Name = x.Key, Color = x.First().ShowcaseBrush })
.ToList();
.Select(x => new AccentColorInfo { Name = x.Key, Color = x.First().ShowcaseBrush })];

ThemeManager.Current.ThemeChanged += Current_ThemeChanged;

LoadCustomThemes();

Expand All @@ -55,22 +93,9 @@ static AppearanceManager()
MetroDialog.DialogButtonFontSize = 14;
MetroDialog.DialogMessageFontSize = 14;
}
#endregion

/// <summary>
/// List who contains all MahApps.Metro themes.
/// </summary>
public static List<ThemeColorInfo> Themes { get; set; }

/// <summary>
/// List who contains all MahApps.Metro custom themes.
/// </summary>
public static List<ThemeInfo> CustomThemes { get; private set; }

/// <summary>
/// List who contains all MahApps.Metro accents.
/// </summary>
public static List<AccentColorInfo> Accents { get; set; }

#region Methods
/// <summary>
/// Change the appearance based on the user settings. This method should be called once, when starting the application.
/// </summary>
Expand All @@ -79,22 +104,21 @@ public static void Load()
if (SettingsManager.Current.Appearance_UseCustomTheme && CustomThemes.Count > 0)
{
ChangeTheme(
CustomThemes.FirstOrDefault(x => x.Name == SettingsManager.Current.Appearance_CustomThemeName) ??
CustomThemes.First());
}
else
{
ChangeTheme(SettingsManager.Current.Appearance_Theme);
ChangeAccent(SettingsManager.Current.Appearance_Accent);
(CustomThemes.FirstOrDefault(x => x.Name == SettingsManager.Current.Appearance_CustomThemeName) ??
CustomThemes.First()).Name);

return;
}

ChangeTheme(SettingsManager.Current.Appearance_Theme, SettingsManager.Current.Appearance_Accent);
}

/// <summary>
/// Method to load the custom themes from a folder into the <see cref="ThemeManager" />.
/// </summary>
private static void LoadCustomThemes()
{
List<ThemeInfo> customThemes = new();
List<ThemeInfo> customThemes = [];

foreach (var file in Directory.GetFiles(Path.Combine(ConfigurationManager.Current.ExecutionPath,
ThemeFolderName)))
Expand All @@ -110,29 +134,68 @@ private static void LoadCustomThemes()
}

/// <summary>
/// Method to change the application theme.
/// Method to change the application theme (and accent).
/// </summary>
/// <param name="name">Name of the MahApps theme base color.</param>
/// <param name="name">Theme name as "theme.accent" to apply.</param>
public static void ChangeTheme(string name)
{
ThemeManager.Current.ChangeThemeBaseColor(System.Windows.Application.Current, name);
ThemeManager.Current.ChangeTheme(System.Windows.Application.Current, name);
}

/// <summary>
/// Method to change the application accent.
/// Method to change the application theme (and accent).
/// </summary>
/// <param name="name">Name of the MahApps theme accent color.</param>
public static void ChangeAccent(string name)
/// <param name="theme">Theme name to apply.</param>
/// <param name="accent">Accent name to apply.</param>
public static void ChangeTheme(string theme, string accent)
{
ThemeManager.Current.ChangeThemeColorScheme(System.Windows.Application.Current, name);
ChangeTheme($"{theme}.{accent}");
}

/// <summary>
/// Method to change the application theme based on the name in <see cref="ThemeInfo" />.
///
/// </summary>
/// <param name="themeInfo">Theme as <see cref="ThemeInfo" /> to apply.</param>
public static void ChangeTheme(ThemeInfo themeInfo)
/// <param name="theme"></param>
private static void ApplyCustomThemeFixes(string theme)
{
// Don't apply on custom themes (only built-in light/dark themes)
if (CustomThemes.Any(x => x.Name.Equals(theme, StringComparison.OrdinalIgnoreCase)))
return;

// Get application resources
var appResources = System.Windows.Application.Current.Resources;

// Remove any existing theme overrides
appResources.MergedDictionaries.Remove(LightThemeOverrideDictionary);
appResources.MergedDictionaries.Remove(DarkThemeOverrideDictionary);


// Theme name is in format "theme.accent"
switch (theme.ToLowerInvariant().Split('.')[0])
{
case "light":
appResources.MergedDictionaries.Add(LightThemeOverrideDictionary);
break;

case "dark":
appResources.MergedDictionaries.Add(DarkThemeOverrideDictionary);
break;
}

// Refresh UI
foreach (Window window in System.Windows.Application.Current.Windows)
{
if (window.IsLoaded)
window.InvalidateVisual();
}
}

#endregion

#region Events
private static void Current_ThemeChanged(object sender, ThemeChangedEventArgs e)
{
ThemeManager.Current.ChangeTheme(System.Windows.Application.Current, themeInfo.Name);
ApplyCustomThemeFixes(e.NewTheme.Name);
}
}
#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<Style x:Key="HeaderTextBlock" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource DefaultTextBlock}">
<Setter Property="FontFamily" Value="{StaticResource MahApps.Fonts.Family.Header}" />
<Setter Property="Foreground" Value="{StaticResource MahApps.Brushes.Gray5}" />
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.Gray5}" />
<Setter Property="FontSize" Value="18" />
<Setter Property="Margin" Value="0,0,0,10" />
</Style>
Expand Down
13 changes: 6 additions & 7 deletions Source/NETworkManager/ViewModels/SettingsAppearanceViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.ComponentModel;
using NETworkManager.Models.Appearance;
using NETworkManager.Settings;
using System.ComponentModel;
using System.Linq;
using System.Windows.Data;
using NETworkManager.Models.Appearance;
using NETworkManager.Settings;

namespace NETworkManager.ViewModels;

Expand All @@ -26,7 +26,7 @@ public ThemeColorInfo SelectedTheme

if (!_isLoading && !UseCustomTheme)
{
AppearanceManager.ChangeTheme(value.Name);
AppearanceManager.ChangeTheme(value.Name, SelectedAccent.Name);
SettingsManager.Current.Appearance_Theme = value.Name;
}

Expand All @@ -35,7 +35,6 @@ public ThemeColorInfo SelectedTheme
}
}


public ICollectionView Accents { get; }

private AccentColorInfo _selectedAccent;
Expand All @@ -50,7 +49,7 @@ public AccentColorInfo SelectedAccent

if (!_isLoading && !UseCustomTheme)
{
AppearanceManager.ChangeAccent(value.Name);
AppearanceManager.ChangeTheme(SelectedTheme.Name, value.Name);
SettingsManager.Current.Appearance_Accent = value.Name;
}

Expand Down Expand Up @@ -95,7 +94,7 @@ public ThemeInfo SelectedCustomTheme

if (!_isLoading && UseCustomTheme)
{
AppearanceManager.ChangeTheme(value);
AppearanceManager.ChangeTheme(value.Name);
SettingsManager.Current.Appearance_CustomThemeName = value.Name;
}

Expand Down
Loading