scrollbars and queuepage
This commit is contained in:
parent
7418ffdded
commit
d64250f6bf
7 changed files with 135 additions and 93 deletions
|
@ -26,28 +26,30 @@ class _AlbumsPageState extends State<AlbumsPage> with AutomaticKeepAliveClientMi
|
|||
return Observer(builder: (_) {
|
||||
print('AlbumsPage.build -> Observer.builder');
|
||||
final List<Album> albums = store.albumStream.value ?? [];
|
||||
return ListView.separated(
|
||||
itemCount: albums.length,
|
||||
itemBuilder: (_, int index) {
|
||||
final Album album = albums[index];
|
||||
return AlbumArtListTile(
|
||||
title: album.title,
|
||||
subtitle: album.artist,
|
||||
albumArtPath: album.albumArtPath,
|
||||
onTap: () {
|
||||
navStore.push(
|
||||
context,
|
||||
MaterialPageRoute<Widget>(
|
||||
builder: (BuildContext context) => AlbumDetailsPage(
|
||||
album: album,
|
||||
return Scrollbar(
|
||||
child: ListView.separated(
|
||||
itemCount: albums.length,
|
||||
itemBuilder: (_, int index) {
|
||||
final Album album = albums[index];
|
||||
return AlbumArtListTile(
|
||||
title: album.title,
|
||||
subtitle: album.artist,
|
||||
albumArtPath: album.albumArtPath,
|
||||
onTap: () {
|
||||
navStore.push(
|
||||
context,
|
||||
MaterialPageRoute<Widget>(
|
||||
builder: (BuildContext context) => AlbumDetailsPage(
|
||||
album: album,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const SizedBox(
|
||||
height: 4.0,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const SizedBox(
|
||||
height: 4.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
|
|
@ -25,26 +25,28 @@ class _ArtistsPageState extends State<ArtistsPage> with AutomaticKeepAliveClient
|
|||
return Observer(builder: (_) {
|
||||
print('ArtistsPage.build -> Observer.builder');
|
||||
final List<Artist> artists = musicDataStore.artistStream.value ?? [];
|
||||
return ListView.separated(
|
||||
itemCount: artists.length,
|
||||
itemBuilder: (_, int index) {
|
||||
final Artist artist = artists[index];
|
||||
return ListTile(
|
||||
title: Text(artist.name),
|
||||
onTap: () {
|
||||
navStore.push(
|
||||
context,
|
||||
MaterialPageRoute<Widget>(
|
||||
builder: (BuildContext context) => ArtistDetailsPage(
|
||||
artist: artist,
|
||||
return Scrollbar(
|
||||
child: ListView.separated(
|
||||
itemCount: artists.length,
|
||||
itemBuilder: (_, int index) {
|
||||
final Artist artist = artists[index];
|
||||
return ListTile(
|
||||
title: Text(artist.name),
|
||||
onTap: () {
|
||||
navStore.push(
|
||||
context,
|
||||
MaterialPageRoute<Widget>(
|
||||
builder: (BuildContext context) => ArtistDetailsPage(
|
||||
artist: artist,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const SizedBox(
|
||||
height: 4.0,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const SizedBox(
|
||||
height: 4.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
|
|
@ -57,7 +57,6 @@ class CurrentlyPlayingPage extends StatelessWidget {
|
|||
padding: const EdgeInsets.only(
|
||||
left: 12.0,
|
||||
right: 12.0,
|
||||
top: 8.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
|
@ -8,7 +8,9 @@ import 'package:reorderables/reorderables.dart';
|
|||
|
||||
import '../../domain/entities/song.dart';
|
||||
import '../state/audio_store.dart';
|
||||
import '../widgets/album_art_list_tile.dart';
|
||||
import '../theming.dart';
|
||||
import '../widgets/song_bottom_sheet.dart';
|
||||
import '../widgets/song_list_tile.dart';
|
||||
|
||||
class QueuePage extends StatelessWidget {
|
||||
const QueuePage({Key? key}) : super(key: key);
|
||||
|
@ -24,6 +26,33 @@ class QueuePage extends StatelessWidget {
|
|||
ScrollController(initialScrollOffset: initialIndex * 72.0);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.only(left: 12.0),
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.expand_more),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
),
|
||||
leadingWidth: 60.0,
|
||||
title: const Text(
|
||||
'Currently Playing',
|
||||
style: TEXT_HEADER,
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.play_arrow_outlined),
|
||||
onPressed: () {
|
||||
_scrollController.animateTo(
|
||||
max((queueIndexStream.value ?? 0) - 2, 0) * 72.0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Observer(
|
||||
builder: (BuildContext context) {
|
||||
|
@ -33,35 +62,38 @@ class QueuePage extends StatelessWidget {
|
|||
switch (queueStream.status) {
|
||||
case StreamStatus.active:
|
||||
final int activeIndex = queueIndexStream.value ?? -1;
|
||||
return CustomScrollView(
|
||||
controller: _scrollController,
|
||||
slivers: [
|
||||
ReorderableSliverList(
|
||||
delegate: ReorderableSliverChildBuilderDelegate(
|
||||
(context, int index) {
|
||||
final Song? song = queueStream.value?[index];
|
||||
if (song == null)
|
||||
return Container();
|
||||
return Dismissible(
|
||||
key: ValueKey(song.path),
|
||||
child: AlbumArtListTile(
|
||||
title: song.title,
|
||||
subtitle: '${song.artist}',
|
||||
albumArtPath: song.albumArtPath,
|
||||
highlight: index == activeIndex,
|
||||
onTap: () => audioStore.seekToIndex(index),
|
||||
),
|
||||
onDismissed: (direction) {
|
||||
audioStore.removeQueueIndex(index);
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: queueStream.value?.length,
|
||||
),
|
||||
onReorder: (oldIndex, newIndex) =>
|
||||
audioStore.moveQueueItem(oldIndex, newIndex),
|
||||
)
|
||||
],
|
||||
return Scrollbar(
|
||||
child: CustomScrollView(
|
||||
controller: _scrollController,
|
||||
slivers: [
|
||||
ReorderableSliverList(
|
||||
delegate: ReorderableSliverChildBuilderDelegate(
|
||||
(context, int index) {
|
||||
final Song? song = queueStream.value?[index];
|
||||
if (song == null) return Container();
|
||||
return Dismissible(
|
||||
key: ValueKey(song.path),
|
||||
child: SongListTile(
|
||||
song: song,
|
||||
highlight: index == activeIndex,
|
||||
onTap: () async {
|
||||
await audioStore.seekToIndex(index);
|
||||
audioStore.play();
|
||||
},
|
||||
onTapMore: () => SongBottomSheet()(song, context),
|
||||
),
|
||||
onDismissed: (direction) {
|
||||
audioStore.removeQueueIndex(index);
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: queueStream.value?.length,
|
||||
),
|
||||
onReorder: (oldIndex, newIndex) =>
|
||||
audioStore.moveQueueItem(oldIndex, newIndex),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
case StreamStatus.waiting:
|
||||
case StreamStatus.done:
|
||||
|
|
|
@ -32,20 +32,22 @@ class _SongsPageState extends State<SongsPage> with AutomaticKeepAliveClientMixi
|
|||
switch (songStream.status) {
|
||||
case StreamStatus.active:
|
||||
final List<Song> songs = songStream.value ?? [];
|
||||
return ListView.separated(
|
||||
itemCount: songs.length,
|
||||
itemBuilder: (_, int index) {
|
||||
final Song song = songs[index];
|
||||
return SongListTile(
|
||||
song: song,
|
||||
showAlbum: true,
|
||||
subtitle: Subtitle.artistAlbum,
|
||||
onTap: () => audioStore.playSong(index, songs),
|
||||
onTapMore: () => SongBottomSheet()(song, context),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const SizedBox(
|
||||
height: 4.0,
|
||||
return Scrollbar(
|
||||
child: ListView.separated(
|
||||
itemCount: songs.length,
|
||||
itemBuilder: (_, int index) {
|
||||
final Song song = songs[index];
|
||||
return SongListTile(
|
||||
song: song,
|
||||
showAlbum: true,
|
||||
subtitle: Subtitle.artistAlbum,
|
||||
onTap: () => audioStore.playSong(index, songs),
|
||||
onTapMore: () => SongBottomSheet()(song, context),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const SizedBox(
|
||||
height: 4.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
case StreamStatus.waiting:
|
||||
|
|
|
@ -27,8 +27,10 @@ class CurrentlyPlayingHeader extends StatelessWidget {
|
|||
child: GestureDetector(
|
||||
onTap: () => onTap(context),
|
||||
child: Container(
|
||||
height: 56.0,
|
||||
color: Colors.transparent,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
|
|
|
@ -7,18 +7,20 @@ import '../utils.dart' as utils;
|
|||
enum Subtitle { artist, artistAlbum, stats }
|
||||
|
||||
class SongListTile extends StatelessWidget {
|
||||
const SongListTile(
|
||||
{Key? key,
|
||||
required this.song,
|
||||
required this.onTap,
|
||||
required this.onTapMore,
|
||||
this.showAlbum = true,
|
||||
this.subtitle = Subtitle.artist})
|
||||
: super(key: key);
|
||||
const SongListTile({
|
||||
Key? key,
|
||||
required this.song,
|
||||
required this.onTap,
|
||||
required this.onTapMore,
|
||||
this.highlight = false,
|
||||
this.showAlbum = true,
|
||||
this.subtitle = Subtitle.artist,
|
||||
}) : super(key: key);
|
||||
|
||||
final Song song;
|
||||
final Function onTap;
|
||||
final Function onTapMore;
|
||||
final bool highlight;
|
||||
final bool showAlbum;
|
||||
final Subtitle subtitle;
|
||||
|
||||
|
@ -90,6 +92,7 @@ class SongListTile extends StatelessWidget {
|
|||
),
|
||||
subtitle: subtitleWidget,
|
||||
onTap: () => onTap(),
|
||||
tileColor: highlight ? Colors.white10 : Colors.transparent,
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
|
Loading…
Add table
Reference in a new issue