diff --git a/lib/components/Artist/ArtistCard.dart b/lib/components/Artist/ArtistCard.dart new file mode 100644 index 00000000..e07e7277 --- /dev/null +++ b/lib/components/Artist/ArtistCard.dart @@ -0,0 +1,55 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:spotify/spotify.dart'; + +class ArtistCard extends StatelessWidget { + final Artist artist; + const ArtistCard(this.artist, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () {}, + borderRadius: BorderRadius.circular(10), + child: Ink( + width: 200, + decoration: BoxDecoration( + color: Theme.of(context).backgroundColor, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + blurRadius: 10, + offset: const Offset(0, 3), + spreadRadius: 5, + color: Theme.of(context).shadowColor) + ], + ), + child: Padding( + padding: const EdgeInsets.all(15), + child: Column( + children: [ + CircleAvatar( + maxRadius: 80, + minRadius: 20, + backgroundImage: CachedNetworkImageProvider((artist + .images?.isNotEmpty ?? + false) + ? artist.images!.first.url! + : "https://avatars.dicebear.com/api/open-peeps/${artist.id}.svg?b=%231ed760&r=50&flip=1&translateX=3&translateY=-6"), + ), + Text( + artist.name!, + style: Theme.of(context).textTheme.headline5, + overflow: TextOverflow.ellipsis, + ), + Text( + "Artist", + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/components/Home.dart b/lib/components/Home.dart index 85c05727..949fbee3 100644 --- a/lib/components/Home.dart +++ b/lib/components/Home.dart @@ -24,6 +24,8 @@ List spotifyScopes = [ "user-library-modify", "user-read-private", "user-read-email", + "user-follow-read", + "user-follow-modify", "playlist-read-collaborative" ]; diff --git a/lib/components/Library/UserArtists.dart b/lib/components/Library/UserArtists.dart index 75401d58..b1ac2679 100644 --- a/lib/components/Library/UserArtists.dart +++ b/lib/components/Library/UserArtists.dart @@ -1,10 +1,81 @@ import 'package:flutter/material.dart'; +import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; +import 'package:provider/provider.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/Artist/ArtistCard.dart'; +import 'package:spotube/provider/SpotifyDI.dart'; -class UserArtists extends StatelessWidget { +class UserArtists extends StatefulWidget { const UserArtists({Key? key}) : super(key: key); + @override + State createState() => _UserArtistsState(); +} + +class _UserArtistsState extends State { + final PagingController _pagingController = + PagingController(firstPageKey: 0); + + @override + void initState() { + super.initState(); + WidgetsBinding.instance?.addPostFrameCallback((timestamp) { + _pagingController.addPageRequestListener((pageKey) async { + try { + SpotifyDI data = context.read(); + var offset = + _pagingController.value.itemList?.elementAt(pageKey).id ?? ""; + CursorPage artists = await data.spotifyApi.me + .following(FollowingType.artist) + .getPage(15, offset); + + var items = artists.items!.toList(); + + if (artists.items != null && items.length < 15) { + _pagingController.appendLastPage(items); + } else if (artists.items != null) { + var yetToBe = [ + ...(_pagingController.value.itemList ?? []), + ...items + ]; + _pagingController.appendPage(items, yetToBe.length - 1); + } + } catch (e, stack) { + _pagingController.error = e; + print("[UserArtists.pagingController]: $e"); + print(stack); + } + }); + }); + } + @override Widget build(BuildContext context) { - return Container(); + SpotifyDI data = context.watch(); + + return FutureBuilder>( + future: data.spotifyApi.me.following(FollowingType.artist).first(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return const Center(child: CircularProgressIndicator.adaptive()); + } + + return PagedGridView( + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 250, + childAspectRatio: 9 / 11, + crossAxisSpacing: 20, + mainAxisSpacing: 20, + ), + padding: const EdgeInsets.all(10), + pagingController: _pagingController, + builderDelegate: PagedChildBuilderDelegate( + itemBuilder: (context, item, index) { + return ArtistCard(item); + }, + ), + ); + }, + ); } } diff --git a/lib/components/Library/UserLibrary.dart b/lib/components/Library/UserLibrary.dart index 5d2d6c98..415764cc 100644 --- a/lib/components/Library/UserLibrary.dart +++ b/lib/components/Library/UserLibrary.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart' hide Image; +import 'package:spotube/components/Library/UserArtists.dart'; import 'package:spotube/components/Library/UserPlaylists.dart'; class UserLibrary extends StatefulWidget { @@ -27,7 +28,7 @@ class _UserLibraryState extends State { ), body: const TabBarView(children: [ UserPlaylists(), - Icon(Icons.ac_unit_outlined), + UserArtists(), Icon(Icons.ac_unit_outlined), ]), ), diff --git a/lib/main.dart b/lib/main.dart index 04d45981..0acc5769 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -160,6 +160,11 @@ class _MyAppState extends State { color: Colors.grey[850], ), ), + cardTheme: CardTheme( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + color: Colors.white, + ), ), darkTheme: ThemeData( brightness: Brightness.dark, @@ -189,6 +194,12 @@ class _MyAppState extends State { backgroundColor: Colors.blueGrey[800], unselectedIconTheme: const IconThemeData(opacity: 1), ), + cardTheme: CardTheme( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + color: Colors.blueGrey[900], + elevation: 20, + ), ), themeMode: _themeMode, home: const Home(),