From 5357e14b062bba6072952708092af9c06f74d9b2 Mon Sep 17 00:00:00 2001 From: zarzet Date: Thu, 30 Jul 2026 14:42:26 +0700 Subject: [PATCH] fix(ui): refine track action spacing --- lib/screens/artist_screen_widgets.dart | 2 +- lib/screens/home_tab_widgets.dart | 2 +- lib/widgets/track_card.dart | 5 +++- .../track_collection_quick_actions.dart | 2 +- test/design_system_test.dart | 25 +++++++++++++++++++ test/preview_button_layout_test.dart | 18 +++++++++++++ 6 files changed, 50 insertions(+), 4 deletions(-) diff --git a/lib/screens/artist_screen_widgets.dart b/lib/screens/artist_screen_widgets.dart index c453d88d..fcfdcbe9 100644 --- a/lib/screens/artist_screen_widgets.dart +++ b/lib/screens/artist_screen_widgets.dart @@ -433,7 +433,7 @@ extension _ArtistScreenSections on _ArtistScreenState { hasLocalPlaybackCandidate: isInHistory || isInLocalLibrary, ), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + padding: const EdgeInsets.fromLTRB(16, 8, 10, 8), child: Row( children: [ SizedBox( diff --git a/lib/screens/home_tab_widgets.dart b/lib/screens/home_tab_widgets.dart index 6cf367fc..0fc95716 100644 --- a/lib/screens/home_tab_widgets.dart +++ b/lib/screens/home_tab_widgets.dart @@ -269,7 +269,7 @@ class _TrackItemWithStatus extends ConsumerWidget { splashColor: colorScheme.primary.withValues(alpha: 0.12), highlightColor: colorScheme.primary.withValues(alpha: 0.08), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + padding: const EdgeInsets.fromLTRB(12, 10, 6, 10), child: Row( children: [ ClipRRect( diff --git a/lib/widgets/track_card.dart b/lib/widgets/track_card.dart index 31f58e7a..38f67505 100644 --- a/lib/widgets/track_card.dart +++ b/lib/widgets/track_card.dart @@ -77,6 +77,9 @@ class TrackCard extends StatelessWidget { final theme = Theme.of(context); final colorScheme = theme.colorScheme; final borderRadius = tokens.borderRadiusCover; + final contentPadding = style == TrackCardStyle.flat + ? EdgeInsets.fromLTRB(tokens.gapMd, tokens.gapMd, 6, tokens.gapMd) + : EdgeInsets.all(tokens.gapMd); final Color? cardColor; if (isSelected) { @@ -111,7 +114,7 @@ class TrackCard extends StatelessWidget { children: [ if (background != null) Positioned.fill(child: background!), Padding( - padding: EdgeInsets.all(tokens.gapMd), + padding: contentPadding, child: Row( children: [ if (isSelectionMode) ...[ diff --git a/lib/widgets/track_collection_quick_actions.dart b/lib/widgets/track_collection_quick_actions.dart index 065e9621..30502198 100644 --- a/lib/widgets/track_collection_quick_actions.dart +++ b/lib/widgets/track_collection_quick_actions.dart @@ -59,7 +59,7 @@ class TrackCollectionQuickActions extends ConsumerWidget { track, hasLocalPlaybackCandidate: hasLocalPlaybackCandidate, ), - padding: const EdgeInsets.only(left: 12), + padding: EdgeInsets.zero, constraints: const BoxConstraints(minWidth: 48, minHeight: 48), ); } diff --git a/test/design_system_test.dart b/test/design_system_test.dart index c5088bd4..1baa8a25 100644 --- a/test/design_system_test.dart +++ b/test/design_system_test.dart @@ -431,6 +431,31 @@ void main() { expect(card.color, Colors.transparent); }); + testWidgets('flat style keeps trailing actions near the card edge', ( + tester, + ) async { + const trailingKey = Key('flat-trailing'); + await tester.pumpWidget( + host( + const SizedBox( + width: 320, + child: TrackCard( + leading: SizedBox(width: 24), + title: 'Song', + style: TrackCardStyle.flat, + trailing: SizedBox(key: trailingKey, width: 48, height: 48), + ), + ), + ), + ); + + final cardRect = tester.getRect(find.byType(Card)); + final trailingRect = tester.getRect(find.byKey(trailingKey)); + // Card's render box includes its 8dp flat-row margin; content itself is + // inset another 6dp from the painted card edge. + expect(cardRect.right - trailingRect.right, 14); + }); + testWidgets('grid variant is a real button with a semantic label', ( tester, ) async { diff --git a/test/preview_button_layout_test.dart b/test/preview_button_layout_test.dart index b839af4e..2dd06825 100644 --- a/test/preview_button_layout_test.dart +++ b/test/preview_button_layout_test.dart @@ -6,6 +6,7 @@ import 'package:spotiflac_android/l10n/l10n.dart'; import 'package:spotiflac_android/models/track.dart'; import 'package:spotiflac_android/providers/music_player_provider.dart'; import 'package:spotiflac_android/widgets/preview_button.dart'; +import 'package:spotiflac_android/widgets/track_collection_quick_actions.dart'; void main() { const track = Track( @@ -66,4 +67,21 @@ void main() { ); expectCenteredHitbox(tester, Icons.play_circle_fill_rounded); }); + + testWidgets('overflow menu icon is centered in its adjacent hitbox', ( + tester, + ) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold(body: TrackCollectionQuickActions(track: track)), + ), + ), + ); + await tester.pump(); + + expectCenteredHitbox(tester, Icons.more_vert); + }); }