Merge branch 'master' into build

This commit is contained in:
Kingkor Roy Tirtho 2022-06-15 18:34:47 +06:00
commit d7d2b31e8e
21 changed files with 290 additions and 300 deletions

1
.github/FUNDING.yml vendored
View File

@ -1,5 +1,4 @@
open_collective: spotube open_collective: spotube
ko_fi: krtirtho
patreon: krtirtho patreon: krtirtho
custom: custom:
- "https://www.buymeacoffee.com/krtirtho" - "https://www.buymeacoffee.com/krtirtho"

View File

@ -35,6 +35,8 @@ jobs:
build/Spotube-linux-x86_64.tar.xz build/Spotube-linux-x86_64.tar.xz
build/Spotube-*-x86_64.AppImage build/Spotube-*-x86_64.AppImage
# Building Android Application # Building Android Application
- run: echo ${{ secrets.KEYSTORE }} | base64 --decode > upload-keystore.jks
- run: echo ${{ secrets.KEY_PROPERTIES }} > android/key.properties
- run: flutter build apk - run: flutter build apk
- run: make apk - run: make apk
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2

3
.gitignore vendored
View File

@ -45,7 +45,6 @@ app.*.map.json
/android/app/profile /android/app/profile
/android/app/release /android/app/release
*.pkg.tar.zst *.pkg.tar.zst
/aur-struct/*.tar /aur-struct/*.tar
/aur-struct/src /aur-struct/src
@ -74,3 +73,5 @@ secrets.json
dist dist
appimage-build appimage-build
android/key.properties

View File

@ -25,6 +25,12 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android { android {
compileSdkVersion 31 compileSdkVersion 31
@ -51,11 +57,17 @@ android {
multiDexEnabled true multiDexEnabled true
} }
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. signingConfig signingConfigs.release
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
} }
} }
} }

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/components/Shared/HeartButton.dart'; import 'package:spotube/components/Shared/HeartButton.dart';
@ -59,6 +60,7 @@ class AlbumView extends HookConsumerWidget {
titleImage: albumArt, titleImage: albumArt,
tracksSnapshot: tracksSnapshot, tracksSnapshot: tracksSnapshot,
album: album, album: album,
routePath: "/album/${album.id}",
onPlay: ([track]) { onPlay: ([track]) {
if (tracksSnapshot.asData?.value != null) { if (tracksSnapshot.asData?.value != null) {
playPlaylist( playPlaylist(

View File

@ -23,6 +23,7 @@ import 'package:spotube/hooks/usePaginatedFutureProvider.dart';
import 'package:spotube/hooks/useUpdateChecker.dart'; import 'package:spotube/hooks/useUpdateChecker.dart';
import 'package:spotube/models/Logger.dart'; import 'package:spotube/models/Logger.dart';
import 'package:spotube/provider/SpotifyRequests.dart'; import 'package:spotube/provider/SpotifyRequests.dart';
import 'package:spotube/utils/platform.dart';
List<String> spotifyScopes = [ List<String> spotifyScopes = [
"playlist-modify-public", "playlist-modify-public",
@ -73,7 +74,7 @@ class Home extends HookConsumerWidget {
child: MoveWindow(), child: MoveWindow(),
), ),
Expanded(child: MoveWindow()), Expanded(child: MoveWindow()),
if (!Platform.isMacOS && !Platform.isAndroid && !Platform.isIOS) if (!Platform.isMacOS && !kIsMobile)
const TitleBarActionButtons(), const TitleBarActionButtons(),
], ],
)) ))
@ -98,7 +99,7 @@ class Home extends HookConsumerWidget {
child: Scaffold( child: Scaffold(
body: Column( body: Column(
children: [ children: [
Platform.isAndroid || Platform.isIOS kIsMobile
? titleBarContents ? titleBarContents
: WindowTitleBarBox(child: titleBarContents), : WindowTitleBarBox(child: titleBarContents),
Expanded( Expanded(

View File

@ -44,7 +44,7 @@ class ShimmerArtistProfile extends HookWidget {
), ),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
const Flexible(child: ShimmerTrackTile()), const Flexible(child: ShimmerTrackTile(noSliver: true)),
], ],
); );
} }

View File

@ -3,7 +3,12 @@ import 'package:skeleton_text/skeleton_text.dart';
import 'package:spotube/extensions/ShimmerColorTheme.dart'; import 'package:spotube/extensions/ShimmerColorTheme.dart';
class ShimmerTrackTile extends StatelessWidget { class ShimmerTrackTile extends StatelessWidget {
const ShimmerTrackTile({Key? key}) : super(key: key); final bool noSliver;
const ShimmerTrackTile({
Key? key,
this.noSliver = false,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -13,15 +18,7 @@ class ShimmerTrackTile extends StatelessWidget {
.extension<ShimmerColorTheme>()! .extension<ShimmerColorTheme>()!
.shimmerBackgroundColor!; .shimmerBackgroundColor!;
return Padding( final single = Container(
padding: const EdgeInsets.only(top: 30),
child: ListView.builder(
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
itemCount: 5,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 20), margin: const EdgeInsets.symmetric(horizontal: 20),
child: Row( child: Row(
children: [ children: [
@ -78,7 +75,20 @@ class ShimmerTrackTile extends StatelessWidget {
], ],
), ),
); );
},
if (noSliver) {
return ListView.builder(
shrinkWrap: true,
itemCount: 5,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, _) => single,
);
}
return SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) => single,
childCount: 5,
), ),
); );
} }

View File

@ -1,6 +1,5 @@
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_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@ -12,6 +11,7 @@ import 'package:spotube/components/Shared/SpotubeMarqueeText.dart';
import 'package:spotube/helpers/artists-to-clickable-artists.dart'; import 'package:spotube/helpers/artists-to-clickable-artists.dart';
import 'package:spotube/helpers/image-to-url-string.dart'; import 'package:spotube/helpers/image-to-url-string.dart';
import 'package:spotube/hooks/useBreakpoints.dart'; import 'package:spotube/hooks/useBreakpoints.dart';
import 'package:spotube/hooks/useCustomStatusBarColor.dart';
import 'package:spotube/hooks/usePaletteColor.dart'; import 'package:spotube/hooks/usePaletteColor.dart';
import 'package:spotube/provider/Playback.dart'; import 'package:spotube/provider/Playback.dart';
@ -46,29 +46,10 @@ class PlayerView extends HookConsumerWidget {
final PaletteColor paletteColor = usePaletteColor(context, albumArt, ref); final PaletteColor paletteColor = usePaletteColor(context, albumArt, ref);
final backgroundColor = Theme.of(context).backgroundColor; useCustomStatusBarColor(
paletteColor.color,
useEffect(() { GoRouter.of(context).location == "/player",
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: paletteColor.color, // status bar color
),
); );
return;
}, [paletteColor.color]);
useEffect(() {
return () {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: backgroundColor, // status bar color
statusBarIconBrightness: backgroundColor.computeLuminance() > 0.179
? Brightness.dark
: Brightness.light,
),
);
};
}, []);
return SafeArea( return SafeArea(
child: Scaffold( child: Scaffold(

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/Shared/HeartButton.dart'; import 'package:spotube/components/Shared/HeartButton.dart';
import 'package:spotube/components/Shared/TrackCollectionView.dart'; import 'package:spotube/components/Shared/TrackCollectionView.dart';
@ -80,6 +81,7 @@ class PlaylistView extends HookConsumerWidget {
} }
}, },
showShare: playlist.id != "user-liked-tracks", showShare: playlist.id != "user-liked-tracks",
routePath: "/playlist/${playlist.id}",
onShare: () { onShare: () {
final data = "https://open.spotify.com/playlist/${playlist.id}"; final data = "https://open.spotify.com/playlist/${playlist.id}";
Clipboard.setData( Clipboard.setData(

View File

@ -13,6 +13,7 @@ import 'package:spotube/models/SpotifyMarkets.dart';
import 'package:spotube/models/SpotubeTrack.dart'; import 'package:spotube/models/SpotubeTrack.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';
import 'package:spotube/utils/platform.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
class Settings extends HookConsumerWidget { class Settings extends HookConsumerWidget {
@ -56,7 +57,7 @@ class Settings extends HookConsumerWidget {
constraints: const BoxConstraints(maxWidth: 1366), constraints: const BoxConstraints(maxWidth: 1366),
child: ListView( child: ListView(
children: [ children: [
if (!Platform.isAndroid && !Platform.isIOS) ...[ if (!kIsMobile) ...[
SettingsHotKeyTile( SettingsHotKeyTile(
title: "Next track global shortcut", title: "Next track global shortcut",
currentHotKey: preferences.nextTrackHotKey, currentHotKey: preferences.nextTrackHotKey,

View File

@ -9,6 +9,7 @@ import 'package:spotube/helpers/getLyrics.dart';
import 'package:spotube/models/SpotubeTrack.dart'; import 'package:spotube/models/SpotubeTrack.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';
import 'package:spotube/utils/platform.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart';
import 'package:path_provider/path_provider.dart' as path_provider; import 'package:path_provider/path_provider.dart' as path_provider;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
@ -30,7 +31,7 @@ class DownloadTrackButton extends HookConsumerWidget {
final _downloadTrack = useCallback(() async { final _downloadTrack = useCallback(() async {
if (track == null) return; if (track == null) return;
if ((Platform.isAndroid || Platform.isIOS) && if ((kIsMobile) &&
!await Permission.storage.isGranted && !await Permission.storage.isGranted &&
!await Permission.storage.isPermanentlyDenied) { !await Permission.storage.isPermanentlyDenied) {
final status = await Permission.storage.request(); final status = await Permission.storage.request();

View File

@ -2,6 +2,7 @@ import 'dart:io';
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:spotube/utils/platform.dart';
class TitleBarActionButtons extends StatelessWidget { class TitleBarActionButtons extends StatelessWidget {
final Color? color; final Color? color;
@ -67,20 +68,23 @@ class PageWindowTitleBar extends StatelessWidget
}) : super(key: key); }) : super(key: key);
@override @override
Size get preferredSize => Size.fromHeight( Size get preferredSize => Size.fromHeight(
!Platform.isIOS && !Platform.isAndroid ? appWindow.titleBarHeight : 35, (kIsDesktop ? appWindow.titleBarHeight : 35),
); );
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (Platform.isIOS || Platform.isAndroid) { if (kIsMobile) {
return PreferredSize( return PreferredSize(
preferredSize: const Size.fromHeight(300), preferredSize: const Size.fromHeight(300),
child: Container(
color: backgroundColor,
child: Row( child: Row(
children: [ children: [
if (leading != null) leading!, if (leading != null) leading!,
Expanded(child: Center(child: center)), Expanded(child: Center(child: center)),
], ],
), ),
),
); );
} }
return WindowTitleBarBox( return WindowTitleBarBox(
@ -94,7 +98,7 @@ class PageWindowTitleBar extends StatelessWidget
), ),
if (leading != null) leading!, if (leading != null) leading!,
Expanded(child: MoveWindow(child: Center(child: center))), Expanded(child: MoveWindow(child: Center(child: center))),
if (!Platform.isMacOS && !Platform.isIOS && !Platform.isAndroid) if (!Platform.isMacOS && !kIsMobile)
TitleBarActionButtons(color: foregroundColor) TitleBarActionButtons(color: foregroundColor)
], ],
), ),

View File

@ -1,14 +1,17 @@
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/LoaderShimmers/ShimmerTrackTile.dart'; import 'package:spotube/components/LoaderShimmers/ShimmerTrackTile.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/simple-track-to-track.dart'; import 'package:spotube/helpers/simple-track-to-track.dart';
import 'package:spotube/hooks/useCustomStatusBarColor.dart';
import 'package:spotube/hooks/usePaletteColor.dart'; import 'package:spotube/hooks/usePaletteColor.dart';
import 'package:spotube/models/Logger.dart'; import 'package:spotube/models/Logger.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/utils/platform.dart';
class TrackCollectionView extends HookConsumerWidget { class TrackCollectionView extends HookConsumerWidget {
final logger = getLogger(TrackCollectionView); final logger = getLogger(TrackCollectionView);
@ -25,6 +28,8 @@ class TrackCollectionView extends HookConsumerWidget {
final bool showShare; final bool showShare;
final bool isOwned; final bool isOwned;
final String routePath;
TrackCollectionView({ TrackCollectionView({
required this.title, required this.title,
required this.id, required this.id,
@ -33,6 +38,7 @@ class TrackCollectionView extends HookConsumerWidget {
required this.isPlaying, required this.isPlaying,
required this.onPlay, required this.onPlay,
required this.onShare, required this.onShare,
required this.routePath,
this.heartBtn, this.heartBtn,
this.album, this.album,
this.description, this.description,
@ -83,6 +89,11 @@ class TrackCollectionView extends HookConsumerWidget {
final collapsed = useState(false); final collapsed = useState(false);
useCustomStatusBarColor(
color?.color ?? Theme.of(context).backgroundColor,
GoRouter.of(context).location == routePath,
);
useEffect(() { useEffect(() {
listener() { listener() {
if (controller.position.pixels >= 400 && !collapsed.value) { if (controller.position.pixels >= 400 && !collapsed.value) {
@ -99,25 +110,16 @@ class TrackCollectionView extends HookConsumerWidget {
return SafeArea( return SafeArea(
child: Scaffold( child: Scaffold(
appBar: PageWindowTitleBar( appBar: (kIsDesktop)
backgroundColor: ? PageWindowTitleBar(
tracksSnapshot.asData?.value != null ? color?.color : null, backgroundColor: color?.color,
foregroundColor: tracksSnapshot.asData?.value != null foregroundColor: color?.titleTextColor,
? color?.titleTextColor
: null,
leading: Row( leading: Row(
children: [ children: [BackButton(color: color?.titleTextColor)],
BackButton( ),
color: tracksSnapshot.asData?.value != null
? color?.titleTextColor
: null,
) )
], : null,
), body: CustomScrollView(
),
body: tracksSnapshot.when(
data: (tracks) {
return CustomScrollView(
controller: controller, controller: controller,
slivers: [ slivers: [
SliverAppBar( SliverAppBar(
@ -125,19 +127,19 @@ class TrackCollectionView extends HookConsumerWidget {
floating: false, floating: false,
pinned: true, pinned: true,
expandedHeight: 400, expandedHeight: 400,
automaticallyImplyLeading: false, automaticallyImplyLeading: kIsMobile,
iconTheme: IconThemeData(color: color?.titleTextColor),
primary: true, primary: true,
backgroundColor: color?.color,
title: collapsed.value title: collapsed.value
? Text( ? Text(
title, title,
style: style: Theme.of(context).textTheme.headline4?.copyWith(
Theme.of(context).textTheme.headline4?.copyWith(
color: color?.titleTextColor, color: color?.titleTextColor,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
) )
: null, : null,
backgroundColor: color?.color.withOpacity(0.8),
flexibleSpace: LayoutBuilder(builder: (context, constrains) { flexibleSpace: LayoutBuilder(builder: (context, constrains) {
return FlexibleSpaceBar( return FlexibleSpaceBar(
background: Container( background: Container(
@ -218,7 +220,9 @@ class TrackCollectionView extends HookConsumerWidget {
); );
}), }),
), ),
TracksTableView( tracksSnapshot.when(
data: (tracks) {
return TracksTableView(
tracks is! List<Track> tracks is! List<Track>
? tracks ? tracks
.map((track) => simpleTrackToTrack(track, album!)) .map((track) => simpleTrackToTrack(track, album!))
@ -227,14 +231,14 @@ class TrackCollectionView extends HookConsumerWidget {
onTrackPlayButtonPressed: onPlay, onTrackPlayButtonPressed: onPlay,
playlistId: id, playlistId: id,
userPlaylist: isOwned, userPlaylist: isOwned,
),
],
); );
}, },
error: (error, _) => Text("Error $error"), error: (error, _) =>
SliverToBoxAdapter(child: Text("Error $error")),
loading: () => const ShimmerTrackTile(), loading: () => const ShimmerTrackTile(),
), ),
), ],
)),
); );
} }
} }

View File

@ -97,77 +97,5 @@ class TracksTableView extends HookConsumerWidget {
}).toList() }).toList()
]), ]),
); );
return Container(
color: Theme.of(context).backgroundColor,
child: Scrollbar(
child: ListView(
children: [
if (heading != null) heading!,
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"#",
textAlign: TextAlign.center,
style: tableHeadStyle,
),
),
Expanded(
child: Row(
children: [
Text(
"Title",
style: tableHeadStyle,
overflow: TextOverflow.ellipsis,
),
],
),
),
// used alignment of this table-head
if (breakpoint.isMoreThan(Breakpoints.md)) ...[
const SizedBox(width: 100),
Expanded(
child: Row(
children: [
Text(
"Album",
overflow: TextOverflow.ellipsis,
style: tableHeadStyle,
),
],
),
)
],
if (!breakpoint.isSm) ...[
const SizedBox(width: 10),
Text("Time", style: tableHeadStyle),
const SizedBox(width: 10),
],
const SizedBox(width: 40),
],
),
...tracks.asMap().entries.map((track) {
String? thumbnailUrl = imageToUrlString(
track.value.album?.images,
index: (track.value.album?.images?.length ?? 1) - 1,
);
String duration =
"${track.value.duration?.inMinutes.remainder(60)}:${zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}";
return TrackTile(
playback,
playlistId: playlistId,
track: track,
duration: duration,
thumbnailUrl: thumbnailUrl,
userPlaylist: userPlaylist,
onTrackPlayButtonPressed: onTrackPlayButtonPressed,
);
}).toList()
],
),
),
);
} }
} }

View File

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
void useCustomStatusBarColor(Color color, bool isCurrentRoute) {
final context = useContext();
final backgroundColor = Theme.of(context).backgroundColor;
resetStatusbar() => SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: backgroundColor, // status bar color
statusBarIconBrightness: backgroundColor.computeLuminance() > 0.179
? Brightness.dark
: Brightness.light,
),
);
final statusBarColor = SystemChrome.latestStyle?.statusBarColor;
useEffect(() {
if (isCurrentRoute && statusBarColor != color) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: color, // status bar color
statusBarIconBrightness: color.computeLuminance() > 0.179
? Brightness.dark
: Brightness.light,
),
);
} else if (!isCurrentRoute && statusBarColor == color) {
resetStatusbar();
}
return;
}, [color, isCurrentRoute, statusBarColor]);
useEffect(() {
return resetStatusbar;
}, []);
}

View File

@ -7,6 +7,7 @@ import 'package:spotube/hooks/playback.dart';
import 'package:spotube/models/GlobalKeyActions.dart'; import 'package:spotube/models/GlobalKeyActions.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';
import 'package:spotube/utils/platform.dart';
useHotKeys(WidgetRef ref) { useHotKeys(WidgetRef ref) {
final playback = ref.watch(playbackProvider); final playback = ref.watch(playbackProvider);
@ -20,7 +21,7 @@ useHotKeys(WidgetRef ref) {
final _playOrPause = useTogglePlayPause(playback); final _playOrPause = useTogglePlayPause(playback);
useEffect(() { useEffect(() {
if (Platform.isIOS || Platform.isAndroid) return null; if (kIsMobile) return null;
_hotKeys = [ _hotKeys = [
GlobalKeyActions( GlobalKeyActions(
HotKey(KeyCode.space, scope: HotKeyScope.inapp), HotKey(KeyCode.space, scope: HotKeyScope.inapp),

View File

@ -16,13 +16,9 @@ import 'package:spotube/provider/YouTube.dart';
import 'package:spotube/themes/dark-theme.dart'; import 'package:spotube/themes/dark-theme.dart';
import 'package:spotube/themes/light-theme.dart'; import 'package:spotube/themes/light-theme.dart';
import 'package:spotube/utils/AudioPlayerHandler.dart'; import 'package:spotube/utils/AudioPlayerHandler.dart';
import 'package:spotube/utils/platform.dart';
void main() async { void main() async {
// await JustAudioBackground.init(
// androidNotificationChannelId: 'oss.krtirtho.Spotube',
// androidNotificationChannelName: 'Spotube',
// androidNotificationOngoing: true,
// );
AudioPlayerHandler audioPlayerHandler = await AudioService.init( AudioPlayerHandler audioPlayerHandler = await AudioService.init(
builder: () => AudioPlayerHandler(), builder: () => AudioPlayerHandler(),
config: const AudioServiceConfig( config: const AudioServiceConfig(
@ -31,12 +27,11 @@ void main() async {
androidNotificationOngoing: true, androidNotificationOngoing: true,
), ),
); );
if (!Platform.isAndroid && !Platform.isIOS) { if (kIsDesktop) {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await hotKeyManager.unregisterAll(); await hotKeyManager.unregisterAll();
doWhenWindowReady(() { doWhenWindowReady(() {
appWindow.minSize = appWindow.minSize = const Size(359, 700);
Size(Platform.isAndroid || Platform.isIOS ? 280 : 359, 700);
appWindow.alignment = Alignment.center; appWindow.alignment = Alignment.center;
appWindow.title = "Spotube"; appWindow.title = "Spotube";
appWindow.maximize(); appWindow.maximize();
@ -75,6 +70,7 @@ class Spotube extends HookConsumerWidget {
.watch(userPreferencesProvider.select((s) => s.backgroundColorScheme)); .watch(userPreferencesProvider.select((s) => s.backgroundColorScheme));
final player = ref.watch(audioPlayerProvider); final player = ref.watch(audioPlayerProvider);
final youtube = ref.watch(youtubeProvider); final youtube = ref.watch(youtubeProvider);
useEffect(() { useEffect(() {
return () { return () {
player.dispose(); player.dispose();

View File

@ -67,8 +67,8 @@ GoRouter createGoRouter() => GoRouter(
GoRoute( GoRoute(
path: "/player", path: "/player",
pageBuilder: (context, state) { pageBuilder: (context, state) {
return SpotubePage( return const SpotubePage(
child: const PlayerView(), child: PlayerView(),
); );
}, },
) )

View File

@ -72,7 +72,9 @@ class Auth extends PersistedChangeNotifier {
_clientSecret = map["clientSecret"]; _clientSecret = map["clientSecret"];
_accessToken = map["accessToken"]; _accessToken = map["accessToken"];
_refreshToken = map["refreshToken"]; _refreshToken = map["refreshToken"];
_expiration = DateTime.tryParse(map["expiration"]); _expiration = map["expiration"] != null
? DateTime.tryParse(map["expiration"])
: _expiration;
} }
@override @override

5
lib/utils/platform.dart Normal file
View File

@ -0,0 +1,5 @@
import 'dart:io';
final kIsDesktop = Platform.isLinux || Platform.isWindows || Platform.isMacOS;
final kIsMobile = Platform.isAndroid || Platform.isIOS;