work on artist details page
This commit is contained in:
parent
58e2c7be81
commit
7d346badef
6 changed files with 157 additions and 42 deletions
|
@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
''';
|
||||
}
|
||||
}
|
||||
|
|
66
lib/presentation/widgets/album_list_tile_extended.dart
Normal file
66
lib/presentation/widgets/album_list_tile_extended.dart
Normal 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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
27
lib/presentation/widgets/artist_albums.dart
Normal file
27
lib/presentation/widgets/artist_albums.dart
Normal 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),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue