983a9d92be
Track row (album detail): - Vertical padding 10→6 and only render the artist line when non-empty, so tracks without a populated artist row don't reserve a blank line. - Number column 28→22 — visually tighter without making 3-digit numbers cramp. Mini player missing artist: - Symptom was an empty `artist` field on MediaItem after tapping a track in album detail; layout change wasn't the cause. Real cause: albumProvider's cold-cache only wrote cachedAlbums + cachedTracks, never cachedArtists. The drift JOINs that build the AlbumRef + each TrackRef returned null for the artist row, so artistName fell back to '' and the audio handler stamped MediaItem.artist=''. - Cold-cache now collects every distinct (artistId, artistName) pair off the album header + each track, inserts them into cachedArtists alongside the album/tracks. Subsequent JOINs populate artistName, the audio handler stamps it on MediaItem, and the mini player picks it up via the existing artistName.isNotEmpty render. - Existing cached albums won't get artist names until they're re-fetched (cache invalidation TBD). Future cold-cache hits will. Artist detail album grid: - AlbumCard gains showArtist (default true). Pass false in the artist detail grid since the page header already names the artist. cellH trimmed by the 16dp artist line.
84 lines
2.7 KiB
Dart
84 lines
2.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_svg/flutter_svg.dart';
|
|
|
|
import '../../models/album.dart';
|
|
import '../../shared/widgets/server_image.dart';
|
|
import '../../theme/theme_extension.dart';
|
|
|
|
class AlbumCard extends StatelessWidget {
|
|
const AlbumCard({
|
|
required this.album,
|
|
required this.onTap,
|
|
this.width = 140,
|
|
this.titleMaxLines = 1,
|
|
this.showArtist = true,
|
|
super.key,
|
|
});
|
|
final AlbumRef album;
|
|
final VoidCallback onTap;
|
|
|
|
/// Outer width of the card. Cover is square at width - 16 (8dp
|
|
/// horizontal padding either side). Default suits horizontal lists;
|
|
/// grids should pass the cell width so the card scales down.
|
|
final double width;
|
|
|
|
/// Lets callers (e.g. the artist detail grid) allow the title to
|
|
/// wrap to a second line so it isn't truncated to a single
|
|
/// ellipsized character at narrower widths.
|
|
final int titleMaxLines;
|
|
|
|
/// Suppress the artist name. Useful on surfaces where the artist is
|
|
/// already implied by the page header (e.g. artist detail).
|
|
final bool showArtist;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final fs = Theme.of(context).extension<FabledSwordTheme>()!;
|
|
final coverSize = width - 16;
|
|
return SizedBox(
|
|
width: width,
|
|
child: Material(
|
|
color: Colors.transparent,
|
|
child: InkWell(
|
|
onTap: onTap,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.circular(6),
|
|
child: Container(
|
|
width: coverSize,
|
|
height: coverSize,
|
|
color: fs.slate,
|
|
child: album.coverUrl.isEmpty
|
|
? SvgPicture.asset('assets/svg/album-fallback.svg',
|
|
fit: BoxFit.cover)
|
|
: ServerImage(url: album.coverUrl, fit: BoxFit.cover),
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
album.title,
|
|
maxLines: titleMaxLines,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(color: fs.parchment, fontSize: 14),
|
|
),
|
|
if (showArtist && album.artistName.isNotEmpty)
|
|
Text(
|
|
album.artistName,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(color: fs.ash, fontSize: 12),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|