@@ -1168,7 +1168,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: -32, // Extend 32px past the hero section bounds
|
||||
bottom: -2, // Minimal overflow to avoid gap without covering hub header
|
||||
height: 80, // Tall enough to cover any gap
|
||||
child: IgnorePointer(
|
||||
child: Builder(
|
||||
|
||||
@@ -73,7 +73,7 @@ class AdaptiveMediaGrid<T> extends StatelessWidget {
|
||||
}
|
||||
|
||||
// Extra top padding for focus decoration (scale + border extends beyond item bounds)
|
||||
static const double _focusDecorationPadding = 8.0;
|
||||
static const double _focusDecorationPadding = 3.0;
|
||||
|
||||
/// Navigate focus to the sidebar
|
||||
void _navigateToSidebar(BuildContext context) {
|
||||
|
||||
@@ -131,7 +131,7 @@ class _LibraryRecommendedTabState extends BaseLibraryTabState<PlexHub, LibraryRe
|
||||
_ensureHubKeys(items.length);
|
||||
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.fromLTRB(0, 8 + _focusDecorationPadding, 0, 8),
|
||||
padding: const EdgeInsets.fromLTRB(0, _focusDecorationPadding, 0, 8),
|
||||
// Allow focus decoration to render outside scroll bounds
|
||||
clipBehavior: Clip.none,
|
||||
itemCount: items.length,
|
||||
|
||||
@@ -79,5 +79,5 @@ class GridLayoutConstants {
|
||||
static const double mainAxisSpacing = 0;
|
||||
|
||||
/// Standard grid padding
|
||||
static EdgeInsets get gridPadding => const EdgeInsets.only(left: 8, right: 8, bottom: 8);
|
||||
static EdgeInsets get gridPadding => const EdgeInsets.only(left: 2, right: 2, bottom: 2);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:plezy/widgets/app_icon.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../focus/dpad_navigator.dart';
|
||||
import '../focus/focus_theme.dart';
|
||||
import '../focus/input_mode_tracker.dart';
|
||||
import '../focus/key_event_utils.dart';
|
||||
import '../providers/settings_provider.dart';
|
||||
@@ -325,13 +326,13 @@ class HubSectionState extends State<HubSection> {
|
||||
children: [
|
||||
// Hub header (NOT focusable - titles should not be focusable)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 24, 16, 8),
|
||||
padding: const EdgeInsets.fromLTRB(8, 12, 8, 4),
|
||||
child: ExcludeFocus(
|
||||
child: InkWell(
|
||||
onTap: widget.hub.more ? () => _navigateToHubDetail(context) : null,
|
||||
borderRadius: BorderRadius.circular(tokens(context).radiusSm),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 6),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -420,23 +421,26 @@ class HubSectionState extends State<HubSection> {
|
||||
// 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 posterWidth = cardWidth - 6; // 3px padding on each side
|
||||
final posterHeight = useWideLayout
|
||||
? posterWidth *
|
||||
(9 / 16) // 16:9 for wide layout
|
||||
: posterWidth * 1.5; // 2:3 for poster layout
|
||||
|
||||
final containerHeight = posterHeight + 66;
|
||||
_itemExtent = cardWidth + 4;
|
||||
final containerHeight = posterHeight + 48;
|
||||
final focusBorderWidth = FocusTheme.focusBorderWidth;
|
||||
final focusExtra = focusBorderWidth * 2; // border on both sides
|
||||
_itemExtent = cardWidth + focusExtra + 4;
|
||||
|
||||
return SizedBox(
|
||||
height: containerHeight,
|
||||
height: containerHeight + focusExtra + 4, // extra for scale + border top/bottom
|
||||
child: HorizontalScrollWithArrows(
|
||||
controller: _scrollController,
|
||||
builder: (scrollController) => ListView.builder(
|
||||
controller: scrollController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
|
||||
clipBehavior: Clip.none,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
itemCount: isKeyboardMode ? _totalItemCount : widget.hub.items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final isItemFocused = hasFocus && index == _focusedIndex;
|
||||
|
||||
@@ -218,7 +218,7 @@ class MediaCardState extends State<MediaCard> {
|
||||
Widget _buildGridCard(BuildContext context, String semanticLabel, String? localPosterPath) {
|
||||
final item = widget.item;
|
||||
// Compute actual poster dimensions from card dimensions
|
||||
final posterWidth = widget.width != null ? widget.width! - 16 : null; // 8px padding each side
|
||||
final posterWidth = widget.width != null ? widget.width! - 6 : null; // 3px padding each side
|
||||
final posterHeight = widget.height;
|
||||
|
||||
return SizedBox(
|
||||
@@ -232,7 +232,7 @@ class MediaCardState extends State<MediaCard> {
|
||||
onSecondaryTap: _showContextMenu,
|
||||
borderRadius: BorderRadius.circular(tokens(context).radiusSm),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
padding: const EdgeInsets.all(3),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -278,7 +278,7 @@ class MediaCardState extends State<MediaCard> {
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const SizedBox(height: 2),
|
||||
// Title (flattened — no inner Column)
|
||||
Text(
|
||||
item is PlexPlaylist ? item.title : (item as PlexMetadata).displayTitle,
|
||||
|
||||
Reference in New Issue
Block a user