Add a dark theme option to the GUI
This commit is contained in:
parent
da40f3d0c5
commit
b6872a2b9e
7
OF DL.Core/Enumerations/Theme.cs
Normal file
7
OF DL.Core/Enumerations/Theme.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace OF_DL.Enumerations;
|
||||
|
||||
public enum Theme
|
||||
{
|
||||
light,
|
||||
dark
|
||||
}
|
||||
@ -89,6 +89,9 @@ public class Config : IFileNameFormatConfig
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public LoggingLevel LoggingLevel { get; set; } = LoggingLevel.Error;
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public Theme Theme { get; set; } = Theme.light;
|
||||
|
||||
[ToggleableConfig] public bool IgnoreOwnMessages { get; set; }
|
||||
|
||||
[ToggleableConfig] public bool DisableBrowserAuth { get; set; }
|
||||
|
||||
@ -236,6 +236,9 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
|
||||
LimitDownloadRate = hoconConfig.GetBoolean("Performance.LimitDownloadRate"),
|
||||
DownloadLimitInMbPerSec = hoconConfig.GetInt("Performance.DownloadLimitInMbPerSec"),
|
||||
|
||||
// Appearance Settings
|
||||
Theme = ParseTheme(hoconConfig.GetString("Appearance.Theme", "light")),
|
||||
|
||||
// Logging/Debug Settings
|
||||
LoggingLevel = Enum.Parse<LoggingLevel>(hoconConfig.GetString("Logging.LoggingLevel"), true)
|
||||
};
|
||||
@ -407,6 +410,11 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
|
||||
hocon.AppendLine($" DownloadLimitInMbPerSec = {config.DownloadLimitInMbPerSec}");
|
||||
hocon.AppendLine("}");
|
||||
|
||||
hocon.AppendLine("# Appearance Settings");
|
||||
hocon.AppendLine("Appearance {");
|
||||
hocon.AppendLine($" Theme = \"{config.Theme.ToString().ToLower()}\"");
|
||||
hocon.AppendLine("}");
|
||||
|
||||
hocon.AppendLine("# Logging/Debug Settings");
|
||||
hocon.AppendLine("Logging {");
|
||||
hocon.AppendLine($" LoggingLevel = \"{config.LoggingLevel.ToString().ToLower()}\"");
|
||||
@ -500,6 +508,16 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
|
||||
return Enum.Parse<VideoResolution>("_" + value, true);
|
||||
}
|
||||
|
||||
private static Theme ParseTheme(string value)
|
||||
{
|
||||
if (Enum.TryParse(value, true, out Theme theme))
|
||||
{
|
||||
return theme;
|
||||
}
|
||||
|
||||
return Theme.light;
|
||||
}
|
||||
|
||||
private static double ParseDrmVideoDurationMatchThreshold(string value) =>
|
||||
!double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out double parsed)
|
||||
? 0.98
|
||||
|
||||
@ -3,6 +3,32 @@
|
||||
xmlns:fluent="clr-namespace:Avalonia.Themes.Fluent;assembly=Avalonia.Themes.Fluent"
|
||||
RequestedThemeVariant="Light"
|
||||
x:Class="OF_DL.Gui.App">
|
||||
<Application.Resources>
|
||||
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#EEF3FB" />
|
||||
<SolidColorBrush x:Key="SurfaceBackgroundBrush" Color="#FFFFFF" />
|
||||
<SolidColorBrush x:Key="SurfaceBorderBrush" Color="#DDE5F3" />
|
||||
<SolidColorBrush x:Key="PrimaryButtonBackgroundBrush" Color="#2E6EEA" />
|
||||
<SolidColorBrush x:Key="PrimaryButtonForegroundBrush" Color="#FFFFFF" />
|
||||
<SolidColorBrush x:Key="SecondaryButtonBackgroundBrush" Color="#FFFFFF" />
|
||||
<SolidColorBrush x:Key="SecondaryButtonForegroundBrush" Color="#1F2A44" />
|
||||
<SolidColorBrush x:Key="SecondaryButtonBorderBrush" Color="#CFD9EB" />
|
||||
<SolidColorBrush x:Key="TopBarBackgroundBrush" Color="#DDEAFF" />
|
||||
<SolidColorBrush x:Key="TopBarBorderBrush" Color="#CFD9EB" />
|
||||
<SolidColorBrush x:Key="TopBarTextBrush" Color="#304261" />
|
||||
<SolidColorBrush x:Key="TextPrimaryBrush" Color="#1F2A44" />
|
||||
<SolidColorBrush x:Key="TextSecondaryBrush" Color="#4A5B78" />
|
||||
<SolidColorBrush x:Key="HelpBadgeBackgroundBrush" Color="#EAF0FB" />
|
||||
<SolidColorBrush x:Key="HelpBadgeBorderBrush" Color="#C5D4EC" />
|
||||
<SolidColorBrush x:Key="ErrorTextBrush" Color="#FF5A5A" />
|
||||
<SolidColorBrush x:Key="PreviewBackgroundBrush" Color="#F5F8FE" />
|
||||
<SolidColorBrush x:Key="PreviewBorderBrush" Color="#D8E3F4" />
|
||||
<SolidColorBrush x:Key="DangerSoftBackgroundBrush" Color="#FFE8E8" />
|
||||
<SolidColorBrush x:Key="DangerSoftBorderBrush" Color="#E8C5C5" />
|
||||
<SolidColorBrush x:Key="DangerButtonBackgroundBrush" Color="#D84E4E" />
|
||||
<SolidColorBrush x:Key="OverlayBackgroundBrush" Color="#80000000" />
|
||||
<SolidColorBrush x:Key="ModalBackgroundBrush" Color="#FFFFFF" />
|
||||
<SolidColorBrush x:Key="ModalBorderBrush" Color="#DDE5F3" />
|
||||
</Application.Resources>
|
||||
<Application.Styles>
|
||||
<fluent:FluentTheme />
|
||||
</Application.Styles>
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using Avalonia;
|
||||
using Avalonia.Styling;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Newtonsoft.Json;
|
||||
@ -41,7 +43,9 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
||||
{
|
||||
["_240"] = "240p",
|
||||
["_720"] = "720p",
|
||||
["source"] = "Source Resolution"
|
||||
["source"] = "Source Resolution",
|
||||
["light"] = "Light",
|
||||
["dark"] = "Dark"
|
||||
};
|
||||
|
||||
public ConfigFieldViewModel(
|
||||
@ -470,6 +474,7 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
||||
|
||||
HashSet<string> allowedVariables = new(GetAllowedFileNameVariables(), StringComparer.OrdinalIgnoreCase);
|
||||
HashSet<string> unknownVariables = new(StringComparer.OrdinalIgnoreCase);
|
||||
(string PlainTextColor, string AllowedVariableColor, string InvalidVariableColor) = GetFileNamePreviewColors();
|
||||
|
||||
MatchCollection matches = s_fileNameVariableRegex.Matches(TextValue);
|
||||
int currentIndex = 0;
|
||||
@ -478,13 +483,13 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
||||
if (match.Index > currentIndex)
|
||||
{
|
||||
string plainText = TextValue[currentIndex..match.Index];
|
||||
FileNameFormatSegments.Add(new FileNameFormatSegmentViewModel(plainText, "#1F2A44"));
|
||||
FileNameFormatSegments.Add(new FileNameFormatSegmentViewModel(plainText, PlainTextColor));
|
||||
}
|
||||
|
||||
string variableName = match.Groups[1].Value;
|
||||
bool isAllowedVariable = allowedVariables.Contains(variableName);
|
||||
FileNameFormatSegments.Add(new FileNameFormatSegmentViewModel(match.Value,
|
||||
isAllowedVariable ? "#2E6EEA" : "#D84E4E"));
|
||||
isAllowedVariable ? AllowedVariableColor : InvalidVariableColor));
|
||||
|
||||
if (!isAllowedVariable)
|
||||
{
|
||||
@ -497,7 +502,7 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
||||
if (currentIndex < TextValue.Length)
|
||||
{
|
||||
string trailingText = TextValue[currentIndex..];
|
||||
FileNameFormatSegments.Add(new FileNameFormatSegmentViewModel(trailingText, "#1F2A44"));
|
||||
FileNameFormatSegments.Add(new FileNameFormatSegmentViewModel(trailingText, PlainTextColor));
|
||||
}
|
||||
|
||||
if (unknownVariables.Count > 0)
|
||||
@ -507,6 +512,15 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
private static (string PlainTextColor, string AllowedVariableColor, string InvalidVariableColor)
|
||||
GetFileNamePreviewColors()
|
||||
{
|
||||
bool isDarkTheme = Application.Current?.RequestedThemeVariant == ThemeVariant.Dark;
|
||||
return isDarkTheme
|
||||
? ("#DCE6F7", "#66A6FF", "#FF8C8C")
|
||||
: ("#1F2A44", "#2E6EEA", "#D84E4E");
|
||||
}
|
||||
|
||||
private static string ToDisplayName(string propertyName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(propertyName))
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.RegularExpressions;
|
||||
using Avalonia;
|
||||
using Avalonia.Styling;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using OF_DL.Models.Config;
|
||||
@ -254,6 +256,7 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
||||
|
||||
HashSet<string> allowedSet = new(allowedVariables, StringComparer.OrdinalIgnoreCase);
|
||||
HashSet<string> unknownVariables = new(StringComparer.OrdinalIgnoreCase);
|
||||
(string PlainTextColor, string AllowedVariableColor, string InvalidVariableColor) = GetFileNamePreviewColors();
|
||||
|
||||
MatchCollection matches = s_fileNameVariableRegex.Matches(format);
|
||||
int currentIndex = 0;
|
||||
@ -262,12 +265,13 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
||||
if (match.Index > currentIndex)
|
||||
{
|
||||
string plainText = format[currentIndex..match.Index];
|
||||
segments.Add(new FileNameFormatSegmentViewModel(plainText, "#1F2A44"));
|
||||
segments.Add(new FileNameFormatSegmentViewModel(plainText, PlainTextColor));
|
||||
}
|
||||
|
||||
string variableName = match.Groups[1].Value;
|
||||
bool isAllowed = allowedSet.Contains(variableName);
|
||||
segments.Add(new FileNameFormatSegmentViewModel(match.Value, isAllowed ? "#2E6EEA" : "#D84E4E"));
|
||||
segments.Add(new FileNameFormatSegmentViewModel(match.Value,
|
||||
isAllowed ? AllowedVariableColor : InvalidVariableColor));
|
||||
|
||||
if (!isAllowed)
|
||||
{
|
||||
@ -280,7 +284,7 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
||||
if (currentIndex < format.Length)
|
||||
{
|
||||
string trailingText = format[currentIndex..];
|
||||
segments.Add(new FileNameFormatSegmentViewModel(trailingText, "#1F2A44"));
|
||||
segments.Add(new FileNameFormatSegmentViewModel(trailingText, PlainTextColor));
|
||||
}
|
||||
|
||||
if (unknownVariables.Count > 0)
|
||||
@ -289,4 +293,13 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
||||
setUnknownMessage($"Unknown variable(s): {tokens}");
|
||||
}
|
||||
}
|
||||
|
||||
private static (string PlainTextColor, string AllowedVariableColor, string InvalidVariableColor)
|
||||
GetFileNamePreviewColors()
|
||||
{
|
||||
bool isDarkTheme = Application.Current?.RequestedThemeVariant == ThemeVariant.Dark;
|
||||
return isDarkTheme
|
||||
? ("#DCE6F7", "#66A6FF", "#FF8C8C")
|
||||
: ("#1F2A44", "#2E6EEA", "#D84E4E");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Text.RegularExpressions;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Avalonia.Threading;
|
||||
using Newtonsoft.Json;
|
||||
using OF_DL.Enumerations;
|
||||
using OF_DL.Gui.Services;
|
||||
using OF_DL.Models;
|
||||
using OF_DL.Models.Config;
|
||||
@ -124,10 +128,68 @@ public partial class MainWindowViewModel(
|
||||
"Enable download speed limiting.",
|
||||
[nameof(Config.DownloadLimitInMbPerSec)] =
|
||||
"Download rate limit in MB/s when rate limiting is enabled.",
|
||||
[nameof(Config.Theme)] =
|
||||
"GUI theme for the configuration and download screens.",
|
||||
[nameof(Config.LoggingLevel)] =
|
||||
"Log verbosity written to logs/OFDL.txt."
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, string> s_lightThemeBrushes = new(StringComparer.Ordinal)
|
||||
{
|
||||
["WindowBackgroundBrush"] = "#EEF3FB",
|
||||
["SurfaceBackgroundBrush"] = "#FFFFFF",
|
||||
["SurfaceBorderBrush"] = "#DDE5F3",
|
||||
["PrimaryButtonBackgroundBrush"] = "#2E6EEA",
|
||||
["PrimaryButtonForegroundBrush"] = "#FFFFFF",
|
||||
["SecondaryButtonBackgroundBrush"] = "#FFFFFF",
|
||||
["SecondaryButtonForegroundBrush"] = "#1F2A44",
|
||||
["SecondaryButtonBorderBrush"] = "#CFD9EB",
|
||||
["TopBarBackgroundBrush"] = "#DDEAFF",
|
||||
["TopBarBorderBrush"] = "#CFD9EB",
|
||||
["TopBarTextBrush"] = "#304261",
|
||||
["TextPrimaryBrush"] = "#1F2A44",
|
||||
["TextSecondaryBrush"] = "#4A5B78",
|
||||
["HelpBadgeBackgroundBrush"] = "#EAF0FB",
|
||||
["HelpBadgeBorderBrush"] = "#C5D4EC",
|
||||
["ErrorTextBrush"] = "#FF5A5A",
|
||||
["PreviewBackgroundBrush"] = "#F5F8FE",
|
||||
["PreviewBorderBrush"] = "#D8E3F4",
|
||||
["DangerSoftBackgroundBrush"] = "#FFE8E8",
|
||||
["DangerSoftBorderBrush"] = "#E8C5C5",
|
||||
["DangerButtonBackgroundBrush"] = "#D84E4E",
|
||||
["OverlayBackgroundBrush"] = "#80000000",
|
||||
["ModalBackgroundBrush"] = "#FFFFFF",
|
||||
["ModalBorderBrush"] = "#DDE5F3"
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, string> s_darkThemeBrushes = new(StringComparer.Ordinal)
|
||||
{
|
||||
["WindowBackgroundBrush"] = "#0F141D",
|
||||
["SurfaceBackgroundBrush"] = "#151C28",
|
||||
["SurfaceBorderBrush"] = "#2A3445",
|
||||
["PrimaryButtonBackgroundBrush"] = "#4C8DFF",
|
||||
["PrimaryButtonForegroundBrush"] = "#FFFFFF",
|
||||
["SecondaryButtonBackgroundBrush"] = "#1C2533",
|
||||
["SecondaryButtonForegroundBrush"] = "#DCE6F7",
|
||||
["SecondaryButtonBorderBrush"] = "#33425A",
|
||||
["TopBarBackgroundBrush"] = "#1A2433",
|
||||
["TopBarBorderBrush"] = "#33425A",
|
||||
["TopBarTextBrush"] = "#C7D6EE",
|
||||
["TextPrimaryBrush"] = "#DCE6F7",
|
||||
["TextSecondaryBrush"] = "#A8B8D2",
|
||||
["HelpBadgeBackgroundBrush"] = "#233145",
|
||||
["HelpBadgeBorderBrush"] = "#3A4E6A",
|
||||
["ErrorTextBrush"] = "#FF8C8C",
|
||||
["PreviewBackgroundBrush"] = "#1B2636",
|
||||
["PreviewBorderBrush"] = "#314359",
|
||||
["DangerSoftBackgroundBrush"] = "#3A2024",
|
||||
["DangerSoftBorderBrush"] = "#6A3A40",
|
||||
["DangerButtonBackgroundBrush"] = "#CC4A4A",
|
||||
["OverlayBackgroundBrush"] = "#99000000",
|
||||
["ModalBackgroundBrush"] = "#151C28",
|
||||
["ModalBorderBrush"] = "#2A3445"
|
||||
};
|
||||
|
||||
private Dictionary<string, long> _allUsers = [];
|
||||
private Dictionary<string, long> _allLists = [];
|
||||
private StartupResult _startupResult = new();
|
||||
@ -816,6 +878,7 @@ public partial class MainWindowViewModel(
|
||||
|
||||
private async Task BeginStartupAsync()
|
||||
{
|
||||
ApplyThemeFromConfigFileIfAvailable();
|
||||
_configReturnScreen = CurrentScreen;
|
||||
SetLoading("Loading configuration...");
|
||||
BuildConfigFields(configService.CurrentConfig);
|
||||
@ -841,6 +904,34 @@ public partial class MainWindowViewModel(
|
||||
await EnsureAuthenticationAndLoadUsersAsync();
|
||||
}
|
||||
|
||||
private static void ApplyThemeFromConfigFileIfAvailable()
|
||||
{
|
||||
const string configPath = "config.conf";
|
||||
if (!File.Exists(configPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string configText = File.ReadAllText(configPath);
|
||||
Match match = Regex.Match(configText, @"(?im)^\s*Theme\s*=\s*""(light|dark)""");
|
||||
if (!match.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Enum.TryParse(match.Groups[1].Value, true, out Theme parsedTheme))
|
||||
{
|
||||
ApplyConfiguredTheme(parsedTheme);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore theme parsing errors here; full config validation happens in ConfigService.
|
||||
}
|
||||
}
|
||||
|
||||
private async Task EnsureAuthenticationAndLoadUsersAsync()
|
||||
{
|
||||
bool hasValidAuth = await TryLoadAndValidateExistingAuthAsync();
|
||||
@ -1070,6 +1161,8 @@ public partial class MainWindowViewModel(
|
||||
|
||||
private void BuildConfigFields(Config config)
|
||||
{
|
||||
ApplyConfiguredTheme(config.Theme);
|
||||
|
||||
ConfigFields.Clear();
|
||||
ConfigCategories.Clear();
|
||||
ConfigCategoriesLeft.Clear();
|
||||
@ -1311,6 +1404,23 @@ public partial class MainWindowViewModel(
|
||||
private static string EscapePathForConfig(string path) =>
|
||||
path.Replace(@"\", @"\\");
|
||||
|
||||
private static void ApplyConfiguredTheme(Theme theme)
|
||||
{
|
||||
if (Application.Current == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool useDarkTheme = theme == Theme.dark;
|
||||
Application.Current.RequestedThemeVariant = useDarkTheme ? ThemeVariant.Dark : ThemeVariant.Light;
|
||||
|
||||
Dictionary<string, string> palette = useDarkTheme ? s_darkThemeBrushes : s_lightThemeBrushes;
|
||||
foreach (KeyValuePair<string, string> brush in palette)
|
||||
{
|
||||
Application.Current.Resources[brush.Key] = new SolidColorBrush(Color.Parse(brush.Value));
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetConfigHelpText(string propertyName) =>
|
||||
s_configHelpTextByProperty.TryGetValue(propertyName, out string? helpText)
|
||||
? helpText
|
||||
@ -1537,6 +1647,8 @@ public partial class MainWindowViewModel(
|
||||
nameof(Config.LimitDownloadRate) => "Performance",
|
||||
nameof(Config.DownloadLimitInMbPerSec) => "Performance",
|
||||
|
||||
nameof(Config.Theme) => "Appearance",
|
||||
|
||||
nameof(Config.LoggingLevel) => "Logging",
|
||||
|
||||
_ => "Other"
|
||||
@ -1553,7 +1665,8 @@ public partial class MainWindowViewModel(
|
||||
"Folder Structure" => 5,
|
||||
"Subscriptions" => 6,
|
||||
"Performance" => 7,
|
||||
"Logging" => 8,
|
||||
"Appearance" => 8,
|
||||
"Logging" => 9,
|
||||
_ => 100
|
||||
};
|
||||
}
|
||||
|
||||
@ -11,30 +11,30 @@
|
||||
MinWidth="1150"
|
||||
MinHeight="700"
|
||||
Title="OF DL"
|
||||
Background="#EEF3FB"
|
||||
Background="{DynamicResource WindowBackgroundBrush}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Styles>
|
||||
<Style Selector="Border.surface">
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="BorderBrush" Value="#DDE5F3" />
|
||||
<Setter Property="Background" Value="{DynamicResource SurfaceBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource SurfaceBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button.primary">
|
||||
<Setter Property="Background" Value="#2E6EEA" />
|
||||
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||
<Setter Property="Background" Value="{DynamicResource PrimaryButtonBackgroundBrush}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryButtonForegroundBrush}" />
|
||||
<Setter Property="Padding" Value="14,8" />
|
||||
<Setter Property="CornerRadius" Value="8" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button.secondary">
|
||||
<Setter Property="Background" Value="#FFFFFF" />
|
||||
<Setter Property="Foreground" Value="#1F2A44" />
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonBackgroundBrush}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource SecondaryButtonForegroundBrush}" />
|
||||
<Setter Property="Padding" Value="14,8" />
|
||||
<Setter Property="CornerRadius" Value="8" />
|
||||
<Setter Property="BorderBrush" Value="#CFD9EB" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource SecondaryButtonBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
</Style>
|
||||
@ -57,11 +57,11 @@
|
||||
<Border Grid.Row="1"
|
||||
Padding="16"
|
||||
BorderThickness="0,0,0,1"
|
||||
BorderBrush="#CFD9EB"
|
||||
Background="#DDEAFF">
|
||||
BorderBrush="{DynamicResource TopBarBorderBrush}"
|
||||
Background="{DynamicResource TopBarBackgroundBrush}">
|
||||
<Grid ColumnDefinitions="*,Auto" VerticalAlignment="Center">
|
||||
<TextBlock Grid.Column="0"
|
||||
Foreground="#304261"
|
||||
Foreground="{DynamicResource TopBarTextBrush}"
|
||||
FontWeight="SemiBold"
|
||||
Text="{Binding AuthenticatedUserDisplay}"
|
||||
TextWrapping="Wrap"
|
||||
@ -106,10 +106,10 @@
|
||||
<Grid ColumnDefinitions="3*,5*" Margin="0,0,0,2">
|
||||
<Border Grid.Column="0" Classes="surface" Padding="12" Margin="0,0,10,0">
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock FontSize="16" FontWeight="Bold" Foreground="#1F2A44" Text="External" />
|
||||
<TextBlock FontSize="16" FontWeight="Bold" Foreground="{DynamicResource TextPrimaryBrush}" Text="External" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="FFmpeg Path" />
|
||||
<Button Width="20"
|
||||
Height="20"
|
||||
@ -120,8 +120,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
@ -139,13 +139,13 @@
|
||||
Click="OnBrowseFfmpegPathClick" />
|
||||
</Grid>
|
||||
<TextBlock IsVisible="{Binding HasFfmpegPathError}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding FfmpegPathError}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="6" Margin="0,8,0,0">
|
||||
<TextBlock FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="FFprobe Path" />
|
||||
<Button Width="20"
|
||||
Height="20"
|
||||
@ -156,8 +156,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
@ -175,7 +175,7 @@
|
||||
Click="OnBrowseFfprobePathClick" />
|
||||
</Grid>
|
||||
<TextBlock IsVisible="{Binding HasFfprobePathError}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding FfprobePathError}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
@ -185,11 +185,11 @@
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="Download Media Types" />
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44" Text="Media Types" />
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Media Types" />
|
||||
<ItemsControl ItemsSource="{Binding MediaTypeOptions}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
@ -211,8 +211,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="11"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="9"
|
||||
Content="?"
|
||||
@ -222,13 +222,13 @@
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock IsVisible="{Binding HasMediaTypesError}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding MediaTypesError}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44" Text="Sources" />
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Sources" />
|
||||
<ItemsControl ItemsSource="{Binding MediaSourceOptions}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
@ -250,8 +250,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="11"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="9"
|
||||
Content="?"
|
||||
@ -261,7 +261,7 @@
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock IsVisible="{Binding HasMediaSourcesError}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding MediaSourcesError}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
@ -285,14 +285,14 @@
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="{Binding CategoryName}" />
|
||||
<StackPanel IsVisible="{Binding IsDownloadBehavior}"
|
||||
Spacing="4"
|
||||
Margin="0,0,0,10">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="Download Path" />
|
||||
<Button Width="20"
|
||||
Height="20"
|
||||
@ -303,8 +303,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
@ -324,7 +324,7 @@
|
||||
</Grid>
|
||||
<TextBlock
|
||||
IsVisible="{Binding ViewModel.HasDownloadPathError, RelativeSource={RelativeSource AncestorType=views:MainWindow}, FallbackValue=False}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding ViewModel.DownloadPathError, RelativeSource={RelativeSource AncestorType=views:MainWindow}, FallbackValue=''}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
@ -335,7 +335,7 @@
|
||||
ClipToBounds="True">
|
||||
<TextBlock Grid.Column="0"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="DRM Video Duration Match Threshold"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Top" />
|
||||
@ -352,8 +352,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
@ -368,7 +368,7 @@
|
||||
Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#4A5B78"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"
|
||||
Text="{Binding ViewModel.DrmVideoDurationMatchThresholdPercentLabel, RelativeSource={RelativeSource AncestorType=views:MainWindow}, FallbackValue='98%'}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
@ -382,7 +382,7 @@
|
||||
Spacing="6"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="Download Posts from Specific Dates"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
@ -397,8 +397,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
@ -435,7 +435,7 @@
|
||||
ClipToBounds="True">
|
||||
<TextBlock Grid.Column="0"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="Limit Download Rate"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Top" />
|
||||
@ -453,8 +453,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
@ -472,7 +472,7 @@
|
||||
Increment="1"
|
||||
FormatString="N0" />
|
||||
<TextBlock Text="Mbps"
|
||||
Foreground="#4A5B78"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@ -486,7 +486,7 @@
|
||||
ClipToBounds="True">
|
||||
<TextBlock Grid.Column="0"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="Create Separate Folders For Each"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Top" />
|
||||
@ -504,8 +504,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
@ -537,7 +537,7 @@
|
||||
ClipToBounds="True">
|
||||
<TextBlock Grid.Column="0"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="{Binding DisplayName}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Top" />
|
||||
@ -555,8 +555,8 @@
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
@ -594,7 +594,7 @@
|
||||
Increment="1"
|
||||
FormatString="N0" />
|
||||
<TextBlock Text="seconds"
|
||||
Foreground="#4A5B78"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
@ -633,8 +633,8 @@
|
||||
FontWeight="SemiBold"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Content="⟳"
|
||||
@ -659,8 +659,8 @@
|
||||
</Grid>
|
||||
|
||||
<Border Padding="8"
|
||||
Background="#F5F8FE"
|
||||
BorderBrush="#D8E3F4"
|
||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<ItemsControl
|
||||
@ -686,7 +686,7 @@
|
||||
|
||||
<TextBlock
|
||||
IsVisible="{Binding HasUnknownFileNameVariables}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding UnknownFileNameVariablesMessage}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
@ -719,8 +719,8 @@
|
||||
<DataTemplate
|
||||
x:DataType="vm:CreatorConfigRowViewModel">
|
||||
<Border
|
||||
Background="#F5F8FE"
|
||||
BorderBrush="#D8E3F4"
|
||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="10">
|
||||
@ -729,7 +729,7 @@
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="{Binding Username}"
|
||||
VerticalAlignment="Center" />
|
||||
<Button
|
||||
@ -744,8 +744,8 @@
|
||||
FontWeight="SemiBold"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
Background="{DynamicResource HelpBadgeBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource HelpBadgeBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="6"
|
||||
Content="✎"
|
||||
@ -762,8 +762,8 @@
|
||||
FontWeight="SemiBold"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
Background="#FFE8E8"
|
||||
BorderBrush="#E8C5C5"
|
||||
Background="{DynamicResource DangerSoftBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource DangerSoftBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="6"
|
||||
Content="×"
|
||||
@ -778,7 +778,7 @@
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock IsVisible="{Binding HasError}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding ErrorMessage}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
@ -852,7 +852,7 @@
|
||||
<Button Grid.Column="1"
|
||||
IsVisible="{Binding IsDownloading}"
|
||||
Classes="primary"
|
||||
Background="#D84E4E"
|
||||
Background="{DynamicResource DangerButtonBackgroundBrush}"
|
||||
Command="{Binding StopWorkCommand}"
|
||||
Content="Stop" />
|
||||
</Grid>
|
||||
@ -866,7 +866,7 @@
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,Auto" VerticalAlignment="Center">
|
||||
<StackPanel Grid.Column="0" Spacing="3">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44" Text="Users" />
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Users" />
|
||||
<CheckBox IsThreeState="True"
|
||||
IsChecked="{Binding AllUsersSelected}"
|
||||
Content="{Binding SelectedUsersSummary}"
|
||||
@ -881,6 +881,8 @@
|
||||
IsEnabled="{Binding !IsDownloading}" />
|
||||
</Grid>
|
||||
<ListBox Grid.Row="1" Margin="0,8,0,0" ItemsSource="{Binding AvailableUsers}"
|
||||
Background="{DynamicResource SurfaceBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource SurfaceBorderBrush}"
|
||||
IsEnabled="{Binding !IsDownloading}">
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
@ -902,8 +904,12 @@
|
||||
Padding="10"
|
||||
Classes="surface">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" FontWeight="SemiBold" Foreground="#1F2A44" Text="Activity Log" />
|
||||
<ListBox Grid.Row="1" Margin="0,8,0,0" ItemsSource="{Binding ActivityLog}" />
|
||||
<TextBlock Grid.Row="0" FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Activity Log" />
|
||||
<ListBox Grid.Row="1"
|
||||
Margin="0,8,0,0"
|
||||
ItemsSource="{Binding ActivityLog}"
|
||||
Background="{DynamicResource SurfaceBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource SurfaceBorderBrush}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
@ -914,7 +920,7 @@
|
||||
Classes="surface"
|
||||
IsVisible="{Binding IsDownloadProgressVisible}">
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44"
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="{Binding DownloadProgressDescription}" />
|
||||
<ProgressBar IsIndeterminate="{Binding IsDownloadProgressIndeterminate}"
|
||||
Minimum="0"
|
||||
@ -944,11 +950,11 @@
|
||||
<!-- Modal Overlay -->
|
||||
<Grid Grid.Row="0" Grid.RowSpan="3"
|
||||
IsVisible="{Binding CreatorConfigEditor.ModalViewModel.IsOpen}"
|
||||
Background="#80000000"
|
||||
Background="{DynamicResource OverlayBackgroundBrush}"
|
||||
ZIndex="1000"
|
||||
PointerPressed="OnModalOverlayClicked">
|
||||
<Border Background="#FFFFFF"
|
||||
BorderBrush="#DDE5F3"
|
||||
<Border Background="{DynamicResource ModalBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource ModalBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12"
|
||||
Padding="24"
|
||||
@ -962,11 +968,11 @@
|
||||
<StackPanel Spacing="14" Margin="8,4,8,4" x:DataType="vm:CreatorConfigModalViewModel">
|
||||
<TextBlock FontSize="18"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Foreground="{DynamicResource TextPrimaryBrush}"
|
||||
Text="{Binding DialogTitle}" />
|
||||
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44" Text="Username" />
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Username" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<AutoCompleteBox Grid.Column="0"
|
||||
Text="{Binding Username}"
|
||||
@ -975,17 +981,17 @@
|
||||
FilterMode="Contains" />
|
||||
</Grid>
|
||||
<TextBlock IsVisible="{Binding HasUsernameError}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding UsernameError}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock FontWeight="SemiBold"
|
||||
Foreground="#4A5B78"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"
|
||||
Text="Filename Formats (leave blank to use global defaults)" />
|
||||
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44" Text="Paid Post Filename Format" />
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Paid Post Filename Format" />
|
||||
<TextBox Text="{Binding PaidPostFileNameFormat}"
|
||||
Watermark="Optional: override global paid post format" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
@ -1000,8 +1006,8 @@
|
||||
Command="{Binding InsertPaidPostVariableCommand}" />
|
||||
</Grid>
|
||||
<Border Padding="8"
|
||||
Background="#F5F8FE"
|
||||
BorderBrush="#D8E3F4"
|
||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<ItemsControl ItemsSource="{Binding PaidPostSegments}">
|
||||
@ -1021,13 +1027,13 @@
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
<TextBlock IsVisible="{Binding HasUnknownPaidPostVariables}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding UnknownPaidPostVariablesMessage}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44" Text="Post Filename Format" />
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Post Filename Format" />
|
||||
<TextBox Text="{Binding PostFileNameFormat}"
|
||||
Watermark="Optional: override global post format" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
@ -1042,8 +1048,8 @@
|
||||
Command="{Binding InsertPostVariableCommand}" />
|
||||
</Grid>
|
||||
<Border Padding="8"
|
||||
Background="#F5F8FE"
|
||||
BorderBrush="#D8E3F4"
|
||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<ItemsControl ItemsSource="{Binding PostSegments}">
|
||||
@ -1063,13 +1069,13 @@
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
<TextBlock IsVisible="{Binding HasUnknownPostVariables}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding UnknownPostVariablesMessage}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44" Text="Paid Message Filename Format" />
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Paid Message Filename Format" />
|
||||
<TextBox Text="{Binding PaidMessageFileNameFormat}"
|
||||
Watermark="Optional: override global paid message format" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
@ -1084,8 +1090,8 @@
|
||||
Command="{Binding InsertPaidMessageVariableCommand}" />
|
||||
</Grid>
|
||||
<Border Padding="8"
|
||||
Background="#F5F8FE"
|
||||
BorderBrush="#D8E3F4"
|
||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<ItemsControl ItemsSource="{Binding PaidMessageSegments}">
|
||||
@ -1105,13 +1111,13 @@
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
<TextBlock IsVisible="{Binding HasUnknownPaidMessageVariables}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding UnknownPaidMessageVariablesMessage}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock FontWeight="SemiBold" Foreground="#1F2A44" Text="Message Filename Format" />
|
||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Message Filename Format" />
|
||||
<TextBox Text="{Binding MessageFileNameFormat}"
|
||||
Watermark="Optional: override global message format" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
@ -1126,8 +1132,8 @@
|
||||
Command="{Binding InsertMessageVariableCommand}" />
|
||||
</Grid>
|
||||
<Border Padding="8"
|
||||
Background="#F5F8FE"
|
||||
BorderBrush="#D8E3F4"
|
||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<ItemsControl ItemsSource="{Binding MessageSegments}">
|
||||
@ -1147,7 +1153,7 @@
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
<TextBlock IsVisible="{Binding HasUnknownMessageVariables}"
|
||||
Foreground="#FF5A5A"
|
||||
Foreground="{DynamicResource ErrorTextBrush}"
|
||||
Text="{Binding UnknownMessageVariablesMessage}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
@ -1167,3 +1173,4 @@
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
@ -41,18 +40,14 @@ public partial class MainWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
TopLevel? topLevel = TopLevel.GetTopLevel(this);
|
||||
TopLevel? topLevel = GetTopLevel(this);
|
||||
if (topLevel?.StorageProvider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IReadOnlyList<IStorageFile> selectedFiles = await topLevel.StorageProvider.OpenFilePickerAsync(
|
||||
new FilePickerOpenOptions
|
||||
{
|
||||
Title = "Select FFmpeg executable",
|
||||
AllowMultiple = false
|
||||
});
|
||||
new FilePickerOpenOptions { Title = "Select FFmpeg executable", AllowMultiple = false });
|
||||
|
||||
IStorageFile? selectedFile = selectedFiles.FirstOrDefault();
|
||||
if (selectedFile == null)
|
||||
@ -77,18 +72,14 @@ public partial class MainWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
TopLevel? topLevel = TopLevel.GetTopLevel(this);
|
||||
TopLevel? topLevel = GetTopLevel(this);
|
||||
if (topLevel?.StorageProvider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IReadOnlyList<IStorageFile> selectedFiles = await topLevel.StorageProvider.OpenFilePickerAsync(
|
||||
new FilePickerOpenOptions
|
||||
{
|
||||
Title = "Select FFprobe executable",
|
||||
AllowMultiple = false
|
||||
});
|
||||
new FilePickerOpenOptions { Title = "Select FFprobe executable", AllowMultiple = false });
|
||||
|
||||
IStorageFile? selectedFile = selectedFiles.FirstOrDefault();
|
||||
if (selectedFile == null)
|
||||
@ -113,18 +104,14 @@ public partial class MainWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
TopLevel? topLevel = TopLevel.GetTopLevel(this);
|
||||
TopLevel? topLevel = GetTopLevel(this);
|
||||
if (topLevel?.StorageProvider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IReadOnlyList<IStorageFolder> selectedFolders = await topLevel.StorageProvider.OpenFolderPickerAsync(
|
||||
new FolderPickerOpenOptions
|
||||
{
|
||||
Title = "Select download folder",
|
||||
AllowMultiple = false
|
||||
});
|
||||
new FolderPickerOpenOptions { Title = "Select download folder", AllowMultiple = false });
|
||||
|
||||
IStorageFolder? selectedFolder = selectedFolders.FirstOrDefault();
|
||||
if (selectedFolder == null)
|
||||
@ -154,9 +141,7 @@ public partial class MainWindow : Window
|
||||
vm.CreatorConfigEditor.ModalViewModel?.CancelCommand?.Execute(null);
|
||||
}
|
||||
|
||||
private void OnModalContentClicked(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
private void OnModalContentClicked(object? sender, PointerPressedEventArgs e) =>
|
||||
// Stop the event from bubbling up to the overlay
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ public class ConfigServiceTests
|
||||
Assert.Equal(service.CurrentConfig.LoggingLevel, loggingService.LastLevel);
|
||||
Assert.Equal("", service.CurrentConfig.FFprobePath);
|
||||
Assert.Equal(0.98, service.CurrentConfig.DrmVideoDurationMatchThreshold, 3);
|
||||
Assert.Equal(Theme.light, service.CurrentConfig.Theme);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -80,6 +81,25 @@ public class ConfigServiceTests
|
||||
Assert.Equal(0.95, service.CurrentConfig.DrmVideoDurationMatchThreshold, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadConfigurationAsync_ParsesAppearanceTheme()
|
||||
{
|
||||
using TempFolder temp = new();
|
||||
using CurrentDirectoryScope _ = new(temp.Path);
|
||||
FakeLoggingService loggingService = new();
|
||||
ConfigService service = new(loggingService);
|
||||
await service.SaveConfigurationAsync();
|
||||
|
||||
string hocon = await File.ReadAllTextAsync("config.conf");
|
||||
hocon = hocon.Replace("Theme = \"light\"", "Theme = \"dark\"");
|
||||
await File.WriteAllTextAsync("config.conf", hocon);
|
||||
|
||||
bool result = await service.LoadConfigurationAsync([]);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.Equal(Theme.dark, service.CurrentConfig.Theme);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyToggleableSelections_UpdatesConfigAndReturnsChange()
|
||||
{
|
||||
|
||||
@ -581,6 +581,17 @@ Allowed values: `true`, `false`
|
||||
|
||||
Description: Posts and messages that contain #ad or free trial links will be ignored if set to `true`
|
||||
|
||||
## Theme
|
||||
|
||||
Type: `string`
|
||||
|
||||
Default: `"light"`
|
||||
|
||||
Allowed values: `"light"`, `"dark"`
|
||||
|
||||
Description: Controls the OF-DL GUI theme.
|
||||
Set to `"light"` for light mode or `"dark"` for dark mode.
|
||||
|
||||
## Timeout
|
||||
|
||||
Type: `integer`
|
||||
|
||||
@ -68,5 +68,8 @@ information about what it does, its default value, and the allowed values.
|
||||
- [LimitDownloadRate](/config/all-configuration-options#limitdownloadrate)
|
||||
- [DownloadLimitInMbPerSec](/config/all-configuration-options#downloadlimitinmbpersec)
|
||||
|
||||
- Appearance
|
||||
- [Theme](/config/all-configuration-options#theme)
|
||||
|
||||
- Logging
|
||||
- [LoggingLevel](/config/all-configuration-options#logginglevel)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user