mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
Merge branch 'master' into build
This commit is contained in:
commit
8dfa13dd06
@ -1,7 +1,7 @@
|
||||
# Maintainer: Kingkor Roy Tirtho <krtirho@gmail.com>
|
||||
pkgname=spotube-bin
|
||||
pkgver=%{{SPOTUBE_VERSION}}%
|
||||
pkgrel=%{{PKGREL}}$
|
||||
pkgrel=%{{PKGREL}}%
|
||||
epoch=
|
||||
pkgdesc="A lightweight free Spotify crossplatform-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed"
|
||||
arch=(x86_64)
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
),
|
||||
|
@ -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();
|
||||
},
|
||||
|
@ -20,7 +20,7 @@ class TitleBarActionButtons extends StatelessWidget {
|
||||
),
|
||||
child: const Icon(Icons.minimize_rounded)),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
appWindow.maximizeOrRestore();
|
||||
},
|
||||
style: ButtonStyle(
|
||||
|
@ -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<double> animation,
|
||||
Animation<double> secondaryAnimation, Widget child) {
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: child,
|
||||
settings: RouteSettings(
|
||||
name: child.key.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SpotubePage extends CustomTransitionPage {
|
||||
SpotubePage({
|
||||
class SpotubePage extends MaterialPage {
|
||||
const SpotubePage({
|
||||
required Widget child,
|
||||
}) : super(
|
||||
child: child,
|
||||
transitionsBuilder: (BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
Widget child) {
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
}) : super(child: child);
|
||||
}
|
||||
|
@ -229,7 +229,6 @@ class TrackTile extends HookConsumerWidget {
|
||||
Text(duration),
|
||||
],
|
||||
const SizedBox(width: 10),
|
||||
if (auth.isLoggedIn)
|
||||
FutureBuilder<bool>(
|
||||
future: spotify.tracks.me.containsOne(track.value.id!),
|
||||
builder: (context, snapshot) {
|
||||
@ -237,6 +236,7 @@ class TrackTile extends HookConsumerWidget {
|
||||
icon: const Icon(Icons.more_horiz_rounded),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
if (auth.isLoggedIn)
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: const [
|
||||
@ -247,7 +247,7 @@ class TrackTile extends HookConsumerWidget {
|
||||
),
|
||||
value: "add-playlist",
|
||||
),
|
||||
if (userPlaylist)
|
||||
if (userPlaylist && auth.isLoggedIn)
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: const [
|
||||
@ -258,6 +258,7 @@ class TrackTile extends HookConsumerWidget {
|
||||
),
|
||||
value: "remove-playlist",
|
||||
),
|
||||
if (auth.isLoggedIn)
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
|
@ -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<P, ItemType> usePaginatedFutureProvider<T, P, ItemType>(
|
||||
FutureProvider<T> Function(P pageKey) createSnapshot, {
|
||||
@ -18,18 +17,13 @@ PagingController<P, ItemType> usePaginatedFutureProvider<T, P, ItemType>(
|
||||
}) {
|
||||
final currentPageKey = useState(firstPageKey);
|
||||
final snapshot = ref.watch(createSnapshot(currentPageKey.value));
|
||||
final pagingController =
|
||||
usePagingController<P, ItemType>(firstPageKey: firstPageKey);
|
||||
useEffect(() {
|
||||
listener(pageKey) {
|
||||
final pagingController = usePagingController<P, ItemType>(
|
||||
firstPageKey: firstPageKey,
|
||||
onPageRequest: (pageKey, pagingController) {
|
||||
if (currentPageKey.value != pageKey) {
|
||||
currentPageKey.value = pageKey;
|
||||
}
|
||||
}
|
||||
|
||||
pagingController.addPageRequestListener(listener);
|
||||
return () => pagingController.removePageRequestListener(listener);
|
||||
}, [snapshot, currentPageKey]);
|
||||
});
|
||||
|
||||
useEffect(() {
|
||||
snapshot.whenOrNull(
|
||||
|
@ -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<PageKeyType, ItemType>
|
||||
usePagingController<PageKeyType, ItemType>({
|
||||
required final PageKeyType firstPageKey,
|
||||
final int? invisibleItemsThreshold,
|
||||
List<Object?>? keys,
|
||||
}) {
|
||||
return use(
|
||||
_PagingControllerHook<PageKeyType, ItemType>(
|
||||
firstPageKey: firstPageKey,
|
||||
invisibleItemsThreshold: invisibleItemsThreshold,
|
||||
keys: keys,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class _PagingControllerHook<PageKeyType, ItemType>
|
||||
extends Hook<PagingController<PageKeyType, ItemType>> {
|
||||
const _PagingControllerHook({
|
||||
required this.firstPageKey,
|
||||
this.invisibleItemsThreshold,
|
||||
List<Object?>? keys,
|
||||
}) : super(keys: keys);
|
||||
|
||||
final PageKeyType firstPageKey;
|
||||
final int? invisibleItemsThreshold;
|
||||
|
||||
@override
|
||||
HookState<PagingController<PageKeyType, ItemType>,
|
||||
Hook<PagingController<PageKeyType, ItemType>>>
|
||||
createState() => _PagingControllerHookState<PageKeyType, ItemType>();
|
||||
}
|
||||
|
||||
class _PagingControllerHookState<PageKeyType, ItemType> extends HookState<
|
||||
PagingController<PageKeyType, ItemType>,
|
||||
_PagingControllerHook<PageKeyType, ItemType>> {
|
||||
late final controller = PagingController<PageKeyType, ItemType>(
|
||||
firstPageKey: hook.firstPageKey,
|
||||
invisibleItemsThreshold: hook.invisibleItemsThreshold);
|
||||
|
||||
@override
|
||||
PagingController<PageKeyType, ItemType> build(BuildContext context) =>
|
||||
controller;
|
||||
|
||||
@override
|
||||
void dispose() => controller.dispose();
|
||||
|
||||
@override
|
||||
String get debugLabel => 'usePagingController';
|
||||
}
|
@ -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>(PaletteColor(Colors.grey[300]!, 0));
|
||||
final _paletteColorState = StateProvider<PaletteColor>(
|
||||
(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;
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
},
|
||||
))
|
||||
|
@ -51,7 +51,7 @@ class Auth extends PersistedChangeNotifier {
|
||||
updatePersistence();
|
||||
}
|
||||
|
||||
logout() {
|
||||
void logout() {
|
||||
_clientId = null;
|
||||
_clientSecret = null;
|
||||
_accessToken = null;
|
||||
|
@ -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<Playback>((ref) {
|
||||
final player = AudioPlayerHandler();
|
||||
final youtube = ref.watch(youtubeProvider);
|
||||
final preferences = ref.watch(userPreferencesProvider);
|
||||
return Playback(
|
||||
player: player,
|
||||
youtube: youtube,
|
||||
preferences: preferences,
|
||||
ref: ref,
|
||||
);
|
||||
});
|
||||
|
13
pubspec.lock
13
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"
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user