import 'package:flutter/material.dart'; import '../models/plex_hub.dart'; import '../screens/hub_detail_screen.dart'; import 'media_card.dart'; import 'horizontal_scroll_with_arrows.dart'; import '../i18n/strings.g.dart'; /// Shared hub section widget used in both discover and library screens /// Displays a hub title with icon and a horizontal scrollable list of items class HubSection extends StatelessWidget { final PlexHub hub; final IconData icon; final void Function(String)? onRefresh; final VoidCallback? onRemoveFromContinueWatching; final bool isInContinueWatching; const HubSection({ super.key, required this.hub, required this.icon, this.onRefresh, this.onRemoveFromContinueWatching, this.isInContinueWatching = false, }); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ // Hub header Padding( padding: const EdgeInsets.fromLTRB(16, 24, 16, 8), child: InkWell( onTap: hub.more ? () { Navigator.push( context, MaterialPageRoute( builder: (context) => HubDetailScreen(hub: hub), ), ); } : null, borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: Row( children: [ Icon(icon), const SizedBox(width: 8), Text( hub.title, style: Theme.of(context).textTheme.titleLarge, ), if (hub.more) ...[ const SizedBox(width: 4), const Icon(Icons.chevron_right, size: 20), ], ], ), ), ), ), // Hub items (horizontal scroll) if (hub.items.isNotEmpty) LayoutBuilder( builder: (context, constraints) { // Responsive card width based on screen size final screenWidth = constraints.maxWidth; final cardWidth = screenWidth > 1600 ? 220.0 : screenWidth > 1200 ? 200.0 : screenWidth > 800 ? 190.0 : 160.0; // MediaCard has 8px padding on all sides (16px total horizontally) // So actual poster width is cardWidth - 16 final posterWidth = cardWidth - 16; // 2:3 poster aspect ratio (height is 1.5x width) final posterHeight = posterWidth * 1.5; // Container height = poster + padding + spacing + text // 8px top padding + posterHeight + 4px spacing + ~26px text + 8px bottom padding final containerHeight = posterHeight + 46; return SizedBox( height: containerHeight, child: HorizontalScrollWithArrows( builder: (scrollController) => ListView.builder( controller: scrollController, scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 12), itemCount: hub.items.length, itemBuilder: (context, index) { final item = hub.items[index]; return Padding( padding: const EdgeInsets.symmetric(horizontal: 2), child: MediaCard( key: Key(item.ratingKey), item: item, width: cardWidth, height: posterHeight, onRefresh: onRefresh, onRemoveFromContinueWatching: onRemoveFromContinueWatching, forceGridMode: true, isInContinueWatching: isInContinueWatching, ), ); }, ), ), ); }, ) else Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Text( t.messages.noItemsAvailable, style: Theme.of( context, ).textTheme.bodySmall?.copyWith(color: Colors.grey), ), ), ], ); } }