mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
flutter provider replaced with flutter_riverpod
This commit is contained in:
parent
88b201b24b
commit
d05ec0099d
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Album/AlbumView.dart';
|
import 'package:spotube/components/Album/AlbumView.dart';
|
||||||
import 'package:spotube/components/Shared/PlaybuttonCard.dart';
|
import 'package:spotube/components/Shared/PlaybuttonCard.dart';
|
||||||
@ -9,13 +9,13 @@ import 'package:spotube/helpers/simple-track-to-track.dart';
|
|||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class AlbumCard extends StatelessWidget {
|
class AlbumCard extends ConsumerWidget {
|
||||||
final Album album;
|
final Album album;
|
||||||
const AlbumCard(this.album, {Key? key}) : super(key: key);
|
const AlbumCard(this.album, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, ref) {
|
||||||
Playback playback = context.watch<Playback>();
|
Playback playback = ref.watch(playbackProvider);
|
||||||
bool isPlaylistPlaying = playback.currentPlaylist != null &&
|
bool isPlaylistPlaying = playback.currentPlaylist != null &&
|
||||||
playback.currentPlaylist!.id == album.id;
|
playback.currentPlaylist!.id == album.id;
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ class AlbumCard extends StatelessWidget {
|
|||||||
));
|
));
|
||||||
},
|
},
|
||||||
onPlaybuttonPressed: () async {
|
onPlaybuttonPressed: () async {
|
||||||
SpotifyApi spotify = context.read<SpotifyDI>().spotifyApi;
|
SpotifyApi spotify = ref.read(spotifyProvider);
|
||||||
if (isPlaylistPlaying) return;
|
if (isPlaylistPlaying) return;
|
||||||
List<Track> tracks = (await spotify.albums.getTracks(album.id!).all())
|
List<Track> tracks = (await spotify.albums.getTracks(album.id!).all())
|
||||||
.map((track) => simpleTrackToTrack(track, album))
|
.map((track) => simpleTrackToTrack(track, album))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
||||||
import 'package:spotube/components/Shared/TracksTableView.dart';
|
import 'package:spotube/components/Shared/TracksTableView.dart';
|
||||||
@ -8,7 +8,7 @@ import 'package:spotube/helpers/simple-track-to-track.dart';
|
|||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class AlbumView extends StatelessWidget {
|
class AlbumView extends ConsumerWidget {
|
||||||
final AlbumSimple album;
|
final AlbumSimple album;
|
||||||
const AlbumView(this.album, {Key? key}) : super(key: key);
|
const AlbumView(this.album, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@ -31,11 +31,11 @@ class AlbumView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, ref) {
|
||||||
Playback playback = context.watch<Playback>();
|
Playback playback = ref.watch(playbackProvider);
|
||||||
|
|
||||||
var isPlaylistPlaying = playback.currentPlaylist?.id == album.id;
|
var isPlaylistPlaying = playback.currentPlaylist?.id == album.id;
|
||||||
SpotifyApi spotify = context.watch<SpotifyDI>().spotifyApi;
|
SpotifyApi spotify = ref.watch(spotifyProvider);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: FutureBuilder<Iterable<TrackSimple>>(
|
body: FutureBuilder<Iterable<TrackSimple>>(
|
||||||
future: spotify.albums.getTracks(album.id!).all(),
|
future: spotify.albums.getTracks(album.id!).all(),
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Album/AlbumCard.dart';
|
import 'package:spotube/components/Album/AlbumCard.dart';
|
||||||
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class ArtistAlbumView extends StatefulWidget {
|
class ArtistAlbumView extends ConsumerStatefulWidget {
|
||||||
final String artistId;
|
final String artistId;
|
||||||
final String artistName;
|
final String artistName;
|
||||||
const ArtistAlbumView(
|
const ArtistAlbumView(
|
||||||
@ -16,10 +16,10 @@ class ArtistAlbumView extends StatefulWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ArtistAlbumView> createState() => _ArtistAlbumViewState();
|
ConsumerState<ArtistAlbumView> createState() => _ArtistAlbumViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ArtistAlbumViewState extends State<ArtistAlbumView> {
|
class _ArtistAlbumViewState extends ConsumerState<ArtistAlbumView> {
|
||||||
final PagingController<int, Album> _pagingController =
|
final PagingController<int, Album> _pagingController =
|
||||||
PagingController<int, Album>(firstPageKey: 0);
|
PagingController<int, Album>(firstPageKey: 0);
|
||||||
|
|
||||||
@ -39,10 +39,9 @@ class _ArtistAlbumViewState extends State<ArtistAlbumView> {
|
|||||||
|
|
||||||
_fetchPage(int pageKey) async {
|
_fetchPage(int pageKey) async {
|
||||||
try {
|
try {
|
||||||
SpotifyDI data = context.read<SpotifyDI>();
|
SpotifyApi spotifyApi = ref.watch(spotifyProvider);
|
||||||
Page<Album> albums = await data.spotifyApi.artists
|
Page<Album> albums =
|
||||||
.albums(widget.artistId)
|
await spotifyApi.artists.albums(widget.artistId).getPage(8, pageKey);
|
||||||
.getPage(8, pageKey);
|
|
||||||
|
|
||||||
var items = albums.items!.toList();
|
var items = albums.items!.toList();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Album/AlbumCard.dart';
|
import 'package:spotube/components/Album/AlbumCard.dart';
|
||||||
import 'package:spotube/components/Artist/ArtistAlbumView.dart';
|
import 'package:spotube/components/Artist/ArtistAlbumView.dart';
|
||||||
@ -14,7 +14,7 @@ import 'package:spotube/helpers/zero-pad-num-str.dart';
|
|||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class ArtistProfile extends StatefulWidget {
|
class ArtistProfile extends ConsumerStatefulWidget {
|
||||||
final String artistId;
|
final String artistId;
|
||||||
const ArtistProfile(this.artistId, {Key? key}) : super(key: key);
|
const ArtistProfile(this.artistId, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@ -22,10 +22,10 @@ class ArtistProfile extends StatefulWidget {
|
|||||||
_ArtistProfileState createState() => _ArtistProfileState();
|
_ArtistProfileState createState() => _ArtistProfileState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ArtistProfileState extends State<ArtistProfile> {
|
class _ArtistProfileState extends ConsumerState<ArtistProfile> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SpotifyApi spotify = context.watch<SpotifyDI>().spotifyApi;
|
SpotifyApi spotify = ref.watch(spotifyProvider);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: const PageWindowTitleBar(
|
appBar: const PageWindowTitleBar(
|
||||||
leading: BackButton(),
|
leading: BackButton(),
|
||||||
@ -134,7 +134,7 @@ class _ArtistProfileState extends State<ArtistProfile> {
|
|||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator.adaptive());
|
child: CircularProgressIndicator.adaptive());
|
||||||
}
|
}
|
||||||
Playback playback = context.watch<Playback>();
|
Playback playback = ref.watch(playbackProvider);
|
||||||
var isPlaylistPlaying =
|
var isPlaylistPlaying =
|
||||||
playback.currentPlaylist?.id == snapshot.data?.id;
|
playback.currentPlaylist?.id == snapshot.data?.id;
|
||||||
playPlaylist(List<Track> tracks, {Track? currentTrack}) {
|
playPlaylist(List<Track> tracks, {Track? currentTrack}) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Playlist/PlaylistCard.dart';
|
import 'package:spotube/components/Playlist/PlaylistCard.dart';
|
||||||
import 'package:spotube/components/Playlist/PlaylistGenreView.dart';
|
import 'package:spotube/components/Playlist/PlaylistGenreView.dart';
|
||||||
@ -51,14 +51,15 @@ class _CategoryCardState extends State<CategoryCard> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Consumer<SpotifyDI>(
|
Consumer(
|
||||||
builder: (context, data, child) {
|
builder: (context, ref, child) {
|
||||||
|
SpotifyApi spotifyApi = ref.watch(spotifyProvider);
|
||||||
return FutureBuilder<Iterable<PlaylistSimple>>(
|
return FutureBuilder<Iterable<PlaylistSimple>>(
|
||||||
future: widget.playlists == null
|
future: widget.playlists == null
|
||||||
? (widget.category.id != "user-featured-playlists"
|
? (widget.category.id != "user-featured-playlists"
|
||||||
? data.spotifyApi.playlists
|
? spotifyApi.playlists
|
||||||
.getByCategoryId(widget.category.id!)
|
.getByCategoryId(widget.category.id!)
|
||||||
: data.spotifyApi.playlists.featured)
|
: spotifyApi.playlists.featured)
|
||||||
.getPage(4, 0)
|
.getPage(4, 0)
|
||||||
.then((value) => value.items ?? [])
|
.then((value) => value.items ?? [])
|
||||||
: Future.value(widget.playlists),
|
: Future.value(widget.playlists),
|
||||||
|
@ -3,8 +3,8 @@ import 'dart:io';
|
|||||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:oauth2/oauth2.dart' show AuthorizationException;
|
import 'package:oauth2/oauth2.dart' show AuthorizationException;
|
||||||
import 'package:spotify/spotify.dart' hide Image, Player, Search;
|
import 'package:spotify/spotify.dart' hide Image, Player, Search;
|
||||||
@ -33,14 +33,14 @@ List<String> spotifyScopes = [
|
|||||||
"playlist-read-collaborative"
|
"playlist-read-collaborative"
|
||||||
];
|
];
|
||||||
|
|
||||||
class Home extends StatefulWidget {
|
class Home extends ConsumerStatefulWidget {
|
||||||
const Home({Key? key}) : super(key: key);
|
const Home({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_HomeState createState() => _HomeState();
|
_HomeState createState() => _HomeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeState extends State<Home> {
|
class _HomeState extends ConsumerState<Home> {
|
||||||
final PagingController<int, Category> _pagingController =
|
final PagingController<int, Category> _pagingController =
|
||||||
PagingController(firstPageKey: 0);
|
PagingController(firstPageKey: 0);
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ class _HomeState extends State<Home> {
|
|||||||
DateTime? expiration =
|
DateTime? expiration =
|
||||||
expirationStr != null ? DateTime.parse(expirationStr) : null;
|
expirationStr != null ? DateTime.parse(expirationStr) : null;
|
||||||
try {
|
try {
|
||||||
Auth authProvider = context.read<Auth>();
|
Auth auth = ref.read(authProvider);
|
||||||
|
|
||||||
if (clientId != null && clientSecret != null) {
|
if (clientId != null && clientSecret != null) {
|
||||||
SpotifyApi spotifyApi = SpotifyApi(
|
SpotifyApi spotifyApi = SpotifyApi(
|
||||||
@ -78,7 +78,7 @@ class _HomeState extends State<Home> {
|
|||||||
);
|
);
|
||||||
SpotifyApiCredentials credentials = await spotifyApi.getCredentials();
|
SpotifyApiCredentials credentials = await spotifyApi.getCredentials();
|
||||||
if (credentials.accessToken?.isNotEmpty ?? false) {
|
if (credentials.accessToken?.isNotEmpty ?? false) {
|
||||||
authProvider.setAuthState(
|
auth.setAuthState(
|
||||||
clientId: clientId,
|
clientId: clientId,
|
||||||
clientSecret: clientSecret,
|
clientSecret: clientSecret,
|
||||||
accessToken:
|
accessToken:
|
||||||
@ -91,8 +91,8 @@ class _HomeState extends State<Home> {
|
|||||||
}
|
}
|
||||||
_pagingController.addPageRequestListener((pageKey) async {
|
_pagingController.addPageRequestListener((pageKey) async {
|
||||||
try {
|
try {
|
||||||
SpotifyDI data = context.read<SpotifyDI>();
|
SpotifyApi spotifyApi = ref.read(spotifyProvider);
|
||||||
Page<Category> categories = await data.spotifyApi.categories
|
Page<Category> categories = await spotifyApi.categories
|
||||||
.list(country: "US")
|
.list(country: "US")
|
||||||
.getPage(15, pageKey);
|
.getPage(15, pageKey);
|
||||||
|
|
||||||
@ -113,10 +113,10 @@ class _HomeState extends State<Home> {
|
|||||||
_pagingController.error = e;
|
_pagingController.error = e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} on AuthorizationException catch (e) {
|
} on AuthorizationException catch (_) {
|
||||||
if (clientId != null && clientSecret != null) {
|
if (clientId != null && clientSecret != null) {
|
||||||
oauthLogin(
|
oauthLogin(
|
||||||
context,
|
ref.read(authProvider),
|
||||||
clientId: clientId,
|
clientId: clientId,
|
||||||
clientSecret: clientSecret,
|
clientSecret: clientSecret,
|
||||||
);
|
);
|
||||||
@ -136,8 +136,9 @@ class _HomeState extends State<Home> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Auth authProvider = Provider.of<Auth>(context);
|
Auth auth = ref.watch(authProvider);
|
||||||
if (!authProvider.isLoggedIn) {
|
SpotifyApi spotify = ref.watch(spotifyProvider);
|
||||||
|
if (!auth.isLoggedIn) {
|
||||||
return const Login();
|
return const Login();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,49 +200,45 @@ class _HomeState extends State<Home> {
|
|||||||
style: Theme.of(context).textTheme.headline4),
|
style: Theme.of(context).textTheme.headline4),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
trailing:
|
trailing: FutureBuilder<User>(
|
||||||
Consumer<SpotifyDI>(builder: (context, data, widget) {
|
future: spotify.me.get(),
|
||||||
return FutureBuilder<User>(
|
builder: (context, snapshot) {
|
||||||
future: data.spotifyApi.me.get(),
|
var avatarImg = imageToUrlString(snapshot.data?.images,
|
||||||
builder: (context, snapshot) {
|
index: (snapshot.data?.images?.length ?? 1) - 1);
|
||||||
var avatarImg = imageToUrlString(snapshot.data?.images,
|
return Padding(
|
||||||
index: (snapshot.data?.images?.length ?? 1) - 1);
|
padding: const EdgeInsets.all(16),
|
||||||
return Padding(
|
child: Row(
|
||||||
padding: const EdgeInsets.all(16),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
child: Row(
|
children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
CircleAvatar(
|
||||||
children: [
|
backgroundImage:
|
||||||
CircleAvatar(
|
CachedNetworkImageProvider(avatarImg),
|
||||||
backgroundImage:
|
),
|
||||||
CachedNetworkImageProvider(avatarImg),
|
const SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
snapshot.data?.displayName ?? "User's name",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
),
|
||||||
Text(
|
],
|
||||||
snapshot.data?.displayName ?? "User's name",
|
),
|
||||||
style: const TextStyle(
|
IconButton(
|
||||||
fontWeight: FontWeight.bold,
|
icon: const Icon(Icons.settings_outlined),
|
||||||
),
|
onPressed: () {
|
||||||
),
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
],
|
builder: (context) {
|
||||||
),
|
return const Settings();
|
||||||
IconButton(
|
},
|
||||||
icon: const Icon(Icons.settings_outlined),
|
));
|
||||||
onPressed: () {
|
}),
|
||||||
Navigator.of(context)
|
],
|
||||||
.push(MaterialPageRoute(
|
),
|
||||||
builder: (context) {
|
);
|
||||||
return const Settings();
|
},
|
||||||
},
|
),
|
||||||
));
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
// contents of the spotify
|
// contents of the spotify
|
||||||
if (_selectedIndex == 0)
|
if (_selectedIndex == 0)
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Artist/ArtistCard.dart';
|
import 'package:spotube/components/Artist/ArtistCard.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class UserArtists extends StatefulWidget {
|
class UserArtists extends ConsumerStatefulWidget {
|
||||||
const UserArtists({Key? key}) : super(key: key);
|
const UserArtists({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<UserArtists> createState() => _UserArtistsState();
|
ConsumerState<UserArtists> createState() => _UserArtistsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UserArtistsState extends State<UserArtists> {
|
class _UserArtistsState extends ConsumerState<UserArtists> {
|
||||||
final PagingController<String, Artist> _pagingController =
|
final PagingController<String, Artist> _pagingController =
|
||||||
PagingController(firstPageKey: "");
|
PagingController(firstPageKey: "");
|
||||||
|
|
||||||
@ -22,8 +22,8 @@ class _UserArtistsState extends State<UserArtists> {
|
|||||||
WidgetsBinding.instance?.addPostFrameCallback((timestamp) {
|
WidgetsBinding.instance?.addPostFrameCallback((timestamp) {
|
||||||
_pagingController.addPageRequestListener((pageKey) async {
|
_pagingController.addPageRequestListener((pageKey) async {
|
||||||
try {
|
try {
|
||||||
SpotifyDI data = context.read<SpotifyDI>();
|
SpotifyApi spotifyApi = ref.read(spotifyProvider);
|
||||||
CursorPage<Artist> artists = await data.spotifyApi.me
|
CursorPage<Artist> artists = await spotifyApi.me
|
||||||
.following(FollowingType.artist)
|
.following(FollowingType.artist)
|
||||||
.getPage(15, pageKey);
|
.getPage(15, pageKey);
|
||||||
|
|
||||||
@ -51,10 +51,10 @@ class _UserArtistsState extends State<UserArtists> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SpotifyDI data = context.watch<SpotifyDI>();
|
SpotifyApi spotifyApi = ref.watch(spotifyProvider);
|
||||||
|
|
||||||
return FutureBuilder<CursorPage<Artist>>(
|
return FutureBuilder<CursorPage<Artist>>(
|
||||||
future: data.spotifyApi.me.following(FollowingType.artist).first(),
|
future: spotifyApi.me.following(FollowingType.artist).first(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (!snapshot.hasData) {
|
if (!snapshot.hasData) {
|
||||||
return const Center(child: CircularProgressIndicator.adaptive());
|
return const Center(child: CircularProgressIndicator.adaptive());
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import 'package:flutter/material.dart' hide Image;
|
import 'package:flutter/material.dart' hide Image;
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Playlist/PlaylistCard.dart';
|
import 'package:spotube/components/Playlist/PlaylistCard.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class UserPlaylists extends StatelessWidget {
|
class UserPlaylists extends ConsumerWidget {
|
||||||
const UserPlaylists({Key? key}) : super(key: key);
|
const UserPlaylists({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, ref) {
|
||||||
SpotifyDI data = context.watch<SpotifyDI>();
|
SpotifyApi spotifyApi = ref.watch(spotifyProvider);
|
||||||
|
|
||||||
return FutureBuilder<Iterable<PlaylistSimple>>(
|
return FutureBuilder<Iterable<PlaylistSimple>>(
|
||||||
future: data.spotifyApi.playlists.me.all(),
|
future: spotifyApi.playlists.me.all(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (!snapshot.hasData) {
|
if (!snapshot.hasData) {
|
||||||
return const Center(child: CircularProgressIndicator.adaptive());
|
return const Center(child: CircularProgressIndicator.adaptive());
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:spotube/components/Shared/Hyperlink.dart';
|
import 'package:spotube/components/Shared/Hyperlink.dart';
|
||||||
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
||||||
@ -8,14 +8,14 @@ import 'package:spotube/models/LocalStorageKeys.dart';
|
|||||||
import 'package:spotube/provider/Auth.dart';
|
import 'package:spotube/provider/Auth.dart';
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
import 'package:spotube/provider/UserPreferences.dart';
|
||||||
|
|
||||||
class Login extends StatefulWidget {
|
class Login extends ConsumerStatefulWidget {
|
||||||
const Login({Key? key}) : super(key: key);
|
const Login({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_LoginState createState() => _LoginState();
|
_LoginState createState() => _LoginState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LoginState extends State<Login> {
|
class _LoginState extends ConsumerState<Login> {
|
||||||
String clientId = "";
|
String clientId = "";
|
||||||
String clientSecret = "";
|
String clientSecret = "";
|
||||||
String accessToken = "";
|
String accessToken = "";
|
||||||
@ -28,7 +28,8 @@ class _LoginState extends State<Login> {
|
|||||||
_fieldError = true;
|
_fieldError = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await oauthLogin(context, clientId: clientId, clientSecret: clientSecret);
|
await oauthLogin(ref.read(authProvider),
|
||||||
|
clientId: clientId, clientSecret: clientSecret);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("[Login.handleLogin] $e");
|
print("[Login.handleLogin] $e");
|
||||||
}
|
}
|
||||||
@ -36,99 +37,95 @@ class _LoginState extends State<Login> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Consumer<Auth>(
|
Auth authState = ref.watch(authProvider);
|
||||||
builder: (context, authState, child) {
|
return Scaffold(
|
||||||
return Scaffold(
|
appBar: const PageWindowTitleBar(),
|
||||||
appBar: const PageWindowTitleBar(),
|
body: SingleChildScrollView(
|
||||||
body: SingleChildScrollView(
|
child: Center(
|
||||||
child: Center(
|
child: Column(
|
||||||
child: Column(
|
children: [
|
||||||
children: [
|
Image.asset(
|
||||||
Image.asset(
|
"assets/spotube-logo.png",
|
||||||
"assets/spotube-logo.png",
|
width: 400,
|
||||||
width: 400,
|
height: 400,
|
||||||
height: 400,
|
|
||||||
),
|
|
||||||
Text("Add your spotify credentials to get started",
|
|
||||||
style: Theme.of(context).textTheme.headline4),
|
|
||||||
const Text(
|
|
||||||
"Don't worry, any of your credentials won't be collected or shared with anyone"),
|
|
||||||
const Hyperlink("How to get these client-id & client-secret?",
|
|
||||||
"https://github.com/KRTirtho/spotube#configuration"),
|
|
||||||
const SizedBox(
|
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxWidth: 400,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
TextField(
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: "Spotify Client ID",
|
|
||||||
label: Text("ClientID"),
|
|
||||||
),
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
clientId = value;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
TextField(
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: "Spotify Client Secret",
|
|
||||||
label: Text("Client Secret"),
|
|
||||||
),
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
clientSecret = value;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
const Divider(color: Colors.grey),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
TextField(
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
label: Text("Genius Access Token (optional)"),
|
|
||||||
),
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
accessToken = value;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () async {
|
|
||||||
await handleLogin(authState);
|
|
||||||
UserPreferences preferences =
|
|
||||||
context.read<UserPreferences>();
|
|
||||||
SharedPreferences localStorage =
|
|
||||||
await SharedPreferences.getInstance();
|
|
||||||
preferences.setGeniusAccessToken(accessToken);
|
|
||||||
await localStorage.setString(
|
|
||||||
LocalStorageKeys.geniusAccessToken,
|
|
||||||
accessToken);
|
|
||||||
setState(() {
|
|
||||||
accessToken = "";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const Text("Submit"),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
Text("Add your spotify credentials to get started",
|
||||||
|
style: Theme.of(context).textTheme.headline4),
|
||||||
|
const Text(
|
||||||
|
"Don't worry, any of your credentials won't be collected or shared with anyone"),
|
||||||
|
const Hyperlink("How to get these client-id & client-secret?",
|
||||||
|
"https://github.com/KRTirtho/spotube#configuration"),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 400,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: "Spotify Client ID",
|
||||||
|
label: Text("ClientID"),
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
clientId = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: "Spotify Client Secret",
|
||||||
|
label: Text("Client Secret"),
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
clientSecret = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
const Divider(color: Colors.grey),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
label: Text("Genius Access Token (optional)"),
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
accessToken = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await handleLogin(authState);
|
||||||
|
UserPreferences preferences =
|
||||||
|
ref.read(userPreferencesProvider);
|
||||||
|
SharedPreferences localStorage =
|
||||||
|
await SharedPreferences.getInstance();
|
||||||
|
preferences.setGeniusAccessToken(accessToken);
|
||||||
|
await localStorage.setString(
|
||||||
|
LocalStorageKeys.geniusAccessToken, accessToken);
|
||||||
|
setState(() {
|
||||||
|
accessToken = "";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: const Text("Submit"),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Settings.dart';
|
import 'package:spotube/components/Settings.dart';
|
||||||
import 'package:spotube/helpers/artist-to-string.dart';
|
import 'package:spotube/helpers/artist-to-string.dart';
|
||||||
@ -7,20 +7,20 @@ import 'package:spotube/helpers/getLyrics.dart';
|
|||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
import 'package:spotube/provider/UserPreferences.dart';
|
||||||
|
|
||||||
class Lyrics extends StatefulWidget {
|
class Lyrics extends ConsumerStatefulWidget {
|
||||||
const Lyrics({Key? key}) : super(key: key);
|
const Lyrics({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<Lyrics> createState() => _LyricsState();
|
ConsumerState<Lyrics> createState() => _LyricsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LyricsState extends State<Lyrics> {
|
class _LyricsState extends ConsumerState<Lyrics> {
|
||||||
Map<String, String> _lyrics = {};
|
Map<String, String> _lyrics = {};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Playback playback = context.watch<Playback>();
|
Playback playback = ref.watch(playbackProvider);
|
||||||
UserPreferences userPreferences = context.watch<UserPreferences>();
|
UserPreferences userPreferences = ref.watch(userPreferencesProvider);
|
||||||
|
|
||||||
bool hasToken = (userPreferences.geniusAccessToken != null ||
|
bool hasToken = (userPreferences.geniusAccessToken != null ||
|
||||||
(userPreferences.geniusAccessToken?.isNotEmpty ?? false));
|
(userPreferences.geniusAccessToken?.isNotEmpty ?? false));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:just_audio/just_audio.dart';
|
import 'package:just_audio/just_audio.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Shared/DownloadTrackButton.dart';
|
import 'package:spotube/components/Shared/DownloadTrackButton.dart';
|
||||||
@ -10,18 +11,17 @@ import 'package:spotube/helpers/image-to-url-string.dart';
|
|||||||
import 'package:spotube/helpers/search-youtube.dart';
|
import 'package:spotube/helpers/search-youtube.dart';
|
||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
|
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
|
||||||
|
|
||||||
class Player extends StatefulWidget {
|
class Player extends ConsumerStatefulWidget {
|
||||||
const Player({Key? key}) : super(key: key);
|
const Player({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_PlayerState createState() => _PlayerState();
|
_PlayerState createState() => _PlayerState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
class _PlayerState extends ConsumerState<Player> with WidgetsBindingObserver {
|
||||||
late AudioPlayer player;
|
late AudioPlayer player;
|
||||||
bool _isPlaying = false;
|
bool _isPlaying = false;
|
||||||
bool _shuffled = false;
|
bool _shuffled = false;
|
||||||
@ -111,7 +111,7 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _movePlaylistPositionBy(int pos) {
|
void _movePlaylistPositionBy(int pos) {
|
||||||
Playback playback = context.read<Playback>();
|
Playback playback = ref.read(playbackProvider);
|
||||||
if (playback.currentTrack != null && playback.currentPlaylist != null) {
|
if (playback.currentTrack != null && playback.currentPlaylist != null) {
|
||||||
int index = playback.currentPlaylist!.trackIds
|
int index = playback.currentPlaylist!.trackIds
|
||||||
.indexOf(playback.currentTrack!.id!) +
|
.indexOf(playback.currentTrack!.id!) +
|
||||||
@ -198,8 +198,9 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Theme.of(context).backgroundColor,
|
color: Theme.of(context).backgroundColor,
|
||||||
child: Consumer<Playback>(
|
child: Consumer(
|
||||||
builder: (context, playback, widget) {
|
builder: (context, ref, widget) {
|
||||||
|
Playback playback = ref.watch(playbackProvider);
|
||||||
if (playback.currentPlaylist != null &&
|
if (playback.currentPlaylist != null &&
|
||||||
playback.currentTrack != null) {
|
playback.currentTrack != null) {
|
||||||
_playTrack(playback.currentTrack!, playback);
|
_playTrack(playback.currentTrack!, playback);
|
||||||
@ -348,10 +349,11 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
|||||||
DownloadTrackButton(
|
DownloadTrackButton(
|
||||||
track: playback.currentTrack,
|
track: playback.currentTrack,
|
||||||
),
|
),
|
||||||
Consumer<SpotifyDI>(builder: (context, data, widget) {
|
Consumer(builder: (context, ref, widget) {
|
||||||
|
SpotifyApi spotifyApi = ref.watch(spotifyProvider);
|
||||||
return FutureBuilder<bool>(
|
return FutureBuilder<bool>(
|
||||||
future: playback.currentTrack?.id != null
|
future: playback.currentTrack?.id != null
|
||||||
? data.spotifyApi.tracks.me
|
? spotifyApi.tracks.me
|
||||||
.containsOne(playback.currentTrack!.id!)
|
.containsOne(playback.currentTrack!.id!)
|
||||||
: Future.value(false),
|
: Future.value(false),
|
||||||
initialData: false,
|
initialData: false,
|
||||||
@ -367,7 +369,7 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (!isLiked &&
|
if (!isLiked &&
|
||||||
playback.currentTrack?.id != null) {
|
playback.currentTrack?.id != null) {
|
||||||
data.spotifyApi.tracks.me
|
spotifyApi.tracks.me
|
||||||
.saveOne(
|
.saveOne(
|
||||||
playback.currentTrack!.id!)
|
playback.currentTrack!.id!)
|
||||||
.then((value) => setState(() {}));
|
.then((value) => setState(() {}));
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
import 'package:hotkey_manager/hotkey_manager.dart';
|
||||||
import 'package:spotube/helpers/zero-pad-num-str.dart';
|
import 'package:spotube/helpers/zero-pad-num-str.dart';
|
||||||
import 'package:spotube/models/GlobalKeyActions.dart';
|
import 'package:spotube/models/GlobalKeyActions.dart';
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
import 'package:spotube/provider/UserPreferences.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class PlayerControls extends StatefulWidget {
|
class PlayerControls extends ConsumerStatefulWidget {
|
||||||
final Stream<Duration> positionStream;
|
final Stream<Duration> positionStream;
|
||||||
final bool isPlaying;
|
final bool isPlaying;
|
||||||
final Duration duration;
|
final Duration duration;
|
||||||
@ -38,7 +38,7 @@ class PlayerControls extends StatefulWidget {
|
|||||||
_PlayerControlsState createState() => _PlayerControlsState();
|
_PlayerControlsState createState() => _PlayerControlsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlayerControlsState extends State<PlayerControls> {
|
class _PlayerControlsState extends ConsumerState<PlayerControls> {
|
||||||
StreamSubscription? _timePositionListener;
|
StreamSubscription? _timePositionListener;
|
||||||
late List<GlobalKeyActions> _hotKeys = [];
|
late List<GlobalKeyActions> _hotKeys = [];
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ class _PlayerControlsState extends State<PlayerControls> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
UserPreferences preferences = context.watch<UserPreferences>();
|
UserPreferences preferences = ref.watch(userPreferencesProvider);
|
||||||
_configureHotKeys(preferences);
|
_configureHotKeys(preferences);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Playlist/PlaylistView.dart';
|
import 'package:spotube/components/Playlist/PlaylistView.dart';
|
||||||
import 'package:spotube/components/Shared/PlaybuttonCard.dart';
|
import 'package:spotube/components/Shared/PlaybuttonCard.dart';
|
||||||
@ -7,17 +7,17 @@ import 'package:spotube/helpers/image-to-url-string.dart';
|
|||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class PlaylistCard extends StatefulWidget {
|
class PlaylistCard extends ConsumerStatefulWidget {
|
||||||
final PlaylistSimple playlist;
|
final PlaylistSimple playlist;
|
||||||
const PlaylistCard(this.playlist, {Key? key}) : super(key: key);
|
const PlaylistCard(this.playlist, {Key? key}) : super(key: key);
|
||||||
@override
|
@override
|
||||||
_PlaylistCardState createState() => _PlaylistCardState();
|
_PlaylistCardState createState() => _PlaylistCardState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlaylistCardState extends State<PlaylistCard> {
|
class _PlaylistCardState extends ConsumerState<PlaylistCard> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Playback playback = context.watch<Playback>();
|
Playback playback = ref.watch(playbackProvider);
|
||||||
bool isPlaylistPlaying = playback.currentPlaylist != null &&
|
bool isPlaylistPlaying = playback.currentPlaylist != null &&
|
||||||
playback.currentPlaylist!.id == widget.playlist.id;
|
playback.currentPlaylist!.id == widget.playlist.id;
|
||||||
return PlaybuttonCard(
|
return PlaybuttonCard(
|
||||||
@ -33,13 +33,13 @@ class _PlaylistCardState extends State<PlaylistCard> {
|
|||||||
},
|
},
|
||||||
onPlaybuttonPressed: () async {
|
onPlaybuttonPressed: () async {
|
||||||
if (isPlaylistPlaying) return;
|
if (isPlaylistPlaying) return;
|
||||||
SpotifyDI data = context.read<SpotifyDI>();
|
SpotifyApi spotifyApi = ref.read(spotifyProvider);
|
||||||
|
|
||||||
List<Track> tracks = (widget.playlist.id != "user-liked-tracks"
|
List<Track> tracks = (widget.playlist.id != "user-liked-tracks"
|
||||||
? await data.spotifyApi.playlists
|
? await spotifyApi.playlists
|
||||||
.getTracksByPlaylistId(widget.playlist.id!)
|
.getTracksByPlaylistId(widget.playlist.id!)
|
||||||
.all()
|
.all()
|
||||||
: await data.spotifyApi.tracks.me.saved
|
: await spotifyApi.tracks.me.saved
|
||||||
.all()
|
.all()
|
||||||
.then((tracks) => tracks.map((e) => e.track!)))
|
.then((tracks) => tracks.map((e) => e.track!)))
|
||||||
.toList();
|
.toList();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
||||||
import 'package:spotube/components/Playlist/PlaylistCard.dart';
|
import 'package:spotube/components/Playlist/PlaylistCard.dart';
|
||||||
@ -33,39 +33,42 @@ class _PlaylistGenreViewState extends State<PlaylistGenreView> {
|
|||||||
style: Theme.of(context).textTheme.headline4,
|
style: Theme.of(context).textTheme.headline4,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
Consumer<SpotifyDI>(
|
Consumer(
|
||||||
builder: (context, data, child) => Expanded(
|
builder: (context, ref, child) {
|
||||||
child: SingleChildScrollView(
|
SpotifyApi spotifyApi = ref.watch(spotifyProvider);
|
||||||
child: FutureBuilder<Iterable<PlaylistSimple>>(
|
return Expanded(
|
||||||
future: widget.playlists == null
|
child: SingleChildScrollView(
|
||||||
? (widget.genreId != "user-featured-playlists"
|
child: FutureBuilder<Iterable<PlaylistSimple>>(
|
||||||
? data.spotifyApi.playlists
|
future: widget.playlists == null
|
||||||
.getByCategoryId(widget.genreId)
|
? (widget.genreId != "user-featured-playlists"
|
||||||
.all()
|
? spotifyApi.playlists
|
||||||
: data.spotifyApi.playlists.featured.all())
|
.getByCategoryId(widget.genreId)
|
||||||
: Future.value(widget.playlists),
|
.all()
|
||||||
builder: (context, snapshot) {
|
: spotifyApi.playlists.featured.all())
|
||||||
if (snapshot.hasError) {
|
: Future.value(widget.playlists),
|
||||||
return const Center(child: Text("Error occurred"));
|
builder: (context, snapshot) {
|
||||||
}
|
if (snapshot.hasError) {
|
||||||
if (!snapshot.hasData) {
|
return const Center(child: Text("Error occurred"));
|
||||||
return const CircularProgressIndicator.adaptive();
|
}
|
||||||
}
|
if (!snapshot.hasData) {
|
||||||
return Center(
|
return const CircularProgressIndicator.adaptive();
|
||||||
child: Wrap(
|
}
|
||||||
children: snapshot.data!
|
return Center(
|
||||||
.map(
|
child: Wrap(
|
||||||
(playlist) => Padding(
|
children: snapshot.data!
|
||||||
padding: const EdgeInsets.all(8.0),
|
.map(
|
||||||
child: PlaylistCard(playlist),
|
(playlist) => Padding(
|
||||||
),
|
padding: const EdgeInsets.all(8.0),
|
||||||
)
|
child: PlaylistCard(playlist),
|
||||||
.toList(),
|
),
|
||||||
),
|
)
|
||||||
);
|
.toList(),
|
||||||
}),
|
),
|
||||||
),
|
);
|
||||||
),
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
||||||
import 'package:spotube/components/Shared/TracksTableView.dart';
|
import 'package:spotube/components/Shared/TracksTableView.dart';
|
||||||
import 'package:spotube/helpers/image-to-url-string.dart';
|
import 'package:spotube/helpers/image-to-url-string.dart';
|
||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class PlaylistView extends StatefulWidget {
|
class PlaylistView extends ConsumerStatefulWidget {
|
||||||
final PlaylistSimple playlist;
|
final PlaylistSimple playlist;
|
||||||
const PlaylistView(this.playlist, {Key? key}) : super(key: key);
|
const PlaylistView(this.playlist, {Key? key}) : super(key: key);
|
||||||
@override
|
@override
|
||||||
_PlaylistViewState createState() => _PlaylistViewState();
|
_PlaylistViewState createState() => _PlaylistViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlaylistViewState extends State<PlaylistView> {
|
class _PlaylistViewState extends ConsumerState<PlaylistView> {
|
||||||
playPlaylist(Playback playback, List<Track> tracks, {Track? currentTrack}) {
|
playPlaylist(Playback playback, List<Track> tracks, {Track? currentTrack}) {
|
||||||
currentTrack ??= tracks.first;
|
currentTrack ??= tracks.first;
|
||||||
var isPlaylistPlaying = playback.currentPlaylist?.id != null &&
|
var isPlaylistPlaying = playback.currentPlaylist?.id != null &&
|
||||||
@ -36,71 +36,70 @@ class _PlaylistViewState extends State<PlaylistView> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Playback playback = context.watch<Playback>();
|
Playback playback = ref.watch(playbackProvider);
|
||||||
|
SpotifyApi spotifyApi = ref.watch(spotifyProvider);
|
||||||
var isPlaylistPlaying = playback.currentPlaylist?.id != null &&
|
var isPlaylistPlaying = playback.currentPlaylist?.id != null &&
|
||||||
playback.currentPlaylist?.id == widget.playlist.id;
|
playback.currentPlaylist?.id == widget.playlist.id;
|
||||||
return Consumer<SpotifyDI>(builder: (_, data, __) {
|
return Scaffold(
|
||||||
return Scaffold(
|
body: FutureBuilder<Iterable<Track>>(
|
||||||
body: FutureBuilder<Iterable<Track>>(
|
future: widget.playlist.id != "user-liked-tracks"
|
||||||
future: widget.playlist.id != "user-liked-tracks"
|
? spotifyApi.playlists
|
||||||
? data.spotifyApi.playlists
|
.getTracksByPlaylistId(widget.playlist.id)
|
||||||
.getTracksByPlaylistId(widget.playlist.id)
|
.all()
|
||||||
.all()
|
: spotifyApi.tracks.me.saved
|
||||||
: data.spotifyApi.tracks.me.saved
|
.all()
|
||||||
.all()
|
.then((tracks) => tracks.map((e) => e.track!)),
|
||||||
.then((tracks) => tracks.map((e) => e.track!)),
|
builder: (context, snapshot) {
|
||||||
builder: (context, snapshot) {
|
List<Track> tracks = snapshot.data?.toList() ?? [];
|
||||||
List<Track> tracks = snapshot.data?.toList() ?? [];
|
return Column(
|
||||||
return Column(
|
children: [
|
||||||
children: [
|
PageWindowTitleBar(
|
||||||
PageWindowTitleBar(
|
leading: Row(
|
||||||
leading: Row(
|
children: [
|
||||||
children: [
|
// nav back
|
||||||
// nav back
|
const BackButton(),
|
||||||
const BackButton(),
|
// heart playlist
|
||||||
// heart playlist
|
IconButton(
|
||||||
IconButton(
|
icon: const Icon(Icons.favorite_outline_rounded),
|
||||||
icon: const Icon(Icons.favorite_outline_rounded),
|
onPressed: () {},
|
||||||
onPressed: () {},
|
),
|
||||||
|
// play playlist
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
isPlaylistPlaying
|
||||||
|
? Icons.stop_rounded
|
||||||
|
: Icons.play_arrow_rounded,
|
||||||
),
|
),
|
||||||
// play playlist
|
onPressed: snapshot.hasData
|
||||||
IconButton(
|
? () => playPlaylist(playback, tracks)
|
||||||
icon: Icon(
|
: null,
|
||||||
isPlaylistPlaying
|
)
|
||||||
? Icons.stop_rounded
|
],
|
||||||
: Icons.play_arrow_rounded,
|
|
||||||
),
|
|
||||||
onPressed: snapshot.hasData
|
|
||||||
? () => playPlaylist(playback, tracks)
|
|
||||||
: null,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Center(
|
),
|
||||||
child: Text(widget.playlist.name!,
|
Center(
|
||||||
style: Theme.of(context).textTheme.headline4),
|
child: Text(widget.playlist.name!,
|
||||||
),
|
style: Theme.of(context).textTheme.headline4),
|
||||||
snapshot.hasError
|
),
|
||||||
? const Center(child: Text("Error occurred"))
|
snapshot.hasError
|
||||||
: !snapshot.hasData
|
? const Center(child: Text("Error occurred"))
|
||||||
? const Expanded(
|
: !snapshot.hasData
|
||||||
child: Center(
|
? const Expanded(
|
||||||
child: CircularProgressIndicator.adaptive()),
|
child: Center(
|
||||||
)
|
child: CircularProgressIndicator.adaptive()),
|
||||||
: TracksTableView(
|
)
|
||||||
|
: TracksTableView(
|
||||||
|
tracks,
|
||||||
|
onTrackPlayButtonPressed: (currentTrack) =>
|
||||||
|
playPlaylist(
|
||||||
|
playback,
|
||||||
tracks,
|
tracks,
|
||||||
onTrackPlayButtonPressed: (currentTrack) =>
|
currentTrack: currentTrack,
|
||||||
playPlaylist(
|
|
||||||
playback,
|
|
||||||
tracks,
|
|
||||||
currentTrack: currentTrack,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
);
|
],
|
||||||
}),
|
);
|
||||||
);
|
}),
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Album/AlbumCard.dart';
|
import 'package:spotube/components/Album/AlbumCard.dart';
|
||||||
import 'package:spotube/components/Artist/ArtistCard.dart';
|
import 'package:spotube/components/Artist/ArtistCard.dart';
|
||||||
@ -11,14 +11,14 @@ import 'package:spotube/helpers/zero-pad-num-str.dart';
|
|||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
import 'package:spotube/provider/SpotifyDI.dart';
|
||||||
|
|
||||||
class Search extends StatefulWidget {
|
class Search extends ConsumerStatefulWidget {
|
||||||
const Search({Key? key}) : super(key: key);
|
const Search({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<Search> createState() => _SearchState();
|
ConsumerState<Search> createState() => _SearchState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SearchState extends State<Search> {
|
class _SearchState extends ConsumerState<Search> {
|
||||||
late TextEditingController _controller;
|
late TextEditingController _controller;
|
||||||
|
|
||||||
String searchTerm = "";
|
String searchTerm = "";
|
||||||
@ -31,7 +31,7 @@ class _SearchState extends State<Search> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SpotifyApi spotify = context.watch<SpotifyDI>().spotifyApi;
|
SpotifyApi spotify = ref.watch(spotifyProvider);
|
||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -80,7 +80,7 @@ class _SearchState extends State<Search> {
|
|||||||
} else if (!snapshot.hasData && searchTerm.isEmpty) {
|
} else if (!snapshot.hasData && searchTerm.isEmpty) {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
Playback playback = context.watch<Playback>();
|
Playback playback = ref.watch(playbackProvider);
|
||||||
List<AlbumSimple> albums = [];
|
List<AlbumSimple> albums = [];
|
||||||
List<Artist> artists = [];
|
List<Artist> artists = [];
|
||||||
List<Track> tracks = [];
|
List<Track> tracks = [];
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:spotube/components/Settings/SettingsHotkeyTile.dart';
|
import 'package:spotube/components/Settings/SettingsHotkeyTile.dart';
|
||||||
import 'package:spotube/components/Shared/Hyperlink.dart';
|
import 'package:spotube/components/Shared/Hyperlink.dart';
|
||||||
@ -10,14 +9,14 @@ import 'package:spotube/models/LocalStorageKeys.dart';
|
|||||||
import 'package:spotube/provider/Auth.dart';
|
import 'package:spotube/provider/Auth.dart';
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
import 'package:spotube/provider/UserPreferences.dart';
|
||||||
|
|
||||||
class Settings extends StatefulWidget {
|
class Settings extends ConsumerStatefulWidget {
|
||||||
const Settings({Key? key}) : super(key: key);
|
const Settings({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SettingsState createState() => _SettingsState();
|
_SettingsState createState() => _SettingsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SettingsState extends State<Settings> {
|
class _SettingsState extends ConsumerState<Settings> {
|
||||||
TextEditingController? _textEditingController;
|
TextEditingController? _textEditingController;
|
||||||
String? _geniusAccessToken;
|
String? _geniusAccessToken;
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ class _SettingsState extends State<Settings> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
UserPreferences preferences = context.watch<UserPreferences>();
|
UserPreferences preferences = ref.watch(userPreferencesProvider);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: PageWindowTitleBar(
|
appBar: PageWindowTitleBar(
|
||||||
@ -151,7 +150,7 @@ class _SettingsState extends State<Settings> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Builder(builder: (context) {
|
Builder(builder: (context) {
|
||||||
var auth = context.read<Auth>();
|
Auth auth = ref.watch(authProvider);
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Album/AlbumView.dart';
|
import 'package:spotube/components/Album/AlbumView.dart';
|
||||||
import 'package:spotube/components/Shared/LinkText.dart';
|
import 'package:spotube/components/Shared/LinkText.dart';
|
||||||
@ -9,7 +9,7 @@ import 'package:spotube/helpers/image-to-url-string.dart';
|
|||||||
import 'package:spotube/helpers/zero-pad-num-str.dart';
|
import 'package:spotube/helpers/zero-pad-num-str.dart';
|
||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
|
|
||||||
class TracksTableView extends StatelessWidget {
|
class TracksTableView extends ConsumerWidget {
|
||||||
final void Function(Track currentTrack)? onTrackPlayButtonPressed;
|
final void Function(Track currentTrack)? onTrackPlayButtonPressed;
|
||||||
final List<Track> tracks;
|
final List<Track> tracks;
|
||||||
const TracksTableView(this.tracks, {Key? key, this.onTrackPlayButtonPressed})
|
const TracksTableView(this.tracks, {Key? key, this.onTrackPlayButtonPressed})
|
||||||
@ -97,8 +97,8 @@ class TracksTableView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(context, ref) {
|
||||||
Playback playback = context.watch<Playback>();
|
Playback playback = ref.watch(playbackProvider);
|
||||||
TextStyle tableHeadStyle =
|
TextStyle tableHeadStyle =
|
||||||
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16);
|
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16);
|
||||||
return Expanded(
|
return Expanded(
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/Home.dart';
|
import 'package:spotube/components/Home.dart';
|
||||||
@ -9,7 +7,7 @@ import 'package:spotube/provider/Auth.dart';
|
|||||||
|
|
||||||
const redirectUri = "http://localhost:4304/auth/spotify/callback";
|
const redirectUri = "http://localhost:4304/auth/spotify/callback";
|
||||||
|
|
||||||
Future<void> oauthLogin(BuildContext context,
|
Future<void> oauthLogin(Auth auth,
|
||||||
{required String clientId, required String clientSecret}) async {
|
{required String clientId, required String clientSecret}) async {
|
||||||
try {
|
try {
|
||||||
String? accessToken;
|
String? accessToken;
|
||||||
@ -50,7 +48,7 @@ Future<void> oauthLogin(BuildContext context,
|
|||||||
clientSecret,
|
clientSecret,
|
||||||
);
|
);
|
||||||
|
|
||||||
Provider.of<Auth>(context, listen: false).setAuthState(
|
auth.setAuthState(
|
||||||
clientId: clientId,
|
clientId: clientId,
|
||||||
clientSecret: clientSecret,
|
clientSecret: clientSecret,
|
||||||
accessToken: accessToken,
|
accessToken: accessToken,
|
||||||
|
215
lib/main.dart
215
lib/main.dart
@ -1,20 +1,15 @@
|
|||||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
import 'package:hotkey_manager/hotkey_manager.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
|
||||||
import 'package:spotube/components/Home.dart';
|
import 'package:spotube/components/Home.dart';
|
||||||
import 'package:spotube/models/LocalStorageKeys.dart';
|
import 'package:spotube/models/LocalStorageKeys.dart';
|
||||||
import 'package:spotube/provider/Auth.dart';
|
|
||||||
import 'package:spotube/provider/Playback.dart';
|
|
||||||
import 'package:spotube/provider/SpotifyDI.dart';
|
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await hotKeyManager.unregisterAll();
|
await hotKeyManager.unregisterAll();
|
||||||
runApp(MyApp());
|
runApp(const ProviderScope(child: MyApp()));
|
||||||
doWhenWindowReady(() {
|
doWhenWindowReady(() {
|
||||||
appWindow.minSize = const Size(900, 700);
|
appWindow.minSize = const Size(900, 700);
|
||||||
appWindow.size = const Size(900, 700);
|
appWindow.size = const Size(900, 700);
|
||||||
@ -25,6 +20,8 @@ void main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatefulWidget {
|
class MyApp extends StatefulWidget {
|
||||||
|
const MyApp({Key? key}) : super(key: key);
|
||||||
|
|
||||||
static _MyAppState? of(BuildContext context) =>
|
static _MyAppState? of(BuildContext context) =>
|
||||||
context.findAncestorStateOfType<_MyAppState>();
|
context.findAncestorStateOfType<_MyAppState>();
|
||||||
@override
|
@override
|
||||||
@ -72,139 +69,95 @@ class _MyAppState extends State<MyApp> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiProvider(
|
return MaterialApp(
|
||||||
providers: [
|
debugShowCheckedModeBanner: false,
|
||||||
ChangeNotifierProvider<Auth>(create: (context) => Auth()),
|
title: 'Spotube',
|
||||||
ChangeNotifierProvider<SpotifyDI>(create: (context) {
|
theme: ThemeData(
|
||||||
Auth authState = Provider.of<Auth>(context, listen: false);
|
primaryColor: Colors.green,
|
||||||
return SpotifyDI(
|
primarySwatch: Colors.green,
|
||||||
SpotifyApi(
|
buttonTheme: const ButtonThemeData(
|
||||||
SpotifyApiCredentials(
|
buttonColor: Colors.green,
|
||||||
authState.clientId,
|
|
||||||
authState.clientSecret,
|
|
||||||
accessToken: authState.accessToken,
|
|
||||||
refreshToken: authState.refreshToken,
|
|
||||||
expiration: authState.expiration,
|
|
||||||
scopes: spotifyScopes,
|
|
||||||
),
|
|
||||||
onCredentialsRefreshed: (credentials) async {
|
|
||||||
SharedPreferences localStorage =
|
|
||||||
await SharedPreferences.getInstance();
|
|
||||||
localStorage.setString(
|
|
||||||
LocalStorageKeys.refreshToken,
|
|
||||||
credentials.refreshToken!,
|
|
||||||
);
|
|
||||||
localStorage.setString(
|
|
||||||
LocalStorageKeys.accessToken,
|
|
||||||
credentials.accessToken!,
|
|
||||||
);
|
|
||||||
localStorage.setString(
|
|
||||||
LocalStorageKeys.clientId, credentials.clientId!);
|
|
||||||
localStorage.setString(
|
|
||||||
LocalStorageKeys.clientSecret,
|
|
||||||
credentials.clientSecret!,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
ChangeNotifierProvider<Playback>(create: (context) => Playback()),
|
|
||||||
ChangeNotifierProvider<UserPreferences>(
|
|
||||||
create: (context) {
|
|
||||||
return UserPreferences();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
],
|
shadowColor: Colors.grey[300],
|
||||||
child: MaterialApp(
|
backgroundColor: Colors.white,
|
||||||
debugShowCheckedModeBanner: false,
|
textTheme: TextTheme(
|
||||||
title: 'Spotube',
|
bodyText1: TextStyle(color: Colors.grey[850]),
|
||||||
theme: ThemeData(
|
headline1: TextStyle(color: Colors.grey[850]),
|
||||||
primaryColor: Colors.green,
|
headline2: TextStyle(color: Colors.grey[850]),
|
||||||
primarySwatch: Colors.green,
|
headline3: TextStyle(color: Colors.grey[850]),
|
||||||
buttonTheme: const ButtonThemeData(
|
headline4: TextStyle(color: Colors.grey[850]),
|
||||||
buttonColor: Colors.green,
|
headline5: TextStyle(color: Colors.grey[850]),
|
||||||
),
|
headline6: TextStyle(color: Colors.grey[850]),
|
||||||
shadowColor: Colors.grey[300],
|
),
|
||||||
backgroundColor: Colors.white,
|
listTileTheme: ListTileThemeData(
|
||||||
textTheme: TextTheme(
|
iconColor: Colors.grey[850],
|
||||||
bodyText1: TextStyle(color: Colors.grey[850]),
|
horizontalTitleGap: 0,
|
||||||
headline1: TextStyle(color: Colors.grey[850]),
|
),
|
||||||
headline2: TextStyle(color: Colors.grey[850]),
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
headline3: TextStyle(color: Colors.grey[850]),
|
focusedBorder: OutlineInputBorder(
|
||||||
headline4: TextStyle(color: Colors.grey[850]),
|
borderSide: BorderSide(
|
||||||
headline5: TextStyle(color: Colors.grey[850]),
|
color: Colors.green[400]!,
|
||||||
headline6: TextStyle(color: Colors.grey[850]),
|
width: 2.0,
|
||||||
),
|
|
||||||
listTileTheme: ListTileThemeData(
|
|
||||||
iconColor: Colors.grey[850],
|
|
||||||
horizontalTitleGap: 0,
|
|
||||||
),
|
|
||||||
inputDecorationTheme: InputDecorationTheme(
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(
|
|
||||||
color: Colors.green[400]!,
|
|
||||||
width: 2.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
enabledBorder: OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(
|
|
||||||
color: Colors.grey[800]!,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
navigationRailTheme: NavigationRailThemeData(
|
enabledBorder: OutlineInputBorder(
|
||||||
backgroundColor: Colors.blueGrey[50],
|
borderSide: BorderSide(
|
||||||
unselectedIconTheme:
|
color: Colors.grey[800]!,
|
||||||
IconThemeData(color: Colors.grey[850], opacity: 1),
|
|
||||||
unselectedLabelTextStyle: TextStyle(
|
|
||||||
color: Colors.grey[850],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
cardTheme: CardTheme(
|
|
||||||
shape:
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
darkTheme: ThemeData(
|
navigationRailTheme: NavigationRailThemeData(
|
||||||
brightness: Brightness.dark,
|
backgroundColor: Colors.blueGrey[50],
|
||||||
primaryColor: Colors.green,
|
unselectedIconTheme:
|
||||||
primarySwatch: Colors.green,
|
IconThemeData(color: Colors.grey[850], opacity: 1),
|
||||||
backgroundColor: Colors.blueGrey[900],
|
unselectedLabelTextStyle: TextStyle(
|
||||||
scaffoldBackgroundColor: Colors.blueGrey[900],
|
color: Colors.grey[850],
|
||||||
dialogBackgroundColor: Colors.blueGrey[800],
|
|
||||||
shadowColor: Colors.black26,
|
|
||||||
buttonTheme: const ButtonThemeData(
|
|
||||||
buttonColor: Colors.green,
|
|
||||||
),
|
),
|
||||||
inputDecorationTheme: InputDecorationTheme(
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(
|
|
||||||
color: Colors.green[400]!,
|
|
||||||
width: 2.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
enabledBorder: OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(
|
|
||||||
color: Colors.grey[800]!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
navigationRailTheme: NavigationRailThemeData(
|
|
||||||
backgroundColor: Colors.blueGrey[800],
|
|
||||||
unselectedIconTheme: const IconThemeData(opacity: 1),
|
|
||||||
),
|
|
||||||
cardTheme: CardTheme(
|
|
||||||
shape:
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
|
||||||
color: Colors.blueGrey[900],
|
|
||||||
elevation: 20,
|
|
||||||
),
|
|
||||||
canvasColor: Colors.blueGrey[900],
|
|
||||||
),
|
),
|
||||||
themeMode: _themeMode,
|
cardTheme: CardTheme(
|
||||||
home: const Home(),
|
shape:
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
darkTheme: ThemeData(
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
primaryColor: Colors.green,
|
||||||
|
primarySwatch: Colors.green,
|
||||||
|
backgroundColor: Colors.blueGrey[900],
|
||||||
|
scaffoldBackgroundColor: Colors.blueGrey[900],
|
||||||
|
dialogBackgroundColor: Colors.blueGrey[800],
|
||||||
|
shadowColor: Colors.black26,
|
||||||
|
buttonTheme: const ButtonThemeData(
|
||||||
|
buttonColor: Colors.green,
|
||||||
|
),
|
||||||
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Colors.green[400]!,
|
||||||
|
width: 2.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Colors.grey[800]!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
navigationRailTheme: NavigationRailThemeData(
|
||||||
|
backgroundColor: Colors.blueGrey[800],
|
||||||
|
unselectedIconTheme: const IconThemeData(opacity: 1),
|
||||||
|
),
|
||||||
|
cardTheme: CardTheme(
|
||||||
|
shape:
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||||
|
color: Colors.blueGrey[900],
|
||||||
|
elevation: 20,
|
||||||
|
),
|
||||||
|
canvasColor: Colors.blueGrey[900],
|
||||||
|
),
|
||||||
|
themeMode: _themeMode,
|
||||||
|
home: const Home(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
class Auth with ChangeNotifier {
|
class Auth with ChangeNotifier {
|
||||||
String? _clientId;
|
String? _clientId;
|
||||||
@ -52,3 +53,5 @@ class Auth with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var authProvider = ChangeNotifierProvider<Auth>((ref) => Auth());
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
|
|
||||||
class CurrentPlaylist {
|
class CurrentPlaylist {
|
||||||
@ -77,4 +78,4 @@ class Playback extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var x = Playback();
|
var playbackProvider = ChangeNotifierProvider<Playback>((_) => Playback());
|
||||||
|
@ -1,10 +1,36 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
|
import 'package:spotube/components/Home.dart';
|
||||||
|
import 'package:spotube/models/LocalStorageKeys.dart';
|
||||||
|
import 'package:spotube/provider/Auth.dart';
|
||||||
|
|
||||||
class SpotifyDI extends ChangeNotifier {
|
var spotifyProvider = Provider<SpotifyApi>((ref) {
|
||||||
SpotifyApi _spotifyApi;
|
Auth authState = ref.watch(authProvider);
|
||||||
|
return SpotifyApi(
|
||||||
SpotifyDI(this._spotifyApi);
|
SpotifyApiCredentials(
|
||||||
|
authState.clientId,
|
||||||
SpotifyApi get spotifyApi => _spotifyApi;
|
authState.clientSecret,
|
||||||
}
|
accessToken: authState.accessToken,
|
||||||
|
refreshToken: authState.refreshToken,
|
||||||
|
expiration: authState.expiration,
|
||||||
|
scopes: spotifyScopes,
|
||||||
|
),
|
||||||
|
onCredentialsRefreshed: (credentials) async {
|
||||||
|
SharedPreferences localStorage = await SharedPreferences.getInstance();
|
||||||
|
localStorage.setString(
|
||||||
|
LocalStorageKeys.refreshToken,
|
||||||
|
credentials.refreshToken!,
|
||||||
|
);
|
||||||
|
localStorage.setString(
|
||||||
|
LocalStorageKeys.accessToken,
|
||||||
|
credentials.accessToken!,
|
||||||
|
);
|
||||||
|
localStorage.setString(LocalStorageKeys.clientId, credentials.clientId!);
|
||||||
|
localStorage.setString(
|
||||||
|
LocalStorageKeys.clientSecret,
|
||||||
|
credentials.clientSecret!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
import 'package:hotkey_manager/hotkey_manager.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:spotube/models/LocalStorageKeys.dart';
|
import 'package:spotube/models/LocalStorageKeys.dart';
|
||||||
@ -110,3 +111,5 @@ class UserPreferences extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userPreferencesProvider = ChangeNotifierProvider((_) => UserPreferences());
|
||||||
|
29
pubspec.lock
29
pubspec.lock
@ -195,6 +195,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
flutter_riverpod:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_riverpod
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -338,13 +345,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.8.1"
|
version: "2.8.1"
|
||||||
nested:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: nested
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
|
||||||
oauth2:
|
oauth2:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -457,13 +457,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.4"
|
version: "4.2.4"
|
||||||
provider:
|
riverpod:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: riverpod
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.1"
|
version: "1.0.3"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -574,6 +574,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.10.0"
|
||||||
|
state_notifier:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: state_notifier
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.2+1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -37,7 +37,6 @@ dependencies:
|
|||||||
cached_network_image: ^3.2.0
|
cached_network_image: ^3.2.0
|
||||||
html: ^0.15.0
|
html: ^0.15.0
|
||||||
http: ^0.13.4
|
http: ^0.13.4
|
||||||
provider: ^6.0.1
|
|
||||||
shared_preferences: ^2.0.11
|
shared_preferences: ^2.0.11
|
||||||
spotify: ^0.6.0
|
spotify: ^0.6.0
|
||||||
url_launcher: ^6.0.17
|
url_launcher: ^6.0.17
|
||||||
@ -50,6 +49,7 @@ dependencies:
|
|||||||
path: ^1.8.0
|
path: ^1.8.0
|
||||||
path_provider: ^2.0.8
|
path_provider: ^2.0.8
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
|
flutter_riverpod: ^1.0.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user