Files
bvandeusen c8baaa5329 feat(flutter): wire TrackActionsButton into 4 surfaces
- TrackRow gains an actions: bool = true param; renders the button
  after duration. Album detail + Search + History/Liked tabs all
  consume TrackRow so they pick up the menu transitively.
- CompactTrackCard (home Most-played) gets the button at the end of
  its inner row.
- _PlaylistTrackRow in playlist_detail_screen gets the button next
  to duration; skipped for unavailable rows (no track id).
- NowPlayingScreen renders the button next to the title with
  hideQueueActions: true (Play next / Add to queue suppressed since
  the menu's track IS the playing one). artistId is left empty since
  it's not stashed in MediaItem.extras — Go-to-artist will route to
  /artists/ which is benign for v1; a follow-up could stash it.

Closes Tier 1 follow-up #2 (track-level actions menu).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 13:43:12 -04:00

85 lines
2.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../models/track.dart';
import '../../player/player_provider.dart';
import '../../shared/widgets/server_image.dart';
import '../../shared/widgets/track_actions/track_actions_button.dart';
import '../../theme/theme_extension.dart';
/// Small horizontal track cell used by the home Most-played section.
/// Mirrors the web CompactTrackCard sizing (~176dp wide, ~56dp tall).
/// Tap plays from this track within [sectionTracks] starting at [index].
class CompactTrackCard extends ConsumerWidget {
const CompactTrackCard({
super.key,
required this.track,
required this.sectionTracks,
required this.index,
});
final TrackRef track;
/// All tracks in the home section so play-from-here can queue them
/// in order.
final List<TrackRef> sectionTracks;
final int index;
@override
Widget build(BuildContext context, WidgetRef ref) {
final fs = Theme.of(context).extension<FabledSwordTheme>()!;
// Cover URL derives from the track's album. Mirrors web
// CompactTrackCard which calls coverUrl(track.album_id).
final coverUrl = track.albumId.isNotEmpty
? '/api/albums/${track.albumId}/cover'
: '';
return SizedBox(
width: 176,
child: InkWell(
onTap: () => ref
.read(playerActionsProvider)
.playTracks(sectionTracks, initialIndex: index),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Row(children: [
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: SizedBox(
width: 48,
height: 48,
child: ServerImage(
url: coverUrl,
fit: BoxFit.cover,
fallback: Container(color: fs.slate),
),
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
track.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: fs.parchment, fontSize: 13),
),
Text(
track.artistName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: fs.ash, fontSize: 11),
),
],
),
),
TrackActionsButton(track: track),
]),
),
),
);
}
}