mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
crash in windows bug fix (hotkey_manager)
Player shuffle unshuffle support Lyrics page infinite loading on no accessToken fixed
This commit is contained in:
parent
07b1891cb4
commit
7cbbd0346e
21
.vscode/c_cpp_properties.json
vendored
Normal file
21
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE"
|
||||
],
|
||||
"windowsSdkVersion": "10.0.19041.0",
|
||||
"compilerPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.29.30133\\bin\\Hostx64\\x64\\cl.exe",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "windows-msvc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -1 +1,3 @@
|
||||
{}
|
||||
{
|
||||
"cmake.configureOnOpen": false
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:spotube/components/Settings.dart';
|
||||
import 'package:spotube/helpers/artist-to-string.dart';
|
||||
import 'package:spotube/helpers/getLyrics.dart';
|
||||
import 'package:spotube/provider/Playback.dart';
|
||||
@ -20,13 +21,16 @@ class _LyricsState extends State<Lyrics> {
|
||||
Playback playback = context.watch<Playback>();
|
||||
UserPreferences userPreferences = context.watch<UserPreferences>();
|
||||
|
||||
bool hasToken = (userPreferences.geniusAccessToken != null ||
|
||||
(userPreferences.geniusAccessToken?.isNotEmpty ?? false));
|
||||
|
||||
if (playback.currentTrack != null &&
|
||||
userPreferences.geniusAccessToken != null &&
|
||||
hasToken &&
|
||||
playback.currentTrack!.id != _lyrics["id"]) {
|
||||
getLyrics(
|
||||
playback.currentTrack!.name!,
|
||||
artistsToString(playback.currentTrack!.artists ?? []),
|
||||
apiKey: userPreferences.geniusAccessToken,
|
||||
apiKey: userPreferences.geniusAccessToken!,
|
||||
optimizeQuery: true,
|
||||
).then((lyrics) {
|
||||
if (lyrics != null) {
|
||||
@ -44,12 +48,32 @@ class _LyricsState extends State<Lyrics> {
|
||||
}
|
||||
|
||||
if (_lyrics["lyrics"] == null && playback.currentTrack != null) {
|
||||
if (!hasToken) {
|
||||
return Expanded(
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const Text("Genius lyrics API access token isn't set"),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return const Settings();
|
||||
},
|
||||
));
|
||||
},
|
||||
child: const Text("Add Access Token"))
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
return const Expanded(
|
||||
child: Center(
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
||||
@ -30,14 +31,52 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
||||
|
||||
double _volume = 0;
|
||||
|
||||
final List<HotKey> _hotKeys = [];
|
||||
late List<GlobalKeyActions> _hotKeys;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
try {
|
||||
super.initState();
|
||||
player = AudioPlayer();
|
||||
_hotKeys = [
|
||||
GlobalKeyActions(
|
||||
HotKey(KeyCode.space, scope: HotKeyScope.inapp),
|
||||
_playOrPause,
|
||||
),
|
||||
// causaes crash in Windows for aquiring global hotkey of
|
||||
// keyboard media buttons
|
||||
if (!Platform.isWindows) ...[
|
||||
GlobalKeyActions(
|
||||
HotKey(KeyCode.mediaPlayPause),
|
||||
_playOrPause,
|
||||
),
|
||||
GlobalKeyActions(HotKey(KeyCode.mediaTrackNext), (key) async {
|
||||
_movePlaylistPositionBy(1);
|
||||
}),
|
||||
GlobalKeyActions(HotKey(KeyCode.mediaTrackPrevious), (key) async {
|
||||
_movePlaylistPositionBy(-1);
|
||||
}),
|
||||
GlobalKeyActions(HotKey(KeyCode.mediaStop), (key) async {
|
||||
Playback playback = context.read<Playback>();
|
||||
setState(() {
|
||||
_isPlaying = false;
|
||||
_currentTrackId = null;
|
||||
_duration = null;
|
||||
_shuffled = false;
|
||||
});
|
||||
playback.reset();
|
||||
})
|
||||
]
|
||||
];
|
||||
WidgetsBinding.instance?.addObserver(this);
|
||||
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) async {
|
||||
WidgetsBinding.instance?.addPostFrameCallback(_init);
|
||||
} catch (e, stack) {
|
||||
print("[Player.initState()] $e");
|
||||
print(stack);
|
||||
}
|
||||
}
|
||||
|
||||
_init(Duration timeStamp) async {
|
||||
try {
|
||||
setState(() {
|
||||
_volume = player.volume;
|
||||
@ -77,44 +116,8 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
||||
}
|
||||
});
|
||||
|
||||
playOrPause(key) async {
|
||||
try {
|
||||
_isPlaying ? await player.pause() : await player.play();
|
||||
} catch (e, stack) {
|
||||
print("[PlayPauseShortcut] $e");
|
||||
print(stack);
|
||||
}
|
||||
}
|
||||
|
||||
List<GlobalKeyActions> keyWithActions = [
|
||||
GlobalKeyActions(
|
||||
HotKey(KeyCode.space, scope: HotKeyScope.inapp),
|
||||
playOrPause,
|
||||
),
|
||||
GlobalKeyActions(
|
||||
HotKey(KeyCode.mediaPlayPause),
|
||||
playOrPause,
|
||||
),
|
||||
GlobalKeyActions(HotKey(KeyCode.mediaTrackNext), (key) async {
|
||||
_movePlaylistPositionBy(1);
|
||||
}),
|
||||
GlobalKeyActions(HotKey(KeyCode.mediaTrackPrevious), (key) async {
|
||||
_movePlaylistPositionBy(-1);
|
||||
}),
|
||||
GlobalKeyActions(HotKey(KeyCode.mediaStop), (key) async {
|
||||
Playback playback = context.read<Playback>();
|
||||
setState(() {
|
||||
_isPlaying = false;
|
||||
_currentTrackId = null;
|
||||
_duration = null;
|
||||
_shuffled = false;
|
||||
});
|
||||
playback.reset();
|
||||
})
|
||||
];
|
||||
|
||||
await Future.wait(
|
||||
keyWithActions.map((e) {
|
||||
_hotKeys.map((e) {
|
||||
return hotKeyManager.register(
|
||||
e.hotKey,
|
||||
keyDownHandler: e.onKeyDown,
|
||||
@ -122,16 +125,15 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
||||
}),
|
||||
);
|
||||
} catch (e) {
|
||||
print("[Player.initState()]: $e");
|
||||
print("[Player._init()]: $e");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance?.removeObserver(this);
|
||||
player.dispose();
|
||||
Future.wait(_hotKeys.map((e) => hotKeyManager.unregister(e)));
|
||||
Future.wait(_hotKeys.map((e) => hotKeyManager.unregister(e.hotKey)));
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -145,6 +147,15 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
_playOrPause(key) async {
|
||||
try {
|
||||
_isPlaying ? await player.pause() : await player.play();
|
||||
} catch (e, stack) {
|
||||
print("[PlayPauseShortcut] $e");
|
||||
print(stack);
|
||||
}
|
||||
}
|
||||
|
||||
void _movePlaylistPositionBy(int pos) {
|
||||
Playback playback = context.read<Playback>();
|
||||
if (playback.currentTrack != null && playback.currentPlaylist != null) {
|
||||
@ -303,19 +314,19 @@ class _PlayerState extends State<Player> with WidgetsBindingObserver {
|
||||
}
|
||||
},
|
||||
onShuffle: () async {
|
||||
if (playback.currentTrack == null ||
|
||||
playback.currentPlaylist == null) return;
|
||||
try {
|
||||
if (!_shuffled) {
|
||||
await player.setShuffleModeEnabled(true).then(
|
||||
(value) => setState(() {
|
||||
playback.currentPlaylist!.shuffle();
|
||||
setState(() {
|
||||
_shuffled = true;
|
||||
}),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
await player.setShuffleModeEnabled(false).then(
|
||||
(value) => setState(() {
|
||||
playback.currentPlaylist!.unshuffle();
|
||||
setState(() {
|
||||
_shuffled = false;
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
} catch (e, stack) {
|
||||
print("[PlayerControls.onShuffle()] $e");
|
||||
|
@ -5,6 +5,7 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
Future<String?> connectIpc(String authUri, String redirectUri) async {
|
||||
try {
|
||||
if (await canLaunch(authUri)) {
|
||||
print("[Launching]: $authUri");
|
||||
await launch(authUri);
|
||||
}
|
||||
|
||||
|
@ -2,18 +2,35 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
|
||||
class CurrentPlaylist {
|
||||
List<Track>? _tempTrack;
|
||||
List<Track> tracks;
|
||||
String id;
|
||||
String name;
|
||||
String thumbnail;
|
||||
CurrentPlaylist({
|
||||
required List<Track> this.tracks,
|
||||
required String this.id,
|
||||
required String this.name,
|
||||
required String this.thumbnail,
|
||||
required this.tracks,
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.thumbnail,
|
||||
});
|
||||
|
||||
List<String> get trackIds => tracks.map((e) => e.id!).toList();
|
||||
|
||||
void shuffle() {
|
||||
// won't shuffle if already shuffled
|
||||
if (_tempTrack == null) {
|
||||
_tempTrack = [...tracks];
|
||||
tracks.shuffle();
|
||||
}
|
||||
}
|
||||
|
||||
void unshuffle() {
|
||||
// without _tempTracks unshuffling can't be done
|
||||
if (_tempTrack != null) {
|
||||
tracks = [..._tempTrack!];
|
||||
_tempTrack = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Playback extends ChangeNotifier {
|
||||
|
@ -16,7 +16,7 @@ class UserPreferences extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
get geniusAccessToken => _geniusAccessToken;
|
||||
String? get geniusAccessToken => _geniusAccessToken;
|
||||
|
||||
setGeniusAccessToken(String? token) {
|
||||
_geniusAccessToken = token;
|
||||
|
Loading…
Reference in New Issue
Block a user