diff --git a/lib/screens/focusable_detail_screen_mixin.dart b/lib/screens/focusable_detail_screen_mixin.dart index d58825b6..81fb8f36 100644 --- a/lib/screens/focusable_detail_screen_mixin.dart +++ b/lib/screens/focusable_detail_screen_mixin.dart @@ -4,6 +4,7 @@ import '../focus/focusable_action_bar.dart'; import '../focus/input_mode_tracker.dart'; import '../mixins/grid_focus_node_mixin.dart'; import '../providers/settings_provider.dart'; +import '../services/settings_service.dart' show ViewMode; import '../utils/grid_size_calculator.dart'; import '../widgets/focusable_media_card.dart'; import '../widgets/media_grid_delegate.dart'; @@ -130,6 +131,36 @@ mixin FocusableDetailScreenMixin on State, GridFocu }) { return Consumer( builder: (context, settingsProvider, child) { + final isListMode = settingsProvider.viewMode == ViewMode.list; + + if (isListMode) { + return SliverPadding( + padding: const EdgeInsets.all(8), + sliver: SliverList.builder( + itemCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + final focusNode = index == 0 + ? firstItemFocusNode + : getGridItemFocusNode(index, prefix: 'detail_grid_item'); + + return FocusableMediaCard( + key: Key(item.ratingKey), + item: item, + focusNode: focusNode, + disableScale: true, + onRefresh: onRefresh, + collectionId: collectionId, + onListRefresh: onListRefresh, + onNavigateUp: index == 0 ? navigateToAppBar : null, + onBack: handleBackFromContent, + onFocusChange: (hasFocus) => trackGridItemFocus(index, hasFocus), + ); + }, + ), + ); + } + final maxExtent = GridSizeCalculator.getMaxCrossAxisExtent(context, settingsProvider.libraryDensity); return SliverPadding( padding: const EdgeInsets.all(8), diff --git a/lib/screens/hub_detail_screen.dart b/lib/screens/hub_detail_screen.dart index 31638738..d8d20ce9 100644 --- a/lib/screens/hub_detail_screen.dart +++ b/lib/screens/hub_detail_screen.dart @@ -319,6 +319,7 @@ class _HubDetailScreenState extends State Builder( builder: (context) { final settings = context.watch(); + final isListMode = settings.viewMode == ViewMode.list; final episodePosterMode = settings.episodePosterMode; // Determine hub content type for layout decisions @@ -335,6 +336,32 @@ class _HubDetailScreenState extends State final useWideLayout = episodePosterMode == EpisodePosterMode.episodeThumbnail && (isEpisodeOnlyHub || isMixedHub); + if (isListMode) { + return SliverPadding( + padding: const EdgeInsets.all(8), + sliver: SliverList.builder( + itemCount: _filteredItems.length, + itemBuilder: (context, index) { + final item = _filteredItems[index]; + final focusNode = index == 0 + ? firstItemFocusNode + : getGridItemFocusNode(index, prefix: 'hub_detail_item'); + + return FocusableMediaCard( + focusNode: focusNode, + item: item, + disableScale: true, + onRefresh: _handleItemRefresh, + onNavigateUp: index == 0 ? navigateToAppBar : null, + onBack: handleBackFromContent, + onFocusChange: (hasFocus) => trackGridItemFocus(index, hasFocus), + mixedHubContext: isMixedHub, + ); + }, + ), + ); + } + return SliverPadding( padding: const EdgeInsets.all(8), sliver: SliverLayoutBuilder( diff --git a/lib/screens/libraries/adaptive_media_grid.dart b/lib/screens/libraries/adaptive_media_grid.dart index de582d8b..90b826c3 100644 --- a/lib/screens/libraries/adaptive_media_grid.dart +++ b/lib/screens/libraries/adaptive_media_grid.dart @@ -14,10 +14,13 @@ class GridItemContext { /// Whether this item is in the first column of the grid. final bool isFirstColumn; + /// Whether items are displayed in list mode (single column). + final bool isListMode; + /// Callback to navigate to the sidebar (for first-column items). final VoidCallback? navigateToSidebar; - const GridItemContext({required this.isFirstRow, required this.isFirstColumn, this.navigateToSidebar}); + const GridItemContext({required this.isFirstRow, required this.isFirstColumn, this.isListMode = false, this.navigateToSidebar}); } /// A widget that automatically switches between grid and list view @@ -99,6 +102,7 @@ class AdaptiveMediaGrid extends StatelessWidget { ? GridItemContext( isFirstRow: index == 0, isFirstColumn: true, // List view = single column + isListMode: true, navigateToSidebar: () => _navigateToSidebar(context), ) : null; diff --git a/lib/screens/libraries/tabs/library_browse_tab.dart b/lib/screens/libraries/tabs/library_browse_tab.dart index 732920b8..05247a6a 100644 --- a/lib/screens/libraries/tabs/library_browse_tab.dart +++ b/lib/screens/libraries/tabs/library_browse_tab.dart @@ -1214,6 +1214,7 @@ class _LibraryBrowseTabState extends BaseLibraryTabState { onBack: widget.onBack, onFocusChange: widget.onFocusChange, enableLongPress: true, + disableScale: widget.disableScale, useComfortableZone: !PlatformDetector.isTV(), // Always center on TV scrollAlignment: 0.5, child: MediaCard(