[GUI] Add dark theme (#388)

pull/403/head
Andrew Kolos 4 years ago committed by GitHub
parent 08442f21b7
commit 19f678ca01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,69 +14,13 @@
<!-- Merged dictionaries --> <!-- Merged dictionaries -->
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" /> <materialDesign:BundledTheme
BaseTheme="Light"
PrimaryColor="Blue"
SecondaryColor="Blue" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<!-- Colors -->
<Color x:Key="PrimaryColor">#343838</Color>
<Color x:Key="PrimaryLightColor">#5E6262</Color>
<Color x:Key="PrimaryDarkColor">#0D1212</Color>
<Color x:Key="AccentColor">#F9A825</Color>
<Color x:Key="AccentDarkColor">#C17900</Color>
<Color x:Key="TextColor">#000000</Color>
<Color x:Key="InverseTextColor">#FFFFFF</Color>
<SolidColorBrush x:Key="PrimaryHueLightBrush" Color="{DynamicResource PrimaryLightColor}" />
<SolidColorBrush x:Key="PrimaryHueLightForegroundBrush" Color="{DynamicResource InverseTextColor}" />
<SolidColorBrush x:Key="PrimaryHueMidBrush" Color="{DynamicResource PrimaryColor}" />
<SolidColorBrush x:Key="PrimaryHueMidForegroundBrush" Color="{DynamicResource InverseTextColor}" />
<SolidColorBrush x:Key="PrimaryHueDarkBrush" Color="{DynamicResource PrimaryDarkColor}" />
<SolidColorBrush x:Key="PrimaryHueDarkForegroundBrush" Color="{DynamicResource InverseTextColor}" />
<SolidColorBrush x:Key="SecondaryAccentBrush" Color="{DynamicResource AccentColor}" />
<SolidColorBrush x:Key="SecondaryAccentForegroundBrush" Color="{DynamicResource TextColor}" />
<SolidColorBrush
x:Key="PrimaryTextBrush"
Opacity="0.87"
Color="{DynamicResource TextColor}" />
<SolidColorBrush
x:Key="SecondaryTextBrush"
Opacity="0.64"
Color="{DynamicResource TextColor}" />
<SolidColorBrush
x:Key="DimTextBrush"
Opacity="0.45"
Color="{DynamicResource TextColor}" />
<SolidColorBrush
x:Key="PrimaryInverseTextBrush"
Opacity="1"
Color="{DynamicResource InverseTextColor}" />
<SolidColorBrush
x:Key="SecondaryInverseTextBrush"
Opacity="0.7"
Color="{DynamicResource InverseTextColor}" />
<SolidColorBrush
x:Key="DimInverseTextBrush"
Opacity="0.52"
Color="{DynamicResource InverseTextColor}" />
<SolidColorBrush
x:Key="AccentTextBrush"
Opacity="1"
Color="{DynamicResource AccentColor}" />
<SolidColorBrush
x:Key="AccentDarkTextBrush"
Opacity="1"
Color="{DynamicResource AccentDarkColor}" />
<SolidColorBrush
x:Key="DividerBrush"
Opacity="0.12"
Color="{DynamicResource TextColor}" />
<SolidColorBrush
x:Key="InverseDividerBrush"
Opacity="0.12"
Color="{DynamicResource InverseTextColor}" />
<!-- Styles --> <!-- Styles -->
<Style x:Key="MaterialDesignRoot" TargetType="{x:Type Control}"> <Style x:Key="MaterialDesignRoot" TargetType="{x:Type Control}">
<Setter Property="FontFamily" Value="{DynamicResource MaterialDesignFont}" /> <Setter Property="FontFamily" Value="{DynamicResource MaterialDesignFont}" />
@ -84,7 +28,7 @@
<Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="TextElement.FontSize" Value="13" /> <Setter Property="TextElement.FontSize" Value="13" />
<Setter Property="TextElement.FontWeight" Value="Regular" /> <Setter Property="TextElement.FontWeight" Value="Regular" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SecondaryTextBrush}" /> <Setter Property="TextElement.Foreground" Value="{DynamicResource MaterialDesignBody}" />
<Setter Property="TextOptions.TextFormattingMode" Value="Ideal" /> <Setter Property="TextOptions.TextFormattingMode" Value="Ideal" />
<Setter Property="TextOptions.TextRenderingMode" Value="Auto" /> <Setter Property="TextOptions.TextRenderingMode" Value="Auto" />
<Setter Property="UseLayoutRounding" Value="True" /> <Setter Property="UseLayoutRounding" Value="True" />
@ -94,27 +38,20 @@
<Style BasedOn="{StaticResource MaterialDesignLinearProgressBar}" TargetType="{x:Type ProgressBar}"> <Style BasedOn="{StaticResource MaterialDesignLinearProgressBar}" TargetType="{x:Type ProgressBar}">
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource SecondaryAccentBrush}" /> <Setter Property="Foreground" Value="{DynamicResource SecondaryAccentBrush}" />
<Setter Property="Height" Value="2" /> <Setter Property="Height" Value="2" />
<Setter Property="Maximum" Value="1" /> <Setter Property="Maximum" Value="1" />
<Setter Property="Minimum" Value="0" /> <Setter Property="Minimum" Value="0" />
</Style> </Style>
<Style BasedOn="{StaticResource MaterialDesignTextBox}" TargetType="{x:Type TextBox}"> <Style BasedOn="{StaticResource MaterialDesignTextBox}" TargetType="{x:Type TextBox}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignComboBox}" TargetType="{x:Type ComboBox}"> <Style BasedOn="{StaticResource MaterialDesignComboBox}" TargetType="{x:Type ComboBox}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignDatePicker}" TargetType="{x:Type DatePicker}"> <Style BasedOn="{StaticResource MaterialDesignDatePicker}" TargetType="{x:Type DatePicker}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignTimePicker}" TargetType="{x:Type materialDesign:TimePicker}"> <Style BasedOn="{StaticResource MaterialDesignTimePicker}" TargetType="{x:Type materialDesign:TimePicker}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Style>
<Style <Style
x:Key="MaterialDesignFlatDarkButton" x:Key="MaterialDesignFlatDarkButton"

@ -12,6 +12,8 @@ namespace DiscordChatExporter.Gui.Services
public bool IsTokenPersisted { get; set; } = true; public bool IsTokenPersisted { get; set; } = true;
public bool IsDarkThemeEnabled { get; set; } = false;
public int ParallelLimit { get; set; } = 1; public int ParallelLimit { get; set; } = 1;
public AuthToken? LastToken { get; set; } public AuthToken? LastToken { get; set; }

@ -0,0 +1,42 @@
using MaterialDesignThemes.Wpf;
using System.Windows.Media;
namespace DiscordChatExporter.Gui
{
public sealed class Theme
{
public static Theme Light { get; } = new Theme(new MaterialDesignLightTheme(), HexToColor.Convert("#343838"), HexToColor.Convert("#F9A825"));
public static Theme Dark { get; } = new Theme(new MaterialDesignDarkTheme(), HexToColor.Convert("#E8E8E8"), HexToColor.Convert("#F9A825"));
public static void SetCurrent(Theme theme)
{
var paletteHelper = new PaletteHelper();
var materialTheme = paletteHelper.GetTheme();
materialTheme.SetBaseTheme(theme.BaseTheme);
materialTheme.SetPrimaryColor(theme.PrimaryColor);
materialTheme.SetSecondaryColor(theme.SecondaryColor);
paletteHelper.SetTheme(materialTheme);
}
public Theme(IBaseTheme baseTheme, Color primaryColor, Color secondaryColor)
{
BaseTheme = baseTheme;
PrimaryColor = primaryColor;
SecondaryColor = secondaryColor;
}
public IBaseTheme BaseTheme { get; }
public Color PrimaryColor { get; }
public Color SecondaryColor { get; }
class HexToColor
{
public static Color Convert(string hex)
{
return (Color)ColorConverter.ConvertFromString(hex);
}
}
}
}

@ -26,6 +26,12 @@ namespace DiscordChatExporter.Gui.ViewModels.Dialogs
set => _settingsService.IsTokenPersisted = value; set => _settingsService.IsTokenPersisted = value;
} }
public bool IsDarkThemeEnabled
{
get => _settingsService.IsDarkThemeEnabled;
set => _settingsService.IsDarkThemeEnabled = value;
}
public int ParallelLimit public int ParallelLimit
{ {
get => _settingsService.ParallelLimit; get => _settingsService.ParallelLimit;

@ -108,6 +108,8 @@ namespace DiscordChatExporter.Gui.ViewModels
TokenValue = _settingsService.LastToken.Value; TokenValue = _settingsService.LastToken.Value;
} }
Theme.SetCurrent(_settingsService.IsDarkThemeEnabled ? Theme.Dark : Theme.Light);
await HandleAutoUpdateAsync(); await HandleAutoUpdateAsync();
} }

@ -48,12 +48,13 @@
Margin="8,0,0,0" Margin="8,0,0,0"
VerticalAlignment="Center" VerticalAlignment="Center"
FontSize="19" FontSize="19"
FontWeight="Light"
TextTrimming="CharacterEllipsis" TextTrimming="CharacterEllipsis"
Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"> Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<Run Text="{Binding Channels[0].Category, Mode=OneWay}" ToolTip="{Binding Channels[0].Category, Mode=OneWay}" /> <Run Text="{Binding Channels[0].Category, Mode=OneWay}" ToolTip="{Binding Channels[0].Category, Mode=OneWay}" />
<Run Text="/" /> <Run Text="/" />
<Run <Run
Foreground="{DynamicResource PrimaryTextBrush}" FontWeight="DemiBold"
Text="{Binding Channels[0].Name, Mode=OneWay}" Text="{Binding Channels[0].Name, Mode=OneWay}"
ToolTip="{Binding Channels[0].Name, Mode=OneWay}" /> ToolTip="{Binding Channels[0].Name, Mode=OneWay}" />
</TextBlock> </TextBlock>
@ -163,18 +164,13 @@
<ToggleButton <ToggleButton
x:Name="AdvancedSectionToggleButton" x:Name="AdvancedSectionToggleButton"
Grid.Column="0" Grid.Column="0"
Margin="8"
Cursor="Hand"
Loaded="AdvancedSectionToggleButton_OnLoaded"
Style="{DynamicResource MaterialDesignFlatToggleButton}"
ToolTip="Show advanced options">
<ToggleButton.Content>
<materialDesign:PackIcon
Width="24" Width="24"
Height="24" Height="24"
Kind="Menu" /> Margin="12"
</ToggleButton.Content> Cursor="Hand"
</ToggleButton> Loaded="AdvancedSectionToggleButton_OnLoaded"
Style="{DynamicResource MaterialDesignHamburgerToggleButton}"
ToolTip="Show advanced options" />
<Button <Button
Grid.Column="2" Grid.Column="2"

@ -15,7 +15,6 @@
<TextBlock <TextBlock
Margin="16" Margin="16"
FontSize="17" FontSize="17"
Foreground="{DynamicResource PrimaryTextBrush}"
Text="Settings" /> Text="Settings" />
<!-- Date format --> <!-- Date format -->
@ -56,11 +55,28 @@
IsChecked="{Binding IsTokenPersisted}" /> IsChecked="{Binding IsTokenPersisted}" />
</DockPanel> </DockPanel>
<!-- Dark/Light theme -->
<DockPanel
Background="Transparent"
LastChildFill="False"
ToolTip="Persist last used token between sessions">
<TextBlock
Margin="16,8"
DockPanel.Dock="Left"
Text="Dark theme" />
<ToggleButton
Margin="16,8"
Checked="ToggleButton_Checked"
DockPanel.Dock="Right"
IsChecked="{Binding IsDarkThemeEnabled}"
Unchecked="ToggleButton_Unchecked" />
</DockPanel>
<!-- Parallel limit --> <!-- Parallel limit -->
<StackPanel Background="Transparent" ToolTip="How many channels can be exported at the same time"> <StackPanel Background="Transparent" ToolTip="How many channels can be exported at the same time">
<TextBlock Margin="16,8"> <TextBlock Margin="16,8">
<Run Text="Parallel limit:" /> <Run Text="Parallel limit:" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="{Binding ParallelLimit, Mode=OneWay}" /> <Run Text="{Binding ParallelLimit, Mode=OneWay}" />
</TextBlock> </TextBlock>
<Slider <Slider
Margin="16,8" Margin="16,8"

@ -1,4 +1,8 @@
namespace DiscordChatExporter.Gui.Views.Dialogs using MaterialDesignThemes;
using MaterialDesignThemes.Wpf;
using System.Windows.Media.Media3D;
namespace DiscordChatExporter.Gui.Views.Dialogs
{ {
public partial class SettingsView public partial class SettingsView
{ {
@ -6,5 +10,20 @@
{ {
InitializeComponent(); InitializeComponent();
} }
private void ToggleButton_Checked(object sender, System.Windows.RoutedEventArgs e)
{
setBaseTheme(Theme.Dark);
}
private void ToggleButton_Unchecked(object sender, System.Windows.RoutedEventArgs e)
{
setBaseTheme(Theme.Light);
}
private void setBaseTheme(Theme theme)
{
Theme.SetCurrent(theme);
}
} }
} }

@ -46,10 +46,7 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Toolbar --> <!-- Toolbar -->
<Grid <Grid Grid.Row="0" Background="{DynamicResource MaterialDesignDarkBackground}">
Grid.Row="0"
Background="{DynamicResource PrimaryHueMidBrush}"
TextElement.Foreground="{DynamicResource SecondaryInverseTextBrush}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@ -124,8 +121,12 @@
Margin="6" Margin="6"
Padding="4" Padding="4"
Command="{s:Action ShowSettings}" Command="{s:Action ShowSettings}"
Style="{DynamicResource MaterialDesignFlatDarkButton}" Foreground="{DynamicResource MaterialDesignDarkForeground}"
Style="{DynamicResource MaterialDesignFlatButton}"
ToolTip="Settings"> ToolTip="Settings">
<Button.Resources>
<SolidColorBrush x:Key="MaterialDesignFlatButtonClick" Color="#4C4C4C" />
</Button.Resources>
<materialDesign:PackIcon <materialDesign:PackIcon
Width="24" Width="24"
Height="24" Height="24"
@ -136,12 +137,17 @@
<!-- Progress bar --> <!-- Progress bar -->
<ProgressBar <ProgressBar
Grid.Row="1" Grid.Row="1"
Background="{DynamicResource PrimaryHueMidBrush}" Background="{DynamicResource MaterialDesignDarkBackground}"
IsIndeterminate="{Binding IsProgressIndeterminate}" IsIndeterminate="{Binding IsProgressIndeterminate}"
Value="{Binding ProgressManager.Progress, Mode=OneWay}" /> Value="{Binding ProgressManager.Progress, Mode=OneWay}" />
<!-- Content --> <!-- Content -->
<Grid Grid.Row="2" IsEnabled="{Binding IsBusy, Converter={x:Static converters:InverseBoolConverter.Instance}}"> <Grid Grid.Row="2" IsEnabled="{Binding IsBusy, Converter={x:Static converters:InverseBoolConverter.Instance}}">
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontWeight" Value="Light" />
</Style>
</Grid.Resources>
<!-- Placeholder / usage instructions --> <!-- Placeholder / usage instructions -->
<Grid Margin="32,32,8,8" Visibility="{Binding AvailableGuilds, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}"> <Grid Margin="32,32,8,8" Visibility="{Binding AvailableGuilds, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}">
<!-- For user token --> <!-- For user token -->
@ -151,25 +157,25 @@
<Run Text="1. Open Discord" /> <Run Text="1. Open Discord" />
<LineBreak /> <LineBreak />
<Run Text="2. Press" /> <Run Text="2. Press" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="Ctrl+Shift+I" /> <Run FontWeight="Bold" Text="Ctrl+Shift+I" />
<Run Text="to show developer tools" /> <Run Text="to show developer tools" />
<LineBreak /> <LineBreak />
<Run Text="3. Navigate to the" /> <Run Text="3. Navigate to the" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="Application" /> <Run FontWeight="Bold" Text="Application" />
<Run Text="tab" /> <Run Text="tab" />
<LineBreak /> <LineBreak />
<Run Text="4. Select" /> <Run Text="4. Select" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="Local Storage" /> <Run FontWeight="Bold" Text="Local Storage" />
<Run Text="&gt;" /> <Run Text="&gt;" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="https://discord.com" /> <Run FontWeight="Bold" Text="https://discord.com" />
<Run Text="on the left" /> <Run Text="on the left" />
<LineBreak /> <LineBreak />
<Run Text="5. Press" /> <Run Text="5. Press" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="Ctrl+R" /> <Run FontWeight="Bold" Text="Ctrl+R" />
<Run Text="to reload" /> <Run Text="to reload" />
<LineBreak /> <LineBreak />
<Run Text="6. Find" /> <Run Text="6. Find" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="token" /> <Run FontWeight="Bold" Text="token" />
<Run Text="at the bottom and copy the value" /> <Run Text="at the bottom and copy the value" />
</TextBlock> </TextBlock>
<TextBlock Margin="0,24,0,0" FontSize="14"> <TextBlock Margin="0,24,0,0" FontSize="14">
@ -177,7 +183,10 @@
<LineBreak /> <LineBreak />
<Run Text="To authorize using bot token instead, click" /> <Run Text="To authorize using bot token instead, click" />
<InlineUIContainer> <InlineUIContainer>
<materialDesign:PackIcon Margin="1,0,0,-3" Kind="Account" /> <materialDesign:PackIcon
Margin="1,0,0,-3"
Foreground="{DynamicResource PrimaryHueMidBrush}"
Kind="Account" />
</InlineUIContainer> </InlineUIContainer>
</TextBlock> </TextBlock>
<TextBlock Margin="0,24,0,0" FontSize="14"> <TextBlock Margin="0,24,0,0" FontSize="14">
@ -188,25 +197,34 @@
<!-- For bot token --> <!-- For bot token -->
<StackPanel Visibility="{Binding IsBotToken, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"> <StackPanel Visibility="{Binding IsBotToken, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<TextBlock FontSize="18" Text="Please provide your bot token to authorize" /> <TextBlock
<TextBlock Margin="8,8,0,0" FontSize="14"> FontSize="18"
FontWeight="Light"
Text="Please provide your bot token to authorize" />
<TextBlock
Margin="8,8,0,0"
FontSize="14"
FontWeight="Light">
<Run Text="1. Open Discord developer portal" /> <Run Text="1. Open Discord developer portal" />
<LineBreak /> <LineBreak />
<Run Text="2. Open your application's settings" /> <Run Text="2. Open your application's settings" />
<LineBreak /> <LineBreak />
<Run Text="3. Navigate to the" /> <Run Text="3. Navigate to the" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="Bot" /> <Run FontWeight="Bold" Text="Bot" />
<Run Text="section on the left" /> <Run Text="section on the left" />
<LineBreak /> <LineBreak />
<Run Text="4. Under" /> <Run Text="4. Under" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="Token" /> <Run FontWeight="Bold" Text="Token" />
<Run Text="click" /> <Run Text="click" />
<Run Foreground="{DynamicResource PrimaryTextBrush}" Text="Copy" /> <Run FontWeight="Bold" Text="Copy" />
</TextBlock> </TextBlock>
<TextBlock Margin="0,24,0,0" FontSize="14"> <TextBlock Margin="0,24,0,0" FontSize="14">
<Run Text="To authorize using user token instead, click" /> <Run Text="To authorize using user token instead, click" />
<InlineUIContainer> <InlineUIContainer>
<materialDesign:PackIcon Margin="1,0,0,-1" Kind="Robot" /> <materialDesign:PackIcon
Margin="1,0,0,-1"
Foreground="{DynamicResource PrimaryHueMidBrush}"
Kind="Robot" />
</InlineUIContainer> </InlineUIContainer>
</TextBlock> </TextBlock>
<TextBlock Margin="0,24,0,0" FontSize="14"> <TextBlock Margin="0,24,0,0" FontSize="14">
@ -226,7 +244,7 @@
<!-- Guilds --> <!-- Guilds -->
<Border <Border
Grid.Column="0" Grid.Column="0"
BorderBrush="{DynamicResource DividerBrush}" BorderBrush="{DynamicResource MaterialDesignDivider}"
BorderThickness="0,0,1,0"> BorderThickness="0,0,1,0">
<ListBox <ListBox
ItemsSource="{Binding AvailableGuilds}" ItemsSource="{Binding AvailableGuilds}"
@ -245,7 +263,7 @@
Width="48" Width="48"
Height="48" Height="48"
Margin="12,4,12,4" Margin="12,4,12,4"
Fill="{DynamicResource DividerBrush}" /> Fill="{DynamicResource MaterialDesignDivider}" />
<!-- Guild icon --> <!-- Guild icon -->
<Ellipse <Ellipse
@ -284,7 +302,7 @@
Margin="0" Margin="0"
Padding="0" Padding="0"
Background="Transparent" Background="Transparent"
BorderBrush="{DynamicResource DividerBrush}" BorderBrush="{DynamicResource MaterialDesignDivider}"
BorderThickness="0,1,0,0" BorderThickness="0,1,0,0"
Header="{Binding Name}" Header="{Binding Name}"
IsExpanded="False"> IsExpanded="False">
@ -322,7 +340,6 @@
Margin="3,8,8,8" Margin="3,8,8,8"
VerticalAlignment="Center" VerticalAlignment="Center"
FontSize="14" FontSize="14"
Foreground="{DynamicResource PrimaryTextBrush}"
Text="{Binding Name, Mode=OneWay}" /> Text="{Binding Name, Mode=OneWay}" />
<!-- Is selected checkmark --> <!-- Is selected checkmark -->

Loading…
Cancel
Save