artist list with images

This commit is contained in:
austinried
2025-11-09 15:48:20 +09:00
parent ee2a276f2f
commit d18ca13f48
12 changed files with 374 additions and 41 deletions

View File

@@ -10,7 +10,7 @@ import '../state/database.dart';
import '../state/settings.dart';
import 'list_items.dart';
const kPageSize = 30;
const kPageSize = 60;
class AlbumsGrid extends HookConsumerWidget {
const AlbumsGrid({super.key});

View File

@@ -0,0 +1,81 @@
import 'package:drift/drift.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import '../../sources/models.dart';
import '../hooks/use_paging_controller.dart';
import '../state/database.dart';
import '../state/settings.dart';
import 'list_items.dart';
const kPageSize = 30;
typedef _ArtistItem = ({Artist artist, int? albumCount});
class ArtistsList extends HookConsumerWidget {
const ArtistsList({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final db = ref.watch(databaseProvider);
final sourceId = ref.watch(sourceIdProvider);
final controller = usePagingController<int, _ArtistItem>(
getNextPageKey: (state) =>
state.lastPageIsEmpty ? null : state.nextIntPageKey,
fetchPage: (pageKey) async {
final albumCount = db.albums.id.count();
final query =
db.artists.select().join([
leftOuterJoin(
db.albums,
db.albums.artistId.equalsExp(db.artists.id),
),
])
..addColumns([albumCount])
..where(
db.artists.sourceId.equals(sourceId) &
db.albums.sourceId.equals(sourceId),
)
..groupBy([db.artists.sourceId, db.artists.id])
..orderBy([OrderingTerm.asc(db.artists.name)])
..limit(kPageSize, offset: (pageKey - 1) * kPageSize);
return (await query.get())
.map(
(row) => (
artist: row.readTable(db.artists),
albumCount: row.read(albumCount),
),
)
.toList();
},
);
return PagingListener(
controller: controller,
builder: (context, state, fetchNextPage) {
return PagedSliverList(
state: state,
fetchNextPage: fetchNextPage,
builderDelegate: PagedChildBuilderDelegate<_ArtistItem>(
itemBuilder: (context, item, index) {
final (:artist, :albumCount) = item;
return ArtistListTile(
artist: artist,
albumCount: albumCount,
onTap: () async {
context.push('/artist/${artist.id}');
},
);
},
),
);
},
);
}
}

View File

@@ -1,4 +1,3 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -33,19 +32,28 @@ class AlbumGridTile extends HookConsumerWidget {
}
class ArtistListTile extends StatelessWidget {
const ArtistListTile({super.key});
const ArtistListTile({
super.key,
required this.artist,
this.albumCount,
this.onTap,
});
final Artist artist;
final int? albumCount;
final void Function()? onTap;
@override
Widget build(BuildContext context) {
return ListTile(
leading: CircleClip(
child: CachedNetworkImage(
imageUrl: 'https://placehold.net/400x400.png',
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
),
child: artist.coverArt != null
? CoverArtImage(coverArt: artist.coverArt)
: CachedImage(artist.smallImage),
),
title: Text('Some Artist'),
title: Text(artist.name),
subtitle: albumCount != null ? Text('$albumCount albums') : null,
onTap: onTap,
);
}
}

View File

@@ -3,7 +3,7 @@ import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:material_symbols_icons/symbols.dart';
import '../lists/albums_grid.dart';
import '../lists/artists_list.dart';
import '../state/services.dart';
import '../util/custom_scroll_fix.dart';
@@ -210,7 +210,7 @@ class _NewWidgetState extends State<NewWidget>
),
SliverPadding(
padding: const EdgeInsets.all(8.0),
sliver: AlbumsGrid(),
sliver: ArtistsList(),
),
],
);