mirror of
https://github.com/austinried/subtracks.git
synced 2026-02-10 15:02:42 +01:00
artist screen
This commit is contained in:
@@ -10,14 +10,14 @@ class CoverArtImage extends HookConsumerWidget {
|
||||
super.key,
|
||||
this.coverArt,
|
||||
this.thumbnail = true,
|
||||
this.fit,
|
||||
this.fit = BoxFit.cover,
|
||||
this.height,
|
||||
this.width,
|
||||
});
|
||||
|
||||
final String? coverArt;
|
||||
final bool thumbnail;
|
||||
final BoxFit? fit;
|
||||
final BoxFit fit;
|
||||
final double? height;
|
||||
final double? width;
|
||||
|
||||
@@ -37,7 +37,7 @@ class CoverArtImage extends HookConsumerWidget {
|
||||
cacheKey: '$sourceId$coverArt$thumbnail',
|
||||
placeholder: (context, url) => Icon(Symbols.cached_rounded),
|
||||
errorWidget: (context, url, error) => Icon(Icons.error),
|
||||
fit: BoxFit.cover,
|
||||
fit: fit,
|
||||
fadeOutDuration: Duration(milliseconds: 100),
|
||||
fadeInDuration: Duration(milliseconds: 200),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -15,7 +14,12 @@ import 'items.dart';
|
||||
const kPageSize = 60;
|
||||
|
||||
class AlbumsGrid extends HookConsumerWidget {
|
||||
const AlbumsGrid({super.key});
|
||||
const AlbumsGrid({
|
||||
super.key,
|
||||
required this.query,
|
||||
});
|
||||
|
||||
final AlbumsQuery query;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -24,11 +28,8 @@ class AlbumsGrid extends HookConsumerWidget {
|
||||
getNextPageKey: (state) =>
|
||||
state.lastPageIsEmpty ? null : state.nextIntPageKey,
|
||||
fetchPage: (pageKey) => db.libraryDao.listAlbums(
|
||||
AlbumsQuery(
|
||||
query.copyWith(
|
||||
sourceId: ref.read(sourceIdProvider),
|
||||
sort: IList([
|
||||
SortingTerm.albumsDesc(AlbumsColumn.created),
|
||||
]),
|
||||
limit: kPageSize,
|
||||
offset: (pageKey - 1) * kPageSize,
|
||||
),
|
||||
|
||||
90
lib/app/ui/lists/albums_list.dart
Normal file
90
lib/app/ui/lists/albums_list.dart
Normal file
@@ -0,0 +1,90 @@
|
||||
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 '../../../database/query.dart';
|
||||
import '../../../sources/models.dart';
|
||||
import '../../hooks/use_on_source.dart';
|
||||
import '../../hooks/use_paging_controller.dart';
|
||||
import '../../state/database.dart';
|
||||
import '../../state/source.dart';
|
||||
import 'items.dart';
|
||||
|
||||
const kPageSize = 30;
|
||||
|
||||
class AlbumsList extends HookConsumerWidget {
|
||||
const AlbumsList({
|
||||
super.key,
|
||||
required this.query,
|
||||
});
|
||||
|
||||
final AlbumsQuery query;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final db = ref.watch(databaseProvider);
|
||||
final controller = usePagingController<int, Album>(
|
||||
getNextPageKey: (state) =>
|
||||
state.lastPageIsEmpty ? null : state.nextIntPageKey,
|
||||
fetchPage: (pageKey) => db.libraryDao.listAlbums(
|
||||
query.copyWith(
|
||||
sourceId: ref.read(sourceIdProvider),
|
||||
limit: kPageSize,
|
||||
offset: (pageKey - 1) * kPageSize,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
useOnSourceChange(ref, (_) => controller.refresh());
|
||||
useOnSourceSync(ref, controller.refresh);
|
||||
|
||||
return PagingListener(
|
||||
controller: controller,
|
||||
builder: (context, state, fetchNextPage) {
|
||||
return PagedSliverList(
|
||||
state: state,
|
||||
fetchNextPage: fetchNextPage,
|
||||
builderDelegate: PagedChildBuilderDelegate<Album>(
|
||||
itemBuilder: (context, item, index) {
|
||||
final tile = AlbumListTile(
|
||||
album: item,
|
||||
onTap: () {
|
||||
context.push('/albums/${item.id}');
|
||||
},
|
||||
);
|
||||
|
||||
final currentItemYear = item.year;
|
||||
final previousItemYear = index == 0
|
||||
? currentItemYear
|
||||
: controller.items?.elementAtOrNull(index - 1)?.year;
|
||||
|
||||
if (index == 0 || currentItemYear != previousItemYear) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 24,
|
||||
bottom: 8,
|
||||
left: 16,
|
||||
right: 16,
|
||||
),
|
||||
child: Text(
|
||||
item.year?.toString() ?? 'Unknown year',
|
||||
style: TextTheme.of(context).headlineMedium,
|
||||
),
|
||||
),
|
||||
tile,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return tile;
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,8 @@ class SongsListHeader extends HookConsumerWidget {
|
||||
children: [
|
||||
const SizedBox(height: 24),
|
||||
Container(
|
||||
height: 300,
|
||||
width: 300,
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
@@ -48,7 +50,6 @@ class SongsListHeader extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
child: CoverArtImage(
|
||||
height: 300,
|
||||
thumbnail: false,
|
||||
coverArt: coverArt,
|
||||
fit: BoxFit.contain,
|
||||
|
||||
@@ -62,6 +62,63 @@ class ArtistListTile extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class AlbumListTile extends StatelessWidget {
|
||||
const AlbumListTile({
|
||||
super.key,
|
||||
required this.album,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final Album album;
|
||||
final void Function()? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textTheme = TextTheme.of(context);
|
||||
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8, right: 18),
|
||||
child: RoundedBoxClip(
|
||||
child: CoverArtImage(
|
||||
coverArt: album.coverArt,
|
||||
thumbnail: true,
|
||||
width: 80,
|
||||
height: 80,
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
album.name,
|
||||
style: textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
),
|
||||
Text(
|
||||
album.albumArtist ?? 'Unknown album artist',
|
||||
style: textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PlaylistListTile extends StatelessWidget {
|
||||
const PlaylistListTile({
|
||||
super.key,
|
||||
|
||||
Reference in New Issue
Block a user