From 74df7a91b1a065fd72ebb94090ba5d8819e300f2 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 7 Jun 2022 19:53:33 +0600 Subject: [PATCH] PlayerOverlay flickering fix track Share popup menu not showing when not logged in fix page tranistions changed to default material 3 design's Wrong link in Login page fix Changing UserPreferences provider resets the Playback provider using using hookified_infinite_scroll_pagination officially --- lib/components/Player/PlayerOverlay.dart | 5 +- lib/components/Player/PlayerView.dart | 2 +- lib/components/Settings/Login.dart | 2 +- lib/components/Settings/Settings.dart | 3 - lib/components/Shared/PageWindowTitleBar.dart | 2 +- lib/components/Shared/SpotubePageRoute.dart | 38 ++------ lib/components/Shared/TrackTile.dart | 97 ++++++++++--------- lib/hooks/usePaginatedFutureProvider.dart | 22 ++--- lib/hooks/usePagingController.dart | 53 ---------- lib/hooks/usePaletteColor.dart | 17 +++- lib/main.dart | 6 +- lib/provider/Auth.dart | 2 +- lib/provider/Playback.dart | 8 +- pubspec.lock | 13 ++- pubspec.yaml | 2 +- 15 files changed, 103 insertions(+), 169 deletions(-) delete mode 100644 lib/hooks/usePagingController.dart diff --git a/lib/components/Player/PlayerOverlay.dart b/lib/components/Player/PlayerOverlay.dart index 1490ad89..776b9966 100644 --- a/lib/components/Player/PlayerOverlay.dart +++ b/lib/components/Player/PlayerOverlay.dart @@ -20,7 +20,7 @@ class PlayerOverlay extends HookConsumerWidget { Widget build(BuildContext context, ref) { final breakpoint = useBreakpoints(); final isCurrentRoute = useIsCurrentRoute("/"); - final paletteColor = usePaletteColor(context, albumArt); + final paletteColor = usePaletteColor(context, albumArt, ref); final playback = ref.watch(playbackProvider); if (isCurrentRoute == false) { @@ -37,7 +37,8 @@ class PlayerOverlay extends HookConsumerWidget { right: (breakpoint.isMd ? 10 : 5), left: (breakpoint.isSm ? 5 : 80), bottom: (breakpoint.isSm ? 63 : 10), - child: Container( + child: AnimatedContainer( + duration: const Duration(milliseconds: 500), width: MediaQuery.of(context).size.width, height: 50, decoration: BoxDecoration( diff --git a/lib/components/Player/PlayerView.dart b/lib/components/Player/PlayerView.dart index 352b84f9..d69c07ee 100644 --- a/lib/components/Player/PlayerView.dart +++ b/lib/components/Player/PlayerView.dart @@ -44,7 +44,7 @@ class PlayerView extends HookConsumerWidget { [currentTrack?.album?.images], ); - final PaletteColor paletteColor = usePaletteColor(context, albumArt); + final PaletteColor paletteColor = usePaletteColor(context, albumArt, ref); final backgroundColor = Theme.of(context).backgroundColor; diff --git a/lib/components/Settings/Login.dart b/lib/components/Settings/Login.dart index 9338374c..ac330117 100644 --- a/lib/components/Settings/Login.dart +++ b/lib/components/Settings/Login.dart @@ -61,7 +61,7 @@ class Login extends HookConsumerWidget { 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"), + "https://github.com/KRTirtho/spotube#optional-configurations"), const SizedBox( height: 10, ), diff --git a/lib/components/Settings/Settings.dart b/lib/components/Settings/Settings.dart index 9689a9dc..438d17be 100644 --- a/lib/components/Settings/Settings.dart +++ b/lib/components/Settings/Settings.dart @@ -280,9 +280,6 @@ class Settings extends HookConsumerWidget { MaterialStateProperty.all(Colors.white), ), onPressed: () async { - SharedPreferences localStorage = - await SharedPreferences.getInstance(); - await localStorage.clear(); auth.logout(); GoRouter.of(context).pop(); }, diff --git a/lib/components/Shared/PageWindowTitleBar.dart b/lib/components/Shared/PageWindowTitleBar.dart index 4de0faf8..aaf1bf86 100644 --- a/lib/components/Shared/PageWindowTitleBar.dart +++ b/lib/components/Shared/PageWindowTitleBar.dart @@ -20,7 +20,7 @@ class TitleBarActionButtons extends StatelessWidget { ), child: const Icon(Icons.minimize_rounded)), TextButton( - onPressed: () { + onPressed: () async { appWindow.maximizeOrRestore(); }, style: ButtonStyle( diff --git a/lib/components/Shared/SpotubePageRoute.dart b/lib/components/Shared/SpotubePageRoute.dart index 0f729873..dd40b423 100644 --- a/lib/components/Shared/SpotubePageRoute.dart +++ b/lib/components/Shared/SpotubePageRoute.dart @@ -1,36 +1,18 @@ import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; class SpotubePageRoute extends PageRouteBuilder { final Widget child; SpotubePageRoute({required this.child}) : super( - pageBuilder: (context, animation, secondaryAnimation) => child, - settings: RouteSettings(name: child.key.toString())); - - @override - Widget buildTransitions(BuildContext context, Animation animation, - Animation secondaryAnimation, Widget child) { - return FadeTransition( - opacity: animation, - child: child, - ); - } -} - -class SpotubePage extends CustomTransitionPage { - SpotubePage({ - required Widget child, - }) : super( - child: child, - transitionsBuilder: (BuildContext context, - Animation animation, - Animation secondaryAnimation, - Widget child) { - return FadeTransition( - opacity: animation, - child: child, - ); - }, + pageBuilder: (context, animation, secondaryAnimation) => child, + settings: RouteSettings( + name: child.key.toString(), + ), ); } + +class SpotubePage extends MaterialPage { + const SpotubePage({ + required Widget child, + }) : super(child: child); +} diff --git a/lib/components/Shared/TrackTile.dart b/lib/components/Shared/TrackTile.dart index 4f5ed5d5..4e418373 100644 --- a/lib/components/Shared/TrackTile.dart +++ b/lib/components/Shared/TrackTile.dart @@ -229,14 +229,14 @@ class TrackTile extends HookConsumerWidget { Text(duration), ], const SizedBox(width: 10), - if (auth.isLoggedIn) - FutureBuilder( - future: spotify.tracks.me.containsOne(track.value.id!), - builder: (context, snapshot) { - return PopupMenuButton( - icon: const Icon(Icons.more_horiz_rounded), - itemBuilder: (context) { - return [ + FutureBuilder( + future: spotify.tracks.me.containsOne(track.value.id!), + builder: (context, snapshot) { + return PopupMenuButton( + icon: const Icon(Icons.more_horiz_rounded), + itemBuilder: (context) { + return [ + if (auth.isLoggedIn) PopupMenuItem( child: Row( children: const [ @@ -247,17 +247,18 @@ class TrackTile extends HookConsumerWidget { ), value: "add-playlist", ), - if (userPlaylist) - PopupMenuItem( - child: Row( - children: const [ - Icon(Icons.remove_circle_outline_rounded), - SizedBox(width: 10), - Text("Remove from Playlist"), - ], - ), - value: "remove-playlist", + if (userPlaylist && auth.isLoggedIn) + PopupMenuItem( + child: Row( + children: const [ + Icon(Icons.remove_circle_outline_rounded), + SizedBox(width: 10), + Text("Remove from Playlist"), + ], ), + value: "remove-playlist", + ), + if (auth.isLoggedIn) PopupMenuItem( child: Row( children: [ @@ -270,36 +271,36 @@ class TrackTile extends HookConsumerWidget { ), value: "favorite", ), - PopupMenuItem( - child: Row( - children: const [ - Icon(Icons.share_rounded), - SizedBox(width: 10), - Text("Share") - ], - ), - value: "share", - ) - ]; - }, - onSelected: (value) { - switch (value) { - case "favorite": - actionFavorite(snapshot.data == true); - break; - case "add-playlist": - actionAddToPlaylist(); - break; - case "remove-playlist": - actionRemoveFromPlaylist(); - break; - case "share": - actionShare(track.value); - break; - } - }, - ); - }) + PopupMenuItem( + child: Row( + children: const [ + Icon(Icons.share_rounded), + SizedBox(width: 10), + Text("Share") + ], + ), + value: "share", + ) + ]; + }, + onSelected: (value) { + switch (value) { + case "favorite": + actionFavorite(snapshot.data == true); + break; + case "add-playlist": + actionAddToPlaylist(); + break; + case "remove-playlist": + actionRemoveFromPlaylist(); + break; + case "share": + actionShare(track.value); + break; + } + }, + ); + }) ], ); } diff --git a/lib/hooks/usePaginatedFutureProvider.dart b/lib/hooks/usePaginatedFutureProvider.dart index b212bc04..94a92575 100644 --- a/lib/hooks/usePaginatedFutureProvider.dart +++ b/lib/hooks/usePaginatedFutureProvider.dart @@ -1,7 +1,6 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; -import 'package:spotube/hooks/usePagingController.dart'; +import 'package:hookified_infinite_scroll_pagination/hookified_infinite_scroll_pagination.dart'; PagingController usePaginatedFutureProvider( FutureProvider Function(P pageKey) createSnapshot, { @@ -18,18 +17,13 @@ PagingController usePaginatedFutureProvider( }) { final currentPageKey = useState(firstPageKey); final snapshot = ref.watch(createSnapshot(currentPageKey.value)); - final pagingController = - usePagingController(firstPageKey: firstPageKey); - useEffect(() { - listener(pageKey) { - if (currentPageKey.value != pageKey) { - currentPageKey.value = pageKey; - } - } - - pagingController.addPageRequestListener(listener); - return () => pagingController.removePageRequestListener(listener); - }, [snapshot, currentPageKey]); + final pagingController = usePagingController( + firstPageKey: firstPageKey, + onPageRequest: (pageKey, pagingController) { + if (currentPageKey.value != pageKey) { + currentPageKey.value = pageKey; + } + }); useEffect(() { snapshot.whenOrNull( diff --git a/lib/hooks/usePagingController.dart b/lib/hooks/usePagingController.dart deleted file mode 100644 index a32dfa0c..00000000 --- a/lib/hooks/usePagingController.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; - -PagingController - usePagingController({ - required final PageKeyType firstPageKey, - final int? invisibleItemsThreshold, - List? keys, -}) { - return use( - _PagingControllerHook( - firstPageKey: firstPageKey, - invisibleItemsThreshold: invisibleItemsThreshold, - keys: keys, - ), - ); -} - -class _PagingControllerHook - extends Hook> { - const _PagingControllerHook({ - required this.firstPageKey, - this.invisibleItemsThreshold, - List? keys, - }) : super(keys: keys); - - final PageKeyType firstPageKey; - final int? invisibleItemsThreshold; - - @override - HookState, - Hook>> - createState() => _PagingControllerHookState(); -} - -class _PagingControllerHookState extends HookState< - PagingController, - _PagingControllerHook> { - late final controller = PagingController( - firstPageKey: hook.firstPageKey, - invisibleItemsThreshold: hook.invisibleItemsThreshold); - - @override - PagingController build(BuildContext context) => - controller; - - @override - void dispose() => controller.dispose(); - - @override - String get debugLabel => 'usePagingController'; -} diff --git a/lib/hooks/usePaletteColor.dart b/lib/hooks/usePaletteColor.dart index 5d665b33..77a417d4 100644 --- a/lib/hooks/usePaletteColor.dart +++ b/lib/hooks/usePaletteColor.dart @@ -1,11 +1,18 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; -PaletteColor usePaletteColor(BuildContext context, String imageUrl) { - final paletteColor = - useState(PaletteColor(Colors.grey[300]!, 0)); +final _paletteColorState = StateProvider( + (ref) { + return PaletteColor(Colors.grey[300]!, 0); + }, +); + +PaletteColor usePaletteColor( + BuildContext context, String imageUrl, WidgetRef ref) { + final paletteColor = ref.watch(_paletteColorState); final mounted = useIsMounted(); useEffect(() { @@ -23,11 +30,11 @@ PaletteColor usePaletteColor(BuildContext context, String imageUrl) { ? palette.lightMutedColor ?? palette.lightVibrantColor : palette.darkMutedColor ?? palette.darkVibrantColor; if (color != null) { - paletteColor.value = color; + ref.read(_paletteColorState.notifier).state = color; } }); return null; }, [imageUrl]); - return paletteColor.value; + return paletteColor; } diff --git a/lib/main.dart b/lib/main.dart index e4380d8d..eee7f9ba 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -37,10 +37,9 @@ void main() async { doWhenWindowReady(() { appWindow.minSize = Size(Platform.isAndroid || Platform.isIOS ? 280 : 359, 700); - appWindow.size = const Size(900, 700); appWindow.alignment = Alignment.center; - appWindow.maximize(); appWindow.title = "Spotube"; + appWindow.maximize(); appWindow.show(); }); } @@ -50,11 +49,10 @@ void main() async { playbackProvider.overrideWithProvider(ChangeNotifierProvider( (ref) { final youtube = ref.watch(youtubeProvider); - final preferences = ref.watch(userPreferencesProvider); return Playback( player: audioPlayerHandler, youtube: youtube, - preferences: preferences, + ref: ref, ); }, )) diff --git a/lib/provider/Auth.dart b/lib/provider/Auth.dart index b34df796..36598335 100644 --- a/lib/provider/Auth.dart +++ b/lib/provider/Auth.dart @@ -51,7 +51,7 @@ class Auth extends PersistedChangeNotifier { updatePersistence(); } - logout() { + void logout() { _clientId = null; _clientSecret = null; _accessToken = null; diff --git a/lib/provider/Playback.dart b/lib/provider/Playback.dart index 13276b7a..ad41ae24 100644 --- a/lib/provider/Playback.dart +++ b/lib/provider/Playback.dart @@ -30,11 +30,11 @@ class Playback extends ChangeNotifier { AudioPlayerHandler player; YoutubeExplode youtube; - UserPreferences preferences; + Ref ref; Playback({ required this.player, required this.youtube, - required this.preferences, + required this.ref, CurrentPlaylist? currentPlaylist, Track? currentTrack, }) : _currentPlaylist = currentPlaylist, @@ -206,6 +206,7 @@ class Playback extends ChangeNotifier { // await player.play(); return; } + final preferences = ref.read(userPreferencesProvider); final spotubeTrack = await toSpotubeTrack( youtube: youtube, track: track, @@ -250,10 +251,9 @@ class Playback extends ChangeNotifier { final playbackProvider = ChangeNotifierProvider((ref) { final player = AudioPlayerHandler(); final youtube = ref.watch(youtubeProvider); - final preferences = ref.watch(userPreferencesProvider); return Playback( player: player, youtube: youtube, - preferences: preferences, + ref: ref, ); }); diff --git a/pubspec.lock b/pubspec.lock index 823843af..ab2e6dc3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -268,6 +268,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.0" + hookified_infinite_scroll_pagination: + dependency: "direct main" + description: + name: hookified_infinite_scroll_pagination + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" hooks_riverpod: dependency: "direct main" description: @@ -311,12 +318,12 @@ packages: source: hosted version: "3.1.3" infinite_scroll_pagination: - dependency: "direct main" + dependency: transitive description: name: infinite_scroll_pagination url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.2.0" js: dependency: transitive description: @@ -906,5 +913,5 @@ packages: source: hosted version: "1.11.0" sdks: - dart: ">=2.17.0 <3.0.0" + dart: ">=2.17.1 <3.0.0" flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 2e08205f..d4e49719 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,7 +41,6 @@ dependencies: git: https://github.com/KRTirtho/spotify-dart.git url_launcher: ^6.0.17 youtube_explode_dart: ^1.10.8 - infinite_scroll_pagination: ^3.1.0 bitsdojo_window: ^0.1.2 hotkey_manager: ^0.1.6 just_audio: ^0.9.18 @@ -61,6 +60,7 @@ dependencies: package_info_plus: ^1.4.2 version: ^2.0.0 audio_service: ^0.18.4 + hookified_infinite_scroll_pagination: ^0.1.0 dev_dependencies: flutter_test: