feat: add server name display on hub titles

This commit is contained in:
edde746
2026-01-14 14:17:56 +01:00
parent 67a6bb29bf
commit 5cb4f79476
13 changed files with 122 additions and 12 deletions
+30 -2
View File
@@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 7
/// Strings: 3617 (516 per locale)
/// Strings: 3631 (518 per locale)
///
/// Built on 2026-01-09 at 12:57 UTC
/// Built on 2026-01-14 at 12:24 UTC
// coverage:ignore-file
// ignore_for_file: type=lint
@@ -320,6 +320,8 @@ class _StringsSettingsEn {
String get showHeroSection => 'Show Hero Section';
String get useGlobalHubs => 'Use Plex Home Layout';
String get useGlobalHubsDescription => 'Show home page hubs like the official Plex client. When off, shows per-library recommendations instead.';
String get showServerNameOnHubs => 'Show Server Name on Hubs';
String get showServerNameOnHubsDescription => 'Always display the server name in hub titles. When off, only shows for duplicate hub names.';
String get hardwareDecoding => 'Hardware Decoding';
String get hardwareDecodingDescription => 'Use hardware acceleration when available';
String get bufferSize => 'Buffer Size';
@@ -1202,6 +1204,8 @@ class _StringsSettingsDe implements _StringsSettingsEn {
@override String get showHeroSection => 'Hero-Bereich anzeigen';
@override String get useGlobalHubs => 'Plex-Startseiten-Layout verwenden';
@override String get useGlobalHubsDescription => 'Zeigt Startseiten-Hubs wie der offizielle Plex-Client. Wenn deaktiviert, werden stattdessen Empfehlungen pro Bibliothek angezeigt.';
@override String get showServerNameOnHubs => 'Servername bei Hubs anzeigen';
@override String get showServerNameOnHubsDescription => 'Zeigt immer den Servernamen in Hub-Titeln an. Wenn deaktiviert, nur bei doppelten Hub-Namen.';
@override String get hardwareDecoding => 'Hardware-Decodierung';
@override String get hardwareDecodingDescription => 'Hardwarebeschleunigung verwenden, sofern verfügbar';
@override String get bufferSize => 'Puffergröße';
@@ -2085,6 +2089,8 @@ class _StringsSettingsIt implements _StringsSettingsEn {
@override String get showHeroSection => 'Mostra sezione principale';
@override String get useGlobalHubs => 'Usa layout Home di Plex';
@override String get useGlobalHubsDescription => 'Mostra gli hub della home page come il client Plex ufficiale. Se disattivato, mostra invece i suggerimenti per libreria.';
@override String get showServerNameOnHubs => 'Mostra nome server sugli hub';
@override String get showServerNameOnHubsDescription => 'Mostra sempre il nome del server nei titoli degli hub. Se disattivato, solo per nomi hub duplicati.';
@override String get hardwareDecoding => 'Decodifica Hardware';
@override String get hardwareDecodingDescription => 'Utilizza l\'accelerazione hardware quando disponibile';
@override String get bufferSize => 'Dimensione buffer';
@@ -2968,6 +2974,8 @@ class _StringsSettingsKo implements _StringsSettingsEn {
@override String get showHeroSection => '주요 추천 영역 표시';
@override String get useGlobalHubs => 'Plex 홈 레이아웃 사용';
@override String get useGlobalHubsDescription => '공식 Plex 클라이언트처럼 홈 페이지 허브를 표시합니다. 끄면 라이브러리별 추천이 대신 표시됩니다.';
@override String get showServerNameOnHubs => '허브에 서버 이름 표시';
@override String get showServerNameOnHubsDescription => '허브 제목에 항상 서버 이름을 표시합니다. 끄면 중복된 허브 이름에만 표시됩니다.';
@override String get hardwareDecoding => '하드웨어 디코딩';
@override String get hardwareDecodingDescription => '가능한 경우 하드웨어 가속을 사용합니다';
@override String get bufferSize => '버퍼 크기';
@@ -3851,6 +3859,8 @@ class _StringsSettingsNl implements _StringsSettingsEn {
@override String get showHeroSection => 'Toon hoofdsectie';
@override String get useGlobalHubs => 'Plex Home-indeling gebruiken';
@override String get useGlobalHubsDescription => 'Toon startpagina-hubs zoals de officiële Plex-client. Indien uitgeschakeld, worden in plaats daarvan aanbevelingen per bibliotheek getoond.';
@override String get showServerNameOnHubs => 'Servernaam tonen bij hubs';
@override String get showServerNameOnHubsDescription => 'Toon altijd de servernaam in hub-titels. Indien uitgeschakeld, alleen bij dubbele hub-namen.';
@override String get hardwareDecoding => 'Hardware decodering';
@override String get hardwareDecodingDescription => 'Gebruik hardware versnelling indien beschikbaar';
@override String get bufferSize => 'Buffer grootte';
@@ -4734,6 +4744,8 @@ class _StringsSettingsSv implements _StringsSettingsEn {
@override String get showHeroSection => 'Visa hjältesektion';
@override String get useGlobalHubs => 'Använd Plex hem-layout';
@override String get useGlobalHubsDescription => 'Visar startsidans hubbar som den officiella Plex-klienten. När av visas rekommendationer per bibliotek istället.';
@override String get showServerNameOnHubs => 'Visa servernamn på hubbar';
@override String get showServerNameOnHubsDescription => 'Visa alltid servernamnet i hubbtitlar. När av visas endast för duplicerade hubbnamn.';
@override String get hardwareDecoding => 'Hårdvaruavkodning';
@override String get hardwareDecodingDescription => 'Använd hårdvaruacceleration när tillgängligt';
@override String get bufferSize => 'Bufferstorlek';
@@ -5617,6 +5629,8 @@ class _StringsSettingsZh implements _StringsSettingsEn {
@override String get showHeroSection => '显示主要精选区';
@override String get useGlobalHubs => '使用 Plex 主页布局';
@override String get useGlobalHubsDescription => '显示与官方 Plex 客户端相同的主页推荐。关闭时将显示按媒体库分类的推荐。';
@override String get showServerNameOnHubs => '在推荐栏显示服务器名称';
@override String get showServerNameOnHubsDescription => '始终在推荐栏标题中显示服务器名称。关闭时仅在推荐栏名称重复时显示。';
@override String get hardwareDecoding => '硬件解码';
@override String get hardwareDecodingDescription => '如果可用,使用硬件加速';
@override String get bufferSize => '缓冲区大小';
@@ -6395,6 +6409,8 @@ extension on Translations {
case 'settings.showHeroSection': return 'Show Hero Section';
case 'settings.useGlobalHubs': return 'Use Plex Home Layout';
case 'settings.useGlobalHubsDescription': return 'Show home page hubs like the official Plex client. When off, shows per-library recommendations instead.';
case 'settings.showServerNameOnHubs': return 'Show Server Name on Hubs';
case 'settings.showServerNameOnHubsDescription': return 'Always display the server name in hub titles. When off, only shows for duplicate hub names.';
case 'settings.hardwareDecoding': return 'Hardware Decoding';
case 'settings.hardwareDecodingDescription': return 'Use hardware acceleration when available';
case 'settings.bufferSize': return 'Buffer Size';
@@ -6919,6 +6935,8 @@ extension on _StringsDe {
case 'settings.showHeroSection': return 'Hero-Bereich anzeigen';
case 'settings.useGlobalHubs': return 'Plex-Startseiten-Layout verwenden';
case 'settings.useGlobalHubsDescription': return 'Zeigt Startseiten-Hubs wie der offizielle Plex-Client. Wenn deaktiviert, werden stattdessen Empfehlungen pro Bibliothek angezeigt.';
case 'settings.showServerNameOnHubs': return 'Servername bei Hubs anzeigen';
case 'settings.showServerNameOnHubsDescription': return 'Zeigt immer den Servernamen in Hub-Titeln an. Wenn deaktiviert, nur bei doppelten Hub-Namen.';
case 'settings.hardwareDecoding': return 'Hardware-Decodierung';
case 'settings.hardwareDecodingDescription': return 'Hardwarebeschleunigung verwenden, sofern verfügbar';
case 'settings.bufferSize': return 'Puffergröße';
@@ -7444,6 +7462,8 @@ extension on _StringsIt {
case 'settings.showHeroSection': return 'Mostra sezione principale';
case 'settings.useGlobalHubs': return 'Usa layout Home di Plex';
case 'settings.useGlobalHubsDescription': return 'Mostra gli hub della home page come il client Plex ufficiale. Se disattivato, mostra invece i suggerimenti per libreria.';
case 'settings.showServerNameOnHubs': return 'Mostra nome server sugli hub';
case 'settings.showServerNameOnHubsDescription': return 'Mostra sempre il nome del server nei titoli degli hub. Se disattivato, solo per nomi hub duplicati.';
case 'settings.hardwareDecoding': return 'Decodifica Hardware';
case 'settings.hardwareDecodingDescription': return 'Utilizza l\'accelerazione hardware quando disponibile';
case 'settings.bufferSize': return 'Dimensione buffer';
@@ -7969,6 +7989,8 @@ extension on _StringsKo {
case 'settings.showHeroSection': return '주요 추천 영역 표시';
case 'settings.useGlobalHubs': return 'Plex 홈 레이아웃 사용';
case 'settings.useGlobalHubsDescription': return '공식 Plex 클라이언트처럼 홈 페이지 허브를 표시합니다. 끄면 라이브러리별 추천이 대신 표시됩니다.';
case 'settings.showServerNameOnHubs': return '허브에 서버 이름 표시';
case 'settings.showServerNameOnHubsDescription': return '허브 제목에 항상 서버 이름을 표시합니다. 끄면 중복된 허브 이름에만 표시됩니다.';
case 'settings.hardwareDecoding': return '하드웨어 디코딩';
case 'settings.hardwareDecodingDescription': return '가능한 경우 하드웨어 가속을 사용합니다';
case 'settings.bufferSize': return '버퍼 크기';
@@ -8494,6 +8516,8 @@ extension on _StringsNl {
case 'settings.showHeroSection': return 'Toon hoofdsectie';
case 'settings.useGlobalHubs': return 'Plex Home-indeling gebruiken';
case 'settings.useGlobalHubsDescription': return 'Toon startpagina-hubs zoals de officiële Plex-client. Indien uitgeschakeld, worden in plaats daarvan aanbevelingen per bibliotheek getoond.';
case 'settings.showServerNameOnHubs': return 'Servernaam tonen bij hubs';
case 'settings.showServerNameOnHubsDescription': return 'Toon altijd de servernaam in hub-titels. Indien uitgeschakeld, alleen bij dubbele hub-namen.';
case 'settings.hardwareDecoding': return 'Hardware decodering';
case 'settings.hardwareDecodingDescription': return 'Gebruik hardware versnelling indien beschikbaar';
case 'settings.bufferSize': return 'Buffer grootte';
@@ -9019,6 +9043,8 @@ extension on _StringsSv {
case 'settings.showHeroSection': return 'Visa hjältesektion';
case 'settings.useGlobalHubs': return 'Använd Plex hem-layout';
case 'settings.useGlobalHubsDescription': return 'Visar startsidans hubbar som den officiella Plex-klienten. När av visas rekommendationer per bibliotek istället.';
case 'settings.showServerNameOnHubs': return 'Visa servernamn på hubbar';
case 'settings.showServerNameOnHubsDescription': return 'Visa alltid servernamnet i hubbtitlar. När av visas endast för duplicerade hubbnamn.';
case 'settings.hardwareDecoding': return 'Hårdvaruavkodning';
case 'settings.hardwareDecodingDescription': return 'Använd hårdvaruacceleration när tillgängligt';
case 'settings.bufferSize': return 'Bufferstorlek';
@@ -9544,6 +9570,8 @@ extension on _StringsZh {
case 'settings.showHeroSection': return '显示主要精选区';
case 'settings.useGlobalHubs': return '使用 Plex 主页布局';
case 'settings.useGlobalHubsDescription': return '显示与官方 Plex 客户端相同的主页推荐。关闭时将显示按媒体库分类的推荐。';
case 'settings.showServerNameOnHubs': return '在推荐栏显示服务器名称';
case 'settings.showServerNameOnHubsDescription': return '始终在推荐栏标题中显示服务器名称。关闭时仅在推荐栏名称重复时显示。';
case 'settings.hardwareDecoding': return '硬件解码';
case 'settings.hardwareDecodingDescription': return '如果可用,使用硬件加速';
case 'settings.bufferSize': return '缓冲区大小';
+2
View File
@@ -91,6 +91,8 @@
"showHeroSection": "Show Hero Section",
"useGlobalHubs": "Use Plex Home Layout",
"useGlobalHubsDescription": "Show home page hubs like the official Plex client. When off, shows per-library recommendations instead.",
"showServerNameOnHubs": "Show Server Name on Hubs",
"showServerNameOnHubsDescription": "Always display the server name in hub titles. When off, only shows for duplicate hub names.",
"hardwareDecoding": "Hardware Decoding",
"hardwareDecodingDescription": "Use hardware acceleration when available",
"bufferSize": "Buffer Size",
+2
View File
@@ -92,6 +92,8 @@
"showHeroSection": "Hero-Bereich anzeigen",
"useGlobalHubs": "Plex-Startseiten-Layout verwenden",
"useGlobalHubsDescription": "Zeigt Startseiten-Hubs wie der offizielle Plex-Client. Wenn deaktiviert, werden stattdessen Empfehlungen pro Bibliothek angezeigt.",
"showServerNameOnHubs": "Servername bei Hubs anzeigen",
"showServerNameOnHubsDescription": "Zeigt immer den Servernamen in Hub-Titeln an. Wenn deaktiviert, nur bei doppelten Hub-Namen.",
"hardwareDecoding": "Hardware-Decodierung",
"hardwareDecodingDescription": "Hardwarebeschleunigung verwenden, sofern verfügbar",
"bufferSize": "Puffergröße",
+2
View File
@@ -92,6 +92,8 @@
"showHeroSection": "Mostra sezione principale",
"useGlobalHubs": "Usa layout Home di Plex",
"useGlobalHubsDescription": "Mostra gli hub della home page come il client Plex ufficiale. Se disattivato, mostra invece i suggerimenti per libreria.",
"showServerNameOnHubs": "Mostra nome server sugli hub",
"showServerNameOnHubsDescription": "Mostra sempre il nome del server nei titoli degli hub. Se disattivato, solo per nomi hub duplicati.",
"hardwareDecoding": "Decodifica Hardware",
"hardwareDecodingDescription": "Utilizza l'accelerazione hardware quando disponibile",
"bufferSize": "Dimensione buffer",
+2
View File
@@ -92,6 +92,8 @@
"showHeroSection": "주요 추천 영역 표시",
"useGlobalHubs": "Plex 홈 레이아웃 사용",
"useGlobalHubsDescription": "공식 Plex 클라이언트처럼 홈 페이지 허브를 표시합니다. 끄면 라이브러리별 추천이 대신 표시됩니다.",
"showServerNameOnHubs": "허브에 서버 이름 표시",
"showServerNameOnHubsDescription": "허브 제목에 항상 서버 이름을 표시합니다. 끄면 중복된 허브 이름에만 표시됩니다.",
"hardwareDecoding": "하드웨어 디코딩",
"hardwareDecodingDescription": "가능한 경우 하드웨어 가속을 사용합니다",
"bufferSize": "버퍼 크기",
+2
View File
@@ -92,6 +92,8 @@
"showHeroSection": "Toon hoofdsectie",
"useGlobalHubs": "Plex Home-indeling gebruiken",
"useGlobalHubsDescription": "Toon startpagina-hubs zoals de officiële Plex-client. Indien uitgeschakeld, worden in plaats daarvan aanbevelingen per bibliotheek getoond.",
"showServerNameOnHubs": "Servernaam tonen bij hubs",
"showServerNameOnHubsDescription": "Toon altijd de servernaam in hub-titels. Indien uitgeschakeld, alleen bij dubbele hub-namen.",
"hardwareDecoding": "Hardware decodering",
"hardwareDecodingDescription": "Gebruik hardware versnelling indien beschikbaar",
"bufferSize": "Buffer grootte",
+2
View File
@@ -92,6 +92,8 @@
"showHeroSection": "Visa hjältesektion",
"useGlobalHubs": "Använd Plex hem-layout",
"useGlobalHubsDescription": "Visar startsidans hubbar som den officiella Plex-klienten. När av visas rekommendationer per bibliotek istället.",
"showServerNameOnHubs": "Visa servernamn på hubbar",
"showServerNameOnHubsDescription": "Visa alltid servernamnet i hubbtitlar. När av visas endast för duplicerade hubbnamn.",
"hardwareDecoding": "Hårdvaruavkodning",
"hardwareDecodingDescription": "Använd hårdvaruacceleration när tillgängligt",
"bufferSize": "Bufferstorlek",
+2
View File
@@ -92,6 +92,8 @@
"showHeroSection": "显示主要精选区",
"useGlobalHubs": "使用 Plex 主页布局",
"useGlobalHubsDescription": "显示与官方 Plex 客户端相同的主页推荐。关闭时将显示按媒体库分类的推荐。",
"showServerNameOnHubs": "在推荐栏显示服务器名称",
"showServerNameOnHubsDescription": "始终在推荐栏标题中显示服务器名称。关闭时仅在推荐栏名称重复时显示。",
"hardwareDecoding": "硬件解码",
"hardwareDecodingDescription": "如果可用,使用硬件加速",
"bufferSize": "缓冲区大小",
+13
View File
@@ -9,6 +9,7 @@ class SettingsProvider extends ChangeNotifier {
EpisodePosterMode _episodePosterMode = EpisodePosterMode.seriesPoster;
bool _showHeroSection = true;
bool _useGlobalHubs = true;
bool _showServerNameOnHubs = false;
bool _isInitialized = false;
Future<void>? _initFuture;
@@ -30,6 +31,7 @@ class SettingsProvider extends ChangeNotifier {
_episodePosterMode = _settingsService!.getEpisodePosterMode();
_showHeroSection = _settingsService!.getShowHeroSection();
_useGlobalHubs = _settingsService!.getUseGlobalHubs();
_showServerNameOnHubs = _settingsService!.getShowServerNameOnHubs();
_isInitialized = true;
notifyListeners();
}
@@ -47,6 +49,8 @@ class SettingsProvider extends ChangeNotifier {
bool get useGlobalHubs => _useGlobalHubs;
bool get showServerNameOnHubs => _showServerNameOnHubs;
Future<void> setLibraryDensity(LibraryDensity density) async {
if (!_isInitialized) await _initializeSettings();
if (_libraryDensity != density) {
@@ -92,6 +96,15 @@ class SettingsProvider extends ChangeNotifier {
}
}
Future<void> setShowServerNameOnHubs(bool value) async {
if (!_isInitialized) await _initializeSettings();
if (_showServerNameOnHubs != value) {
_showServerNameOnHubs = value;
await _settingsService!.setShowServerNameOnHubs(value);
notifyListeners();
}
}
String get libraryDensityDisplayName {
switch (_libraryDensity) {
case LibraryDensity.compact:
+16 -1
View File
@@ -489,8 +489,9 @@ class _DiscoverScreenState extends State<DiscoverScreen>
// Get hidden libraries for filtering
final hiddenLibrariesProvider = Provider.of<HiddenLibrariesProvider>(context, listen: false);
// Get settings for hub mode preference
// Get settings for hub mode preference (ensure initialized before accessing)
final settingsProvider = Provider.of<SettingsProvider>(context, listen: false);
await settingsProvider.ensureInitialized();
// Start OnDeck and hubs fetch in parallel
final onDeckFuture = multiServerProvider.aggregationService.getOnDeckFromAllServers(limit: 20);
@@ -698,6 +699,15 @@ class _DiscoverScreenState extends State<DiscoverScreen>
return Symbols.auto_awesome_rounded;
}
/// Get the set of hub titles that appear more than once (duplicates)
Set<String> _getDuplicateHubTitles() {
final titleCounts = <String, int>{};
for (final hub in _hubs) {
titleCounts[hub.title] = (titleCounts[hub.title] ?? 0) + 1;
}
return titleCounts.entries.where((e) => e.value > 1).map((e) => e.key).toSet();
}
@override
void updateItemInLists(String ratingKey, PlexMetadata updatedMetadata) {
// Check and update in _onDeck list
@@ -949,6 +959,10 @@ class _DiscoverScreenState extends State<DiscoverScreen>
@override
Widget build(BuildContext context) {
// Get settings for server name display
final showServerNameOnHubs = context.watch<SettingsProvider>().showServerNameOnHubs;
final duplicateHubTitles = _getDuplicateHubTitles();
return Scaffold(
body: Stack(
children: [
@@ -1008,6 +1022,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
key: i < _hubKeys.length ? _hubKeys[i] : null,
hub: _hubs[i],
icon: _getHubIcon(_hubs[i].title),
showServerName: showServerNameOnHubs || duplicateHubTitles.contains(_hubs[i].title),
onRefresh: updateItem,
// Hub index is i + 1 if continue watching exists, otherwise i
onVerticalNavigation: (isUp) => _handleVerticalNavigation(_onDeck.isNotEmpty ? i + 1 : i, isUp),
+13
View File
@@ -226,6 +226,19 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
},
),
Consumer<SettingsProvider>(
builder: (context, settingsProvider, child) {
return SwitchListTile(
secondary: const AppIcon(Symbols.dns_rounded, fill: 1),
title: Text(t.settings.showServerNameOnHubs),
subtitle: Text(t.settings.showServerNameOnHubsDescription),
value: settingsProvider.showServerNameOnHubs,
onChanged: (value) async {
await settingsProvider.setShowServerNameOnHubs(value);
},
);
},
),
],
),
);
+10
View File
@@ -34,6 +34,7 @@ class SettingsService extends BaseSharedPreferencesService {
static const String _keyMediaVersionPreferences = 'media_version_preferences';
static const String _keyShowHeroSection = 'show_hero_section';
static const String _keyUseGlobalHubs = 'use_global_hubs';
static const String _keyShowServerNameOnHubs = 'show_server_name_on_hubs';
static const String _keySleepTimerDuration = 'sleep_timer_duration';
static const String _keyAudioSyncOffset = 'audio_sync_offset';
static const String _keySubtitleSyncOffset = 'subtitle_sync_offset';
@@ -194,6 +195,15 @@ class SettingsService extends BaseSharedPreferencesService {
return prefs.getBool(_keyUseGlobalHubs) ?? true; // Default: true (use global hubs like official Plex)
}
// Show Server Name on Hubs (false = only on duplicates, true = always)
Future<void> setShowServerNameOnHubs(bool enabled) async {
await prefs.setBool(_keyShowServerNameOnHubs, enabled);
}
bool getShowServerNameOnHubs() {
return prefs.getBool(_keyShowServerNameOnHubs) ?? false; // Default: false (only show on duplicates)
}
// Seek Time Small (in seconds)
Future<void> setSeekTimeSmall(int seconds) async {
await prefs.setInt(_keySeekTimeSmall, seconds);
+26 -9
View File
@@ -30,6 +30,7 @@ class HubSection extends StatefulWidget {
final void Function(String)? onRefresh;
final VoidCallback? onRemoveFromContinueWatching;
final bool isInContinueWatching;
final bool showServerName;
/// Callback for vertical navigation (up/down). Return true if handled.
final bool Function(bool isUp)? onVerticalNavigation;
@@ -45,6 +46,7 @@ class HubSection extends StatefulWidget {
this.onRefresh,
this.onRemoveFromContinueWatching,
this.isInContinueWatching = false,
this.showServerName = false,
this.onVerticalNavigation,
this.onBack,
});
@@ -263,7 +265,7 @@ class HubSectionState extends State<HubSection> {
children: [
AppIcon(widget.icon, fill: 1),
const SizedBox(width: 8),
Expanded(
Flexible(
child: Text(
widget.hub.title,
style: Theme.of(context).textTheme.titleLarge,
@@ -271,6 +273,22 @@ class HubSectionState extends State<HubSection> {
maxLines: 1,
),
),
if (widget.showServerName && widget.hub.serverName != null) ...[
const SizedBox(width: 8),
Text(
'',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.7),
),
),
const SizedBox(width: 8),
Text(
widget.hub.serverName!,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.7),
),
),
],
if (widget.hub.more) ...[
const SizedBox(width: 4),
const AppIcon(Symbols.chevron_right_rounded, fill: 1, size: 20),
@@ -303,10 +321,8 @@ class HubSectionState extends State<HubSection> {
final episodePosterMode = context.watch<SettingsProvider>().episodePosterMode;
// Determine hub content type for layout decisions
final hasEpisodes = widget.hub.items.any((item) =>
item.usesWideAspectRatio(episodePosterMode));
final hasNonEpisodes = widget.hub.items.any((item) =>
!item.usesWideAspectRatio(episodePosterMode));
final hasEpisodes = widget.hub.items.any((item) => item.usesWideAspectRatio(episodePosterMode));
final hasNonEpisodes = widget.hub.items.any((item) => !item.usesWideAspectRatio(episodePosterMode));
// Mixed hub = has both episodes AND non-episodes (like Continue Watching)
final isMixedHub = hasEpisodes && hasNonEpisodes;
@@ -315,16 +331,17 @@ class HubSectionState extends State<HubSection> {
final isEpisodeOnlyHub = hasEpisodes && !hasNonEpisodes;
// Use 16:9 for episode-only hubs OR mixed hubs (with episode thumbnail mode)
final useWideLayout = episodePosterMode == EpisodePosterMode.episodeThumbnail &&
(isEpisodeOnlyHub || isMixedHub);
final useWideLayout =
episodePosterMode == EpisodePosterMode.episodeThumbnail && (isEpisodeOnlyHub || isMixedHub);
// Card dimensions based on hub type
const wideCardMultiplier = 1.5;
final cardWidth = useWideLayout ? baseCardWidth * wideCardMultiplier : baseCardWidth;
final posterWidth = cardWidth - 16; // 8px padding on each side
final posterHeight = useWideLayout
? posterWidth * (9 / 16) // 16:9 for wide layout
: posterWidth * 1.5; // 2:3 for poster layout
? posterWidth *
(9 / 16) // 16:9 for wide layout
: posterWidth * 1.5; // 2:3 for poster layout
final containerHeight = posterHeight + 66;
_itemExtent = cardWidth + 4;