fix: detail screen section alignment

This commit is contained in:
edde746
2026-04-12 01:37:08 +02:00
parent 1b2ecd9de4
commit 77893bb9ba
2 changed files with 18 additions and 10 deletions
+6 -3
View File
@@ -1836,7 +1836,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
if (key.isLeftKey) {
if (_focusedCastIndex > 0) {
setState(() => _focusedCastIndex--);
scrollListToIndex(_castScrollController, _focusedCastIndex, itemExtent: _getResponsiveCardWidth() + 8 + 4, leadingPadding: 0);
scrollListToIndex(_castScrollController, _focusedCastIndex, itemExtent: _getResponsiveCardWidth() + 6 + 4, leadingPadding: 0);
}
return KeyEventResult.handled;
}
@@ -1845,7 +1845,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
if (key.isRightKey) {
if (_focusedCastIndex < roleCount - 1) {
setState(() => _focusedCastIndex++);
scrollListToIndex(_castScrollController, _focusedCastIndex, itemExtent: _getResponsiveCardWidth() + 8 + 4, leadingPadding: 0);
scrollListToIndex(_castScrollController, _focusedCastIndex, itemExtent: _getResponsiveCardWidth() + 6 + 4, leadingPadding: 0);
}
return KeyEventResult.handled;
}
@@ -2651,6 +2651,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
key: _relatedHubKeys[i],
hub: _relatedHubs[i],
icon: _getRelatedHubIcon(_relatedHubs[i]),
inset: true,
onVerticalNavigation: (isUp) => _handleRelatedHubNavigation(i, isUp),
),
const SizedBox(height: 8),
@@ -2764,7 +2765,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
/// Uses same layout pattern as seasons/extras (ListView.builder + Padding(horizontal: 2))
Widget _buildCastSection(PlexMetadata metadata) {
final cardWidth = _getResponsiveCardWidth();
const innerPadding = 4.0;
const innerPadding = 3.0;
final imageSize = cardWidth;
// image + inner padding + text area + outer list padding + focus scale headroom
final containerHeight = imageSize + innerPadding * 2 + 66 + 16;
@@ -2782,6 +2783,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
builder: (scrollController) => ListView.builder(
controller: scrollController,
scrollDirection: Axis.horizontal,
clipBehavior: Clip.none,
padding: const EdgeInsets.symmetric(vertical: 5),
itemCount: metadata.role!.length,
itemBuilder: (context, index) {
@@ -2870,6 +2872,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
builder: (scrollController) => ListView.builder(
controller: scrollController,
scrollDirection: Axis.horizontal,
clipBehavior: Clip.none,
padding: const EdgeInsets.symmetric(vertical: 5),
itemCount: _extras!.length,
itemBuilder: (context, index) {
+12 -7
View File
@@ -54,6 +54,10 @@ class HubSection extends StatefulWidget {
/// Used to navigate focus to the sidebar.
final VoidCallback? onNavigateToSidebar;
/// When true, removes internal horizontal padding (header + list).
/// Use when the parent already provides edge spacing (e.g. inside Padding(16)).
final bool inset;
const HubSection({
super.key,
required this.hub,
@@ -66,6 +70,7 @@ class HubSection extends StatefulWidget {
this.onBack,
this.onNavigateUp,
this.onNavigateToSidebar,
this.inset = false,
});
@override
@@ -83,7 +88,7 @@ class HubSectionState extends State<HubSection> {
/// Item extent for scroll calculations
double _itemExtent = 0;
static const double _leadingPadding = 12.0;
double get _leadingPadding => widget.inset ? 0.0 : 12.0;
Timer? _longPressTimer;
bool _isSelectKeyDown = false;
@@ -326,13 +331,13 @@ class HubSectionState extends State<HubSection> {
children: [
// Hub header (NOT focusable - titles should not be focusable)
Padding(
padding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
padding: widget.inset ? const EdgeInsets.symmetric(vertical: 2) : const EdgeInsets.fromLTRB(8, 2, 8, 2),
child: ExcludeFocus(
child: InkWell(
onTap: widget.hub.more ? () => _navigateToHubDetail(context) : null,
borderRadius: BorderRadius.circular(tokens(context).radiusSm),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
padding: widget.inset ? const EdgeInsets.symmetric(vertical: 2) : const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
@@ -422,7 +427,7 @@ class HubSectionState extends State<HubSection> {
controller: scrollController,
scrollDirection: Axis.horizontal,
clipBehavior: Clip.none,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
padding: widget.inset ? const EdgeInsets.symmetric(vertical: 2) : const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
itemCount: isKeyboardMode ? _totalItemCount : widget.hub.items.length,
itemBuilder: (context, index) {
final isItemFocused = hasFocus && index == _focusedIndex;
@@ -430,7 +435,7 @@ class HubSectionState extends State<HubSection> {
// "View All" card at end
if (index == widget.hub.items.length) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
padding: widget.inset ? const EdgeInsets.only(right: 4) : const EdgeInsets.symmetric(horizontal: 2),
child: FocusBuilders.buildLockedFocusWrapper(
context: context,
isFocused: isItemFocused,
@@ -468,7 +473,7 @@ class HubSectionState extends State<HubSection> {
final item = widget.hub.items[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
padding: widget.inset ? const EdgeInsets.only(right: 4) : const EdgeInsets.symmetric(horizontal: 2),
child: FocusBuilders.buildLockedFocusWrapper(
context: context,
isFocused: isItemFocused,
@@ -496,7 +501,7 @@ class HubSectionState extends State<HubSection> {
)
else
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: widget.inset ? const EdgeInsets.symmetric(vertical: 8) : const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(
t.messages.noItemsAvailable,
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.grey),