mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-27 00:59:28 +01:00
songs list tab
This commit is contained in:
parent
16a79c81cb
commit
a4e4c6fa57
@ -10,6 +10,7 @@ import '../state/source.dart';
|
||||
import '../ui/cover_art_theme.dart';
|
||||
import '../ui/gradient.dart';
|
||||
import '../ui/lists/header.dart';
|
||||
import '../ui/lists/items.dart';
|
||||
import '../ui/lists/songs_list.dart';
|
||||
|
||||
class AlbumScreen extends HookConsumerWidget {
|
||||
@ -61,7 +62,13 @@ class AlbumScreen extends HookConsumerWidget {
|
||||
onMore: () {},
|
||||
),
|
||||
),
|
||||
SongsList(query: query),
|
||||
SongsList(
|
||||
query: query,
|
||||
itemBuilder: (context, item, index) => SongListTile(
|
||||
song: item.song,
|
||||
onTap: () {},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
import '../../database/query.dart';
|
||||
import '../../l10n/generated/app_localizations.dart';
|
||||
import '../state/services.dart';
|
||||
import '../state/source.dart';
|
||||
import '../ui/lists/albums_grid.dart';
|
||||
import '../ui/lists/artists_list.dart';
|
||||
import '../ui/lists/items.dart';
|
||||
import '../ui/lists/songs_list.dart';
|
||||
import '../util/custom_scroll_fix.dart';
|
||||
|
||||
const kIconSize = 26.0;
|
||||
@ -51,20 +56,7 @@ class LibraryScreen extends HookConsumerWidget {
|
||||
builder: (context) => CustomScrollProvider(
|
||||
tabController: tabController,
|
||||
parent: PrimaryScrollController.of(context),
|
||||
child: TabBarView(
|
||||
controller: tabController,
|
||||
children: LibraryTab.values
|
||||
.map(
|
||||
(tab) => TabScrollView(
|
||||
index: LibraryTab.values.indexOf(tab),
|
||||
sliver: switch (tab) {
|
||||
LibraryTab.albums => AlbumsGrid(),
|
||||
_ => ArtistsList(),
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
child: LibraryTabBarView(tabController: tabController),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -72,6 +64,56 @@ class LibraryScreen extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class LibraryTabBarView extends HookConsumerWidget {
|
||||
const LibraryTabBarView({
|
||||
super.key,
|
||||
required this.tabController,
|
||||
});
|
||||
|
||||
final TabController tabController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final sourceId = ref.watch(sourceIdProvider);
|
||||
|
||||
final songsQuery = SongsQuery(
|
||||
sourceId: sourceId,
|
||||
sort: IList([
|
||||
SongsSortingTerm(dir: SortDirection.asc, by: SongsColumn.albumArtist),
|
||||
SongsSortingTerm(dir: SortDirection.asc, by: SongsColumn.album),
|
||||
SongsSortingTerm(dir: SortDirection.asc, by: SongsColumn.disc),
|
||||
SongsSortingTerm(dir: SortDirection.asc, by: SongsColumn.track),
|
||||
SongsSortingTerm(dir: SortDirection.asc, by: SongsColumn.title),
|
||||
]),
|
||||
);
|
||||
|
||||
return TabBarView(
|
||||
controller: tabController,
|
||||
children: LibraryTab.values
|
||||
.map(
|
||||
(tab) => TabScrollView(
|
||||
index: LibraryTab.values.indexOf(tab),
|
||||
sliver: switch (tab) {
|
||||
LibraryTab.albums => AlbumsGrid(),
|
||||
LibraryTab.artists => ArtistsList(),
|
||||
LibraryTab.songs => SongsList(
|
||||
query: songsQuery,
|
||||
itemBuilder: (context, item, index) => SongListTile(
|
||||
song: item.song,
|
||||
coverArt: item.albumCoverArt,
|
||||
showLeading: true,
|
||||
onTap: () {},
|
||||
),
|
||||
),
|
||||
_ => ArtistsList(),
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LibraryTabsHeader extends HookConsumerWidget {
|
||||
const LibraryTabsHeader({
|
||||
super.key,
|
||||
|
||||
@ -66,19 +66,25 @@ class SongListTile extends StatelessWidget {
|
||||
const SongListTile({
|
||||
super.key,
|
||||
required this.song,
|
||||
this.coverArt,
|
||||
this.showLeading = false,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final Song song;
|
||||
final String? coverArt;
|
||||
final bool showLeading;
|
||||
final void Function()? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
// leading: CoverArtImage(
|
||||
// coverArt: song.coverArt,
|
||||
// thumbnail: true,
|
||||
// ),
|
||||
leading: showLeading
|
||||
? CoverArtImage(
|
||||
coverArt: coverArt,
|
||||
thumbnail: true,
|
||||
)
|
||||
: null,
|
||||
title: Text(song.title),
|
||||
subtitle: Text(song.artist ?? ''),
|
||||
onTap: onTap,
|
||||
|
||||
@ -2,12 +2,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||
|
||||
import '../../../database/dao/library_dao.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 'items.dart';
|
||||
|
||||
const kPageSize = 30;
|
||||
|
||||
@ -15,14 +14,17 @@ class SongsList extends HookConsumerWidget {
|
||||
const SongsList({
|
||||
super.key,
|
||||
required this.query,
|
||||
required this.itemBuilder,
|
||||
});
|
||||
|
||||
final SongsQuery query;
|
||||
final Widget Function(BuildContext context, SongListItem item, int index)
|
||||
itemBuilder;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final db = ref.watch(databaseProvider);
|
||||
final controller = usePagingController<int, Song>(
|
||||
final controller = usePagingController<int, SongListItem>(
|
||||
getNextPageKey: (state) =>
|
||||
state.lastPageIsEmpty ? null : state.nextIntPageKey,
|
||||
fetchPage: (pageKey) => db.libraryDao.listSongs(
|
||||
@ -42,13 +44,8 @@ class SongsList extends HookConsumerWidget {
|
||||
return PagedSliverList(
|
||||
state: state,
|
||||
fetchNextPage: fetchNextPage,
|
||||
builderDelegate: PagedChildBuilderDelegate<Song>(
|
||||
itemBuilder: (context, item, index) {
|
||||
return SongListTile(
|
||||
song: item,
|
||||
onTap: () async {},
|
||||
);
|
||||
},
|
||||
builderDelegate: PagedChildBuilderDelegate<SongListItem>(
|
||||
itemBuilder: itemBuilder,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@ -6,7 +6,15 @@ import '../query.dart';
|
||||
|
||||
part 'library_dao.g.dart';
|
||||
|
||||
typedef AristListItem = ({models.Artist artist, int? albumCount});
|
||||
typedef AristListItem = ({
|
||||
models.Artist artist,
|
||||
int? albumCount,
|
||||
});
|
||||
|
||||
typedef SongListItem = ({
|
||||
models.Song song,
|
||||
String? albumCoverArt,
|
||||
});
|
||||
|
||||
extension on SortDirection {
|
||||
OrderingMode toMode() => switch (this) {
|
||||
@ -111,7 +119,7 @@ class LibraryDao extends DatabaseAccessor<SubtracksDatabase>
|
||||
.get();
|
||||
}
|
||||
|
||||
Future<List<models.Song>> listSongs(SongsQuery q) {
|
||||
Future<List<SongListItem>> listSongs(SongsQuery q) {
|
||||
var joinPlaylistSongs = false;
|
||||
var filter = songs.sourceId.equals(q.sourceId);
|
||||
|
||||
@ -127,6 +135,11 @@ class LibraryDao extends DatabaseAccessor<SubtracksDatabase>
|
||||
|
||||
final query =
|
||||
songs.select().join([
|
||||
leftOuterJoin(
|
||||
albums,
|
||||
albums.id.equalsExp(songs.albumId) &
|
||||
albums.sourceId.equals(q.sourceId),
|
||||
),
|
||||
if (joinPlaylistSongs)
|
||||
leftOuterJoin(
|
||||
playlistSongs,
|
||||
@ -134,6 +147,9 @@ class LibraryDao extends DatabaseAccessor<SubtracksDatabase>
|
||||
playlistSongs.songId.equalsExp(songs.id),
|
||||
),
|
||||
])
|
||||
..addColumns([
|
||||
albums.coverArt,
|
||||
])
|
||||
..where(filter)
|
||||
..orderBy(
|
||||
q.sort
|
||||
@ -144,6 +160,9 @@ class LibraryDao extends DatabaseAccessor<SubtracksDatabase>
|
||||
SongsColumn.starred => songs.starred,
|
||||
SongsColumn.disc => songs.disc,
|
||||
SongsColumn.track => songs.track,
|
||||
SongsColumn.album => songs.album,
|
||||
SongsColumn.artist => songs.artist,
|
||||
SongsColumn.albumArtist => albums.albumArtist,
|
||||
},
|
||||
mode: sort.dir.toMode(),
|
||||
),
|
||||
@ -153,7 +172,14 @@ class LibraryDao extends DatabaseAccessor<SubtracksDatabase>
|
||||
|
||||
_limitQuery(query: query, limit: q.limit, offset: q.offset);
|
||||
|
||||
return query.map((row) => (row.readTable(songs))).get();
|
||||
return query
|
||||
.map(
|
||||
(row) => (
|
||||
song: row.readTable(songs),
|
||||
albumCoverArt: row.read(albums.coverArt),
|
||||
),
|
||||
)
|
||||
.get();
|
||||
}
|
||||
|
||||
Selectable<models.Album> getAlbum(int sourceId, String id) {
|
||||
|
||||
@ -27,6 +27,9 @@ enum SongsColumn {
|
||||
starred,
|
||||
disc,
|
||||
track,
|
||||
album,
|
||||
artist,
|
||||
albumArtist,
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user