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