work on artist details page

This commit is contained in:
Moritz Weber 2021-01-17 10:20:51 +01:00
parent 58e2c7be81
commit 7d346badef
6 changed files with 157 additions and 42 deletions

View file

@ -5,7 +5,7 @@ import 'package:provider/provider.dart';
import '../../domain/entities/album.dart';
import '../../domain/entities/artist.dart';
import '../state/music_data_store.dart';
import '../widgets/album_art_list_tile.dart';
import '../widgets/artist_albums.dart';
import 'album_details_page.dart';
class ArtistDetailsPage extends StatelessWidget {
@ -17,36 +17,30 @@ class ArtistDetailsPage extends StatelessWidget {
Widget build(BuildContext context) {
final MusicDataStore musicDataStore = Provider.of<MusicDataStore>(context);
return Scaffold(
body: SafeArea(
child: Observer(
builder: (BuildContext context) => ListView.separated(
itemCount: musicDataStore.artistAlbumStream.value.length,
separatorBuilder: (BuildContext context, int index) => const Divider(
height: 4.0,
),
itemBuilder: (_, int index) {
final Album album = musicDataStore.artistAlbumStream.value[index];
return AlbumArtListTile(
title: album.title,
subtitle: album.pubYear.toString(),
albumArtPath: album.albumArtPath,
onTap: () {
musicDataStore.fetchSongsFromAlbum(album);
Navigator.push(
context,
MaterialPageRoute<Widget>(
builder: (BuildContext context) => AlbumDetailsPage(
album: album,
),
),
);
},
);
},
return Observer(
builder: (BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(artist.name),
),
body: SafeArea(
child: ArtistAlbumList(
albums: musicDataStore.sortedArtistAlbums,
onTap: (Album album) => _tapAlbum(album, context, musicDataStore),
),
),
),
);
}
void _tapAlbum(Album album, BuildContext context, MusicDataStore musicDataStore) {
musicDataStore.fetchSongsFromAlbum(album);
Navigator.push(
context,
MaterialPageRoute<Widget>(
builder: (BuildContext context) => AlbumDetailsPage(
album: album,
),
),
);
}
}

View file

@ -14,19 +14,35 @@ class LibraryTabContainer extends StatelessWidget {
child: SafeArea(
child: Column(
children: <Widget>[
Container(
color: Theme.of(context).primaryColor,
child: const TabBar(
tabs: <Tab>[
Tab(
text: 'Artists',
),
Tab(
text: 'Albums',
),
Tab(
text: 'Songs',
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 16.0),
child: Row(
children: [
const Expanded(
child: TabBar(
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: Colors.transparent,
labelStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
),
labelPadding: EdgeInsets.only(left: 16.0, right: 8.0),
unselectedLabelColor: Colors.white30,
isScrollable: true,
tabs: [
Tab(
text: 'Artists',
),
Tab(
text: 'Albums',
),
Tab(
text: 'Songs',
),
],
),
),
IconButton(icon: const Icon(Icons.more_vert), onPressed: () => null),
],
),
),
@ -50,4 +66,4 @@ class LibraryTabContainer extends StatelessWidget {
),
);
}
}
}

View file

@ -48,6 +48,9 @@ abstract class _MusicDataStore with Store {
@observable
bool isUpdatingDatabase = false;
@computed
List<Album> get sortedArtistAlbums => artistAlbumStream.value.toList()..sort((a, b) => -a.pubYear.compareTo(b.pubYear));
@action
Future<void> updateDatabase() async {
isUpdatingDatabase = true;

View file

@ -9,6 +9,14 @@ part of 'music_data_store.dart';
// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
mixin _$MusicDataStore on _MusicDataStore, Store {
Computed<List<Album>> _$sortedArtistAlbumsComputed;
@override
List<Album> get sortedArtistAlbums => (_$sortedArtistAlbumsComputed ??=
Computed<List<Album>>(() => super.sortedArtistAlbums,
name: '_MusicDataStore.sortedArtistAlbums'))
.value;
final _$songStreamAtom = Atom(name: '_MusicDataStore.songStream');
@override
@ -135,7 +143,8 @@ albumStream: ${albumStream},
artistStream: ${artistStream},
albumSongStream: ${albumSongStream},
artistAlbumStream: ${artistAlbumStream},
isUpdatingDatabase: ${isUpdatingDatabase}
isUpdatingDatabase: ${isUpdatingDatabase},
sortedArtistAlbums: ${sortedArtistAlbums}
''';
}
}

View file

@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import '../theming.dart';
import '../utils.dart' as utils;
class AlbumListTileExtended extends StatelessWidget {
const AlbumListTileExtended(
{Key key, this.title, this.subtitle, this.albumArtPath, this.onTap, this.highlight = false})
: super(key: key);
final String title;
final String subtitle;
final String albumArtPath;
final Function onTap;
final bool highlight;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => onTap(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Row(
children: [
SizedBox(
height: 72,
width: 72,
child: Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(4.0)),
clipBehavior: Clip.antiAlias,
child: Image(
image: utils.getAlbumImage(albumArtPath),
fit: BoxFit.cover,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0),
maxLines: 2,
),
Text(
subtitle,
style: TEXT_SMALL_SUBTITLE,
),
],
),
),
),
IconButton(
icon: Icon(Icons.play_circle_fill_rounded),
iconSize: 40.0,
onPressed: () => null,
),
],
),
),
);
}
}

View file

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import '../../domain/entities/album.dart';
import 'album_list_tile_extended.dart';
class ArtistAlbumList extends StatelessWidget {
const ArtistAlbumList({Key key, this.albums, this.onTap}) : super(key: key);
final List<Album> albums;
final Function onTap;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: albums.length,
itemBuilder: (_, int index) {
final Album album = albums[index];
return AlbumListTileExtended(
title: album.title,
subtitle: album.pubYear.toString(),
albumArtPath: album.albumArtPath,
onTap: () => onTap(album),
);
},
);
}
}