Add Dark Mode toggle with dynamic theme switching

Summary

  - Add dark mode toggle icon (☀️/🌙) to main window and settings header for quick theme switching
  - Create ThemeService for centralized theme management with save/load from settings
  - Replace all hardcoded colors with DynamicResource for proper theme support
  - Synchronize theme state between MainWindow and Settings via ThemeChanged event
  - Update Buttons, TextBlocks, and ComboBoxes styles to be theme-aware
  - Fix dark mode for all modal dialogs (BuildInfo, InstallationComplete, Installing, IpInput, TvLogs)
  - Update DialogService to use theme-aware colors from FluentTheme resources
This commit is contained in:
kingchenc
2026-01-12 14:24:49 +01:00
parent ab61755609
commit 2192fede6a
17 changed files with 258 additions and 77 deletions

View File

@@ -49,7 +49,10 @@ namespace Jellyfin2Samsung
});
}
RequestedThemeVariant = ThemeVariant.Light;
// Apply saved theme on startup
var themeService = _serviceProvider.GetRequiredService<IThemeService>();
themeService.ApplyTheme();
base.OnFrameworkInitializationCompleted();
}
@@ -68,6 +71,7 @@ namespace Jellyfin2Samsung
services.AddSingleton<INetworkService, NetworkService>();
services.AddSingleton<ITizenCertificateService, TizenCertificateService>();
services.AddSingleton<ITizenInstallerService, TizenInstallerService>();
services.AddSingleton<IThemeService, ThemeService>();
// HttpClient (configured ONCE)
services.AddSingleton(sp =>

View File

@@ -71,6 +71,7 @@ namespace Jellyfin2Samsung.Helpers
public bool KeepWGTFile { get; set; } = false;
public bool PatchYoutubePlugin { get; set; } = false;
public string CustomCss { get; set; } = "";
public bool DarkMode { get; set; } = false;
// ----- Application-scoped settings (readonly at runtime) -----
public string ReleasesUrl { get; set; } = "https://api.github.com/repos/jeppevinkel/jellyfin-tizen-builds/releases";

View File

@@ -0,0 +1,12 @@
using System;
namespace Jellyfin2Samsung.Interfaces
{
public interface IThemeService
{
bool IsDarkMode { get; }
event EventHandler<bool>? ThemeChanged;
void SetTheme(bool isDarkMode);
void ApplyTheme();
}
}

View File

@@ -2,15 +2,31 @@
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.Markup.Xaml.Styling;
using System.Threading.Tasks;
using System;
using Jellyfin2Samsung.Interfaces;
using Jellyfin2Samsung;
using Jellyfin2Samsung.Helpers;
namespace Jellyfin2Samsung.Services
{
public class DialogService : IDialogService
{
private static IBrush GetThemeBrush(string resourceKey, bool isDarkMode)
{
var themeVariant = isDarkMode ? ThemeVariant.Dark : ThemeVariant.Light;
if (Application.Current?.TryFindResource(resourceKey, themeVariant, out var resource) == true && resource is IBrush brush)
{
return brush;
}
// Ultimate fallback
return resourceKey.Contains("Background")
? (isDarkMode ? Brushes.Black : Brushes.White)
: (isDarkMode ? Brushes.White : Brushes.Black);
}
private Window? GetMainWindow()
{
if (Application.Current?.ApplicationLifetime is Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop)
@@ -27,6 +43,9 @@ namespace Jellyfin2Samsung.Services
string yesText = "Yes",
string noText = "No")
{
// Get theme from AppSettings
var isDarkMode = AppSettings.Default.DarkMode;
var dialog = new Window
{
Title = title,
@@ -35,11 +54,22 @@ namespace Jellyfin2Samsung.Services
MaxWidth = 600,
CanResize = false,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Background = Brushes.White,
CornerRadius = new CornerRadius(12),
SizeToContent = SizeToContent.Height, // dynamic height
RequestedThemeVariant = isDarkMode ? ThemeVariant.Dark : ThemeVariant.Light
};
// Apply FluentTheme
dialog.Styles.Add(new StyleInclude(new Uri("avares://Jellyfin2Samsung"))
{
Source = new Uri("avares://Avalonia.Themes.Fluent/FluentTheme.xaml")
});
// Get colors from theme resources (same as main UI)
var backgroundBrush = GetThemeBrush("SystemControlBackgroundAltHighBrush", isDarkMode);
var foregroundBrush = GetThemeBrush("SystemControlForegroundBaseHighBrush", isDarkMode);
dialog.Background = backgroundBrush;
var mainPanel = new StackPanel
{
Orientation = Orientation.Vertical,
@@ -52,6 +82,7 @@ namespace Jellyfin2Samsung.Services
Text = title,
FontSize = 18,
FontWeight = FontWeight.Bold,
Foreground = foregroundBrush,
HorizontalAlignment = HorizontalAlignment.Center,
Margin = new Thickness(0, 0, 0, 10)
});
@@ -117,10 +148,14 @@ namespace Jellyfin2Samsung.Services
public async Task ShowMessageAsync(string title, string message)
{
var window = GetMainWindow();
var isDarkMode = AppSettings.Default.DarkMode;
var foregroundBrush = GetThemeBrush("SystemControlForegroundBaseHighBrush", isDarkMode);
var dialog = CreateStyledDialog(title, new TextBlock
{
Text = message,
TextWrapping = TextWrapping.Wrap,
Foreground = foregroundBrush,
FontSize = 14,
Margin = new Thickness(0, 5, 0, 0)
});
@@ -149,11 +184,14 @@ namespace Jellyfin2Samsung.Services
{
var window = owner ?? GetMainWindow();
var tcs = new TaskCompletionSource<bool>();
var isDarkMode = AppSettings.Default.DarkMode;
var foregroundBrush = GetThemeBrush("SystemControlForegroundBaseHighBrush", isDarkMode);
var dialog = CreateStyledDialog(title, new TextBlock
{
Text = message,
TextWrapping = TextWrapping.Wrap,
Foreground = foregroundBrush,
FontSize = 14,
Margin = new Thickness(0, 5, 0, 0)
}, showButtons: true, tcs: tcs, yesText: yesText, noText: noText);

View File

@@ -0,0 +1,37 @@
using Avalonia;
using Avalonia.Styling;
using Jellyfin2Samsung.Helpers;
using Jellyfin2Samsung.Interfaces;
using System;
namespace Jellyfin2Samsung.Services
{
public class ThemeService : IThemeService
{
public bool IsDarkMode => AppSettings.Default.DarkMode;
public event EventHandler<bool>? ThemeChanged;
public void SetTheme(bool isDarkMode)
{
if (AppSettings.Default.DarkMode == isDarkMode)
return;
AppSettings.Default.DarkMode = isDarkMode;
AppSettings.Default.Save();
ApplyTheme();
ThemeChanged?.Invoke(this, isDarkMode);
}
public void ApplyTheme()
{
if (Application.Current is null)
return;
Application.Current.RequestedThemeVariant = AppSettings.Default.DarkMode
? ThemeVariant.Dark
: ThemeVariant.Light;
}
}
}

View File

@@ -34,9 +34,9 @@
<Setter Property="Width" Value="40"/>
<Setter Property="Height" Value="40"/>
<Setter Property="CornerRadius" Value="20"/>
<Setter Property="Background" Value="#ffffff"/>
<Setter Property="Foreground" Value="#2C3E50"/>
<Setter Property="BorderBrush" Value="#d0d7de"/>
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundAltHighBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>

View File

@@ -1,9 +1,9 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="ComboBox.clean">
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="#2C3E50"/>
<Setter Property="BorderBrush" Value="#BDC3C7"/>
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundAltHighBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="4"/>
<Setter Property="Padding" Value="12,8"/>

View File

@@ -3,11 +3,11 @@
<Style Selector="TextBlock.label">
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Foreground" Value="#2C3E50"/>
<Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
</Style>
<Style Selector="TextBlock.subtitle">
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="#7F8C8D"/>
<Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundBaseMediumBrush}"/>
</Style>
</Styles>

View File

@@ -27,6 +27,7 @@ namespace Jellyfin2Samsung.ViewModels
private readonly ILocalizationService _localizationService;
private readonly CertificateHelper _certificateHelper;
private readonly INetworkService _networkService;
private readonly IThemeService _themeService;
[ObservableProperty]
private string? audioLanguagePreference;
@@ -169,6 +170,9 @@ namespace Jellyfin2Samsung.ViewModels
[ObservableProperty]
private bool keepWGTFile;
[ObservableProperty]
private bool darkMode;
public ObservableCollection<LanguageOption> AvailableLanguages { get; }
public ObservableCollection<ExistingCertificates> AvailableCertificates { get; } = new();
public ObservableCollection<JellyfinUser> AvailableJellyfinUsers { get; } = new();
@@ -300,13 +304,16 @@ namespace Jellyfin2Samsung.ViewModels
JellyfinApiClient jellyfinApiClient,
ILocalizationService localizationService,
CertificateHelper certificateHelper,
INetworkService networkService)
INetworkService networkService,
IThemeService themeService)
{
_jellyfinApiClient = jellyfinApiClient;
_localizationService = localizationService;
_certificateHelper = certificateHelper;
_networkService = networkService;
_themeService = themeService;
_localizationService.LanguageChanged += OnLanguageChanged;
_themeService.ThemeChanged += OnThemeChanged;
// Initialize selected users collection with change tracking
SelectedJellyfinUsers = new ObservableCollection<JellyfinUser>();
@@ -344,6 +351,11 @@ namespace Jellyfin2Samsung.ViewModels
RefreshLocalizedProperties();
}
private void OnThemeChanged(object? sender, bool isDarkMode)
{
DarkMode = isDarkMode;
}
private void RefreshLocalizedProperties()
{
OnPropertyChanged(nameof(LblJellyfinConfig));
@@ -927,14 +939,15 @@ namespace Jellyfin2Samsung.ViewModels
{
using var http = new HttpClient();
var bytes = await http.GetByteArrayAsync(url);
using var ms = new System.IO.MemoryStream(bytes);
return new Bitmap(ms);
}
catch (Exception ex)
{
Trace.WriteLine($"[ThemePreview] Failed to load preview: {ex.Message}");
return null;
using var http = new HttpClient();
var stream = await http.GetStreamAsync(url);
return new Bitmap(stream);
}
}
@@ -1002,7 +1015,6 @@ namespace Jellyfin2Samsung.ViewModels
HexColor = "#6B5B95",
CssImportUrl = "https://cdn.jsdelivr.net/gh/kingchenc/JellyThemes@master/Themes/Obsidian/Obsidian.css",
PreviewUrl = "https://raw.githubusercontent.com/kingchenc/JellyThemes/master/Themes/Obsidian/assets/preview/Obsidian.png"
},
new JellyTheme
{
@@ -1244,6 +1256,7 @@ namespace Jellyfin2Samsung.ViewModels
TryOverwrite = AppSettings.Default.TryOverwrite;
OpenAfterInstall = AppSettings.Default.OpenAfterInstall;
KeepWGTFile = AppSettings.Default.KeepWGTFile;
DarkMode = AppSettings.Default.DarkMode;
}
private async Task LoadLocalIpAsync()
@@ -1379,11 +1392,17 @@ namespace Jellyfin2Samsung.ViewModels
AppSettings.Default.Save();
}
partial void OnDarkModeChanged(bool value)
{
_themeService.SetTheme(value);
}
// ========== End Main Settings Methods ==========
public void Dispose()
{
_localizationService.LanguageChanged -= OnLanguageChanged;
_themeService.ThemeChanged -= OnThemeChanged;
}
}
}

View File

@@ -8,6 +8,7 @@ using Jellyfin2Samsung.Helpers.API;
using Jellyfin2Samsung.Helpers.Core;
using Jellyfin2Samsung.Helpers.Tizen.Devices;
using Jellyfin2Samsung.Interfaces;
using Jellyfin2Samsung.Services;
using Jellyfin2Samsung.Models;
using Jellyfin2Samsung.Views;
using Microsoft.Extensions.DependencyInjection;
@@ -29,6 +30,7 @@ namespace Jellyfin2Samsung.ViewModels
private readonly IDialogService _dialogService;
private readonly INetworkService _networkService;
private readonly ILocalizationService _localizationService;
private readonly IThemeService _themeService;
private readonly FileHelper _fileHelper;
private readonly DeviceHelper _deviceHelper;
private readonly TizenApiClient _tizenApiClient;
@@ -70,6 +72,9 @@ namespace Jellyfin2Samsung.ViewModels
[ObservableProperty]
private bool isSamsungLoginActive;
[ObservableProperty]
private bool darkMode;
private string _currentStatusKey = string.Empty;
private string? _downloadedPackagePath;
@@ -91,6 +96,7 @@ namespace Jellyfin2Samsung.ViewModels
IDialogService dialogService,
INetworkService networkService,
ILocalizationService localizationService,
IThemeService themeService,
HttpClient httpClient,
DeviceHelper deviceHelper,
TizenApiClient tizenApiClient,
@@ -106,12 +112,17 @@ namespace Jellyfin2Samsung.ViewModels
_tizenApiClient = tizenApiClient;
_packageHelper = packageHelper;
_localizationService = localizationService;
_themeService = themeService;
_fileHelper = fileHelper;
_settingsViewModel = settingsViewModel;
_addLatestRelease = new AddLatestRelease(httpClient);
_localizationService.LanguageChanged += OnLanguageChanged;
_themeService.ThemeChanged += OnThemeChanged;
// Initialize dark mode state from settings
DarkMode = AppSettings.Default.DarkMode;
}
@@ -122,6 +133,16 @@ namespace Jellyfin2Samsung.ViewModels
if (!string.IsNullOrEmpty(_currentStatusKey))
StatusBar = L(_currentStatusKey);
}
private void OnThemeChanged(object? sender, bool isDarkMode)
{
DarkMode = isDarkMode;
}
partial void OnDarkModeChanged(bool value)
{
_themeService.SetTheme(value);
}
private void SetStatus(string key)
{
_currentStatusKey = key;
@@ -340,6 +361,7 @@ namespace Jellyfin2Samsung.ViewModels
await _dialogService.ShowErrorAsync($"Failed to open build info window: {ex}");
}
}
[RelayCommand]
private async Task BrowseWgtAsync()
{
@@ -584,6 +606,7 @@ namespace Jellyfin2Samsung.ViewModels
{
DisposeSamsungCts();
_localizationService.LanguageChanged -= OnLanguageChanged;
_themeService.ThemeChanged -= OnThemeChanged;
}
}

View File

@@ -8,19 +8,18 @@
MaxWidth="900"
MinHeight="500"
WindowStartupLocation="CenterOwner"
Title="Jellyfin Tizen Versions"
Background="#F5F5F5">
Title="Jellyfin Tizen Versions">
<Window.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
</Window.Styles>
<Border Background="White"
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
Padding="16"
CornerRadius="8"
Margin="12"
BorderBrush="#E8E8E8"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<Border.Effect>
@@ -53,7 +52,7 @@
FontSize="15"/>
</Border>
<Border BorderBrush="#D0D0D0"
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="4"
Height="200">
@@ -91,7 +90,7 @@
FontSize="15"/>
</Border>
<Border BorderBrush="#D0D0D0"
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="4"
Height="260">

View File

@@ -10,7 +10,6 @@
WindowStartupLocation="CenterScreen"
CanResize="False"
SizeToContent="WidthAndHeight"
Background="#F5F5F5"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1">
@@ -24,11 +23,11 @@
<StyleInclude Source="avares://Jellyfin2Samsung/Styles/ComboBoxes.axaml"/>
</Window.Styles>
<Border Background="White"
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
Padding="10"
CornerRadius="8"
Margin="20"
BorderBrush="#E8E8E8"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<Border.Effect>
<DropShadowEffect BlurRadius="15"
@@ -50,14 +49,14 @@
TextWrapping="Wrap"
FontSize="16"
TextAlignment="Center"
Foreground="#2C3E50"
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"
FontWeight="Medium"/>
<!-- Extra Info -->
<TextBlock Text="{Binding EasyRight}"
TextWrapping="Wrap"
TextAlignment="Center"
Foreground="#7F8C8D"
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"
FontSize="14"/>
<!-- Action Buttons -->

View File

@@ -12,12 +12,20 @@
Topmost="True"
ShowInTaskbar="False"
Title="Installing">
<Window.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentTheme.xaml"/>
</Window.Styles>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<Border Background="#FFF" CornerRadius="4" Padding="10" Margin="5"
BorderBrush="#FF000B25" BorderThickness="1" >
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="4" Padding="10" Margin="5"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<StackPanel>
<TextBlock x:Name="StatusTextBlock"
Text="{Binding StatusText}"
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"
FontWeight="Bold"
Margin="0,10"
HorizontalAlignment="Center"/>

View File

@@ -9,18 +9,21 @@
x:Class="Jellyfin2Samsung.IpInputDialog"
x:DataType="viewModels:IpInputDialogViewModel"
Width="420"
Height="220"
Height="250"
Title="{Binding Title}"
WindowStartupLocation="CenterOwner"
CanResize="False"
Background="White"
CornerRadius="12">
<Border Background="White"
<Window.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentTheme.xaml"/>
</Window.Styles>
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
Padding="20"
CornerRadius="12"
Margin="10"
BorderBrush="#E5E7EB"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<Border.Effect>
<DropShadowEffect BlurRadius="20"
@@ -36,12 +39,13 @@
<TextBlock Text="{Binding Title}"
FontSize="18"
FontWeight="Bold"
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"
HorizontalAlignment="Center"
Margin="0,0,0,10"/>
<!-- Message -->
<TextBlock Text="{Binding Message}"
Foreground="#111827"
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"
FontSize="14"
TextWrapping="Wrap"
Margin="0,0,0,8"/>
@@ -49,9 +53,8 @@
<!-- IP Input -->
<TextBox Text="{Binding EnteredIp}"
Watermark="Enter IP address..."
CaretBrush="Black"
SelectionBrush="#2563eb"
BorderBrush="#9CA3AF"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
CornerRadius="8"
Padding="8"
FontSize="14"

View File

@@ -8,9 +8,8 @@
x:Class="Jellyfin2Samsung.JellyfinConfigView"
x:DataType="viewModels:JellyfinConfigViewModel"
Title="Settings"
Width="700"
Height="850"
Background="#F5F5F5">
Width="715"
Height="850">
<Window.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentTheme.xaml"/>
@@ -20,11 +19,11 @@
<StyleInclude Source="avares://Jellyfin2Samsung/Styles/ComboBoxes.axaml"/>
</Window.Styles>
<Border Background="White"
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
Padding="16"
CornerRadius="8"
Margin="6"
BorderBrush="#E8E8E8"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<Border.Effect>
@@ -43,11 +42,33 @@
CornerRadius="8"
Padding="24,16"
Margin="0,0,0,14">
<TextBlock Text="{Binding LblSettingsHeader}"
Foreground="White"
FontSize="18"
FontWeight="Medium"
HorizontalAlignment="Center"/>
<Grid>
<TextBlock Text="{Binding LblSettingsHeader}"
Foreground="White"
FontSize="18"
FontWeight="Medium"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<ToggleButton IsChecked="{Binding DarkMode}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Background="Transparent"
BorderThickness="0"
Padding="4">
<ToggleButton.Styles>
<Style Selector="ToggleButton:checked">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="ToggleButton:pointerover">
<Setter Property="Background" Value="#40FFFFFF"/>
</Style>
</ToggleButton.Styles>
<Panel>
<TextBlock Text="&#x2600;" FontSize="18" Foreground="White" IsVisible="{Binding DarkMode}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="&#x1F319;" FontSize="16" Foreground="White" IsVisible="{Binding !DarkMode}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Panel>
</ToggleButton>
</Grid>
</Border>
<!-- TabControl with 5 Tabs -->
@@ -63,7 +84,7 @@
<TextBlock Text="{Binding LblMainSettings}"
FontSize="15"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<!-- Language Section -->
<Grid ColumnDefinitions="180,*" ColumnSpacing="12">
@@ -116,7 +137,7 @@
</Grid>
</StackPanel>
<Border Height="1" Background="#E8E8E8" Margin="0,4"/>
<Border Height="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" Margin="0,4"/>
<!-- Installation Options Section -->
<StackPanel Spacing="12">
@@ -200,7 +221,7 @@
<TextBlock Text="{Binding LblServerSettings}"
FontSize="15"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<!-- Server Input Mode Selection -->
<Grid ColumnDefinitions="180,*" ColumnSpacing="12">
@@ -296,14 +317,14 @@
</StackPanel>
<Border Height="1" Background="#E8E8E8" Margin="0,4"/>
<Border Height="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" Margin="0,4"/>
<!-- Auto-Login Settings Section -->
<StackPanel Spacing="12">
<TextBlock Text="{Binding LblAutoLoginSettings}"
FontSize="15"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<!-- Username -->
<Grid ColumnDefinitions="180,*" ColumnSpacing="12">
@@ -379,8 +400,8 @@
SelectedItems="{Binding SelectedJellyfinUsers}"
SelectionMode="Multiple"
MaxHeight="120"
Background="#FAFAFA"
BorderBrush="#E0E0E0"
Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="4"
Padding="4">
@@ -394,20 +415,20 @@
</Grid>
<TextBlock Text="{Binding LblUserSelectionHint}"
FontSize="11"
Foreground="#7F8C8D"
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"
FontStyle="Italic"
Margin="180,0,0,0"/>
</StackPanel>
</StackPanel>
<Border Height="1" Background="#E8E8E8" Margin="0,4"/>
<Border Height="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" Margin="0,4"/>
<!-- Advanced Settings Section -->
<StackPanel Spacing="12">
<TextBlock Text="{Binding LblAdvancedSettings}"
FontSize="15"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<!-- Dev Logs -->
<Grid ColumnDefinitions="180,*" ColumnSpacing="12">
@@ -466,7 +487,7 @@
<TextBlock Text="{Binding LblBrowserSettings}"
FontSize="15"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="12">
<TextBlock Grid.Column="0" Text="{Binding LblEnableBackdrops}" Classes="label" VerticalAlignment="Center"/>
@@ -513,7 +534,7 @@
<ToggleSwitch Grid.Column="1" IsChecked="{Binding SkipIntros}"/>
</Grid>
<Border Height="1" Background="#E8E8E8" Margin="0,4"/>
<Border Height="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" Margin="0,4"/>
<Grid ColumnDefinitions="180,*" ColumnSpacing="12">
<TextBlock Grid.Column="0" Text="{Binding LblAudioLanguagePreference}" Classes="label" VerticalAlignment="Center"/>
@@ -551,12 +572,12 @@
<TextBlock Text="{Binding LblCssSettings}"
FontSize="15"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<!-- CSS Hint -->
<TextBlock Text="{Binding LblCssHint}"
FontSize="12"
Foreground="#7F8C8D"
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"
TextWrapping="Wrap"/>
<!-- Custom CSS TextBox -->
@@ -602,8 +623,7 @@
FontWeight="SemiBold"/>
</Grid>
<Border Height="1" Background="#E8E8E8" Margin="0,16,0,8"/>
<Border Height="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" Margin="0,16,0,8"/>
<!-- JellyThemes Section -->
<StackPanel Spacing="8">
@@ -612,7 +632,7 @@
Text="{Binding LblJellyThemes}"
FontSize="15"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<Button Grid.Column="1"
Classes="secondary"
Command="{Binding OpenJellyThemesRepoCommand}"
@@ -627,7 +647,7 @@
<TextBlock Text="{Binding LblJellyThemesHint}"
FontSize="12"
Foreground="#7F8C8D"
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"
TextWrapping="Wrap"/>
<!-- Theme Buttons -->
@@ -665,8 +685,8 @@
<Border
Margin="0,12,0,0"
Padding="10"
Background="#FAFAFA"
BorderBrush="#E0E0E0"
Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="6"
IsVisible="{Binding HasSelectedJellyTheme}">
@@ -676,7 +696,7 @@
Text="{Binding SelectedJellyTheme.Name}"
FontSize="14"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<Image
Source="{Binding SelectedJellyThemePreview}"
@@ -686,7 +706,7 @@
<TextBlock
Text="Theme preview"
FontSize="11"
Foreground="#7F8C8D"/>
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"/>
</StackPanel>
</Border>

View File

@@ -8,8 +8,7 @@
Width="580"
Height="410"
WindowStartupLocation="CenterScreen"
Title="Jellyfin2Samsung"
Background="#F5F5F5">
Title="Jellyfin2Samsung">
<Window.Resources>
<helpers:TvLogStatusToBrushConverter x:Key="TvLogStatusToBrushConverter"/>
<helpers:StringEqualsConverter x:Key="StringEquals"/>
@@ -24,11 +23,11 @@
<StyleInclude Source="avares://Jellyfin2Samsung/Styles/ComboBoxes.axaml"/>
</Window.Styles>
<Border Background="White"
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
Padding="16"
CornerRadius="8"
Margin="6"
BorderBrush="#E8E8E8"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<Border.Effect>
@@ -163,6 +162,26 @@
<Button Classes="icon" Command="{Binding OpenSettingsCommand}">
<fa:SymbolIcon Symbol="Settings" Width="20" Height="20"/>
</Button>
<ToggleButton IsChecked="{Binding DarkMode}"
Background="Transparent"
BorderThickness="0"
Width="40"
Height="40"
CornerRadius="20"
Padding="0">
<ToggleButton.Styles>
<Style Selector="ToggleButton:checked">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="ToggleButton:pointerover">
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundBaseLowBrush}"/>
</Style>
</ToggleButton.Styles>
<Panel>
<TextBlock Text="&#x2600;" FontSize="18" IsVisible="{Binding DarkMode}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="&#x1F319;" FontSize="16" IsVisible="{Binding !DarkMode}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Panel>
</ToggleButton>
<Button Classes="icon"
IsVisible="{Binding IsSamsungLoginActive}"
Command="{Binding CancelSamsungLoginCommand}">
@@ -175,7 +194,7 @@
<!-- Clean footer -->
<TextBlock HorizontalAlignment="Center"
FontSize="11"
Foreground="#95A5A6"
Opacity="0.6"
Text="{Binding FooterText}"/>
</StackPanel>

View File

@@ -7,7 +7,6 @@
Width="900"
Height="650"
Title="Samsung TV Logs"
Background="#F5F5F5"
WindowStartupLocation="CenterOwner">
<!-- ========================= -->
@@ -48,11 +47,11 @@
<!-- ========================= -->
<!-- Layout -->
<!-- ========================= -->
<Border Background="White"
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
Padding="16"
CornerRadius="8"
Margin="12"
BorderBrush="#E8E8E8"
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
<StackPanel Spacing="16">
@@ -61,7 +60,7 @@
<TextBlock Text="TV Log Output"
FontSize="20"
FontWeight="SemiBold"
Foreground="#2C3E50"/>
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
<!-- Status + Endpoint -->
<StackPanel Orientation="Horizontal"
@@ -83,11 +82,11 @@
<!-- IP:Port -->
<TextBlock Text="{Binding EndpointText}"
FontSize="12"
Foreground="#555"/>
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"/>
</StackPanel>
<!-- Log output -->
<Border BorderBrush="#CCCCCC"
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
Background="#1E1E1E"
CornerRadius="4"