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
ko_fi: krtirtho
patreon: krtirtho
custom:
- "https://www.buymeacoffee.com/krtirtho"

View File

@ -35,6 +35,8 @@ jobs:
build/Spotube-linux-x86_64.tar.xz
build/Spotube-*-x86_64.AppImage
# 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: make apk
- uses: actions/upload-artifact@v2

3
.gitignore vendored
View File

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

View File

@ -25,6 +25,12 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
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 {
compileSdkVersion 31
@ -51,11 +57,17 @@ android {
multiDexEnabled true
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
signingConfig signingConfigs.release
}
}
}

View File

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

View File

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

View File

@ -44,7 +44,7 @@ class ShimmerArtistProfile extends HookWidget {
),
),
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';
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
Widget build(BuildContext context) {
@ -13,25 +18,35 @@ class ShimmerTrackTile extends StatelessWidget {
.extension<ShimmerColorTheme>()!
.shimmerBackgroundColor!;
return Padding(
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),
child: Row(
final single = Container(
margin: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
SkeletonAnimation(
shimmerColor: shimmerColor,
borderRadius: BorderRadius.circular(20),
shimmerDuration: 1000,
child: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: shimmerBackgroundColor,
borderRadius: BorderRadius.circular(10),
),
margin: const EdgeInsets.only(top: 10),
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SkeletonAnimation(
shimmerColor: shimmerColor,
borderRadius: BorderRadius.circular(20),
shimmerDuration: 1000,
child: Container(
width: 50,
height: 50,
height: 15,
decoration: BoxDecoration(
color: shimmerBackgroundColor,
borderRadius: BorderRadius.circular(10),
@ -39,46 +54,41 @@ class ShimmerTrackTile extends StatelessWidget {
margin: const EdgeInsets.only(top: 10),
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SkeletonAnimation(
shimmerColor: shimmerColor,
borderRadius: BorderRadius.circular(20),
shimmerDuration: 1000,
child: Container(
height: 15,
decoration: BoxDecoration(
color: shimmerBackgroundColor,
borderRadius: BorderRadius.circular(10),
),
margin: const EdgeInsets.only(top: 10),
),
),
SkeletonAnimation(
shimmerColor: shimmerColor,
borderRadius: BorderRadius.circular(20),
shimmerDuration: 1000,
child: Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .8),
height: 10,
decoration: BoxDecoration(
color: shimmerBackgroundColor,
borderRadius: BorderRadius.circular(10),
),
margin: const EdgeInsets.only(top: 10),
),
),
],
SkeletonAnimation(
shimmerColor: shimmerColor,
borderRadius: BorderRadius.circular(20),
shimmerDuration: 1000,
child: Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * .8),
height: 10,
decoration: BoxDecoration(
color: shimmerBackgroundColor,
borderRadius: BorderRadius.circular(10),
),
margin: const EdgeInsets.only(top: 10),
),
),
],
),
);
},
),
],
),
);
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:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.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/image-to-url-string.dart';
import 'package:spotube/hooks/useBreakpoints.dart';
import 'package:spotube/hooks/useCustomStatusBarColor.dart';
import 'package:spotube/hooks/usePaletteColor.dart';
import 'package:spotube/provider/Playback.dart';
@ -46,29 +46,10 @@ class PlayerView extends HookConsumerWidget {
final PaletteColor paletteColor = usePaletteColor(context, albumArt, ref);
final backgroundColor = Theme.of(context).backgroundColor;
useEffect(() {
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,
),
);
};
}, []);
useCustomStatusBarColor(
paletteColor.color,
GoRouter.of(context).location == "/player",
);
return SafeArea(
child: Scaffold(

View File

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

View File

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

View File

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

View File

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

View File

@ -1,14 +1,17 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/LoaderShimmers/ShimmerTrackTile.dart';
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
import 'package:spotube/components/Shared/TracksTableView.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/models/Logger.dart';
import 'package:flutter/material.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/utils/platform.dart';
class TrackCollectionView extends HookConsumerWidget {
final logger = getLogger(TrackCollectionView);
@ -25,6 +28,8 @@ class TrackCollectionView extends HookConsumerWidget {
final bool showShare;
final bool isOwned;
final String routePath;
TrackCollectionView({
required this.title,
required this.id,
@ -33,6 +38,7 @@ class TrackCollectionView extends HookConsumerWidget {
required this.isPlaying,
required this.onPlay,
required this.onShare,
required this.routePath,
this.heartBtn,
this.album,
this.description,
@ -83,6 +89,11 @@ class TrackCollectionView extends HookConsumerWidget {
final collapsed = useState(false);
useCustomStatusBarColor(
color?.color ?? Theme.of(context).backgroundColor,
GoRouter.of(context).location == routePath,
);
useEffect(() {
listener() {
if (controller.position.pixels >= 400 && !collapsed.value) {
@ -99,142 +110,135 @@ class TrackCollectionView extends HookConsumerWidget {
return SafeArea(
child: Scaffold(
appBar: PageWindowTitleBar(
backgroundColor:
tracksSnapshot.asData?.value != null ? color?.color : null,
foregroundColor: tracksSnapshot.asData?.value != null
? color?.titleTextColor
appBar: (kIsDesktop)
? PageWindowTitleBar(
backgroundColor: color?.color,
foregroundColor: color?.titleTextColor,
leading: Row(
children: [BackButton(color: color?.titleTextColor)],
),
)
: null,
leading: Row(
children: [
BackButton(
color: tracksSnapshot.asData?.value != null
? color?.titleTextColor
: null,
)
],
),
),
body: tracksSnapshot.when(
data: (tracks) {
return CustomScrollView(
controller: controller,
slivers: [
SliverAppBar(
actions: collapsed.value ? buttons : null,
floating: false,
pinned: true,
expandedHeight: 400,
automaticallyImplyLeading: false,
primary: true,
title: collapsed.value
? Text(
title,
style:
Theme.of(context).textTheme.headline4?.copyWith(
color: color?.titleTextColor,
fontWeight: FontWeight.w600,
),
)
: null,
backgroundColor: color?.color.withOpacity(0.8),
flexibleSpace: LayoutBuilder(builder: (context, constrains) {
return FlexibleSpaceBar(
background: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
color?.color ?? Colors.transparent,
Theme.of(context).canvasColor,
],
begin: const FractionalOffset(0, 0),
end: const FractionalOffset(0, 1),
tileMode: TileMode.clamp,
),
),
child: Material(
type: MaterialType.transparency,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
body: CustomScrollView(
controller: controller,
slivers: [
SliverAppBar(
actions: collapsed.value ? buttons : null,
floating: false,
pinned: true,
expandedHeight: 400,
automaticallyImplyLeading: kIsMobile,
iconTheme: IconThemeData(color: color?.titleTextColor),
primary: true,
backgroundColor: color?.color,
title: collapsed.value
? Text(
title,
style: Theme.of(context).textTheme.headline4?.copyWith(
color: color?.titleTextColor,
fontWeight: FontWeight.w600,
),
child: Wrap(
spacing: 20,
runSpacing: 20,
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.center,
runAlignment: WrapAlignment.center,
children: [
Container(
constraints:
const BoxConstraints(maxHeight: 200),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
imageUrl: titleImage,
),
)
: null,
flexibleSpace: LayoutBuilder(builder: (context, constrains) {
return FlexibleSpaceBar(
background: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
color?.color ?? Colors.transparent,
Theme.of(context).canvasColor,
],
begin: const FractionalOffset(0, 0),
end: const FractionalOffset(0, 1),
tileMode: TileMode.clamp,
),
),
child: Material(
type: MaterialType.transparency,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
),
child: Wrap(
spacing: 20,
runSpacing: 20,
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.center,
runAlignment: WrapAlignment.center,
children: [
Container(
constraints:
const BoxConstraints(maxHeight: 200),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
imageUrl: titleImage,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: Theme.of(context)
.textTheme
.headline4
?.copyWith(
color: color?.titleTextColor,
fontWeight: FontWeight.w600,
),
),
if (description != null)
Text(
title,
description!,
style: Theme.of(context)
.textTheme
.headline4
.bodyLarge
?.copyWith(
color: color?.titleTextColor,
fontWeight: FontWeight.w600,
color: color?.bodyTextColor,
),
maxLines: 2,
overflow: TextOverflow.fade,
),
if (description != null)
Text(
description!,
style: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(
color: color?.bodyTextColor,
),
maxLines: 2,
overflow: TextOverflow.fade,
),
const SizedBox(height: 10),
Row(
mainAxisSize: MainAxisSize.min,
children: buttons,
),
],
)
],
),
const SizedBox(height: 10),
Row(
mainAxisSize: MainAxisSize.min,
children: buttons,
),
],
)
],
),
),
),
);
}),
),
TracksTableView(
tracks is! List<Track>
? tracks
.map((track) => simpleTrackToTrack(track, album!))
.toList()
: tracks,
onTrackPlayButtonPressed: onPlay,
playlistId: id,
userPlaylist: isOwned,
),
],
);
},
error: (error, _) => Text("Error $error"),
loading: () => const ShimmerTrackTile(),
),
),
),
);
}),
),
tracksSnapshot.when(
data: (tracks) {
return TracksTableView(
tracks is! List<Track>
? tracks
.map((track) => simpleTrackToTrack(track, album!))
.toList()
: tracks,
onTrackPlayButtonPressed: onPlay,
playlistId: id,
userPlaylist: isOwned,
);
},
error: (error, _) =>
SliverToBoxAdapter(child: Text("Error $error")),
loading: () => const ShimmerTrackTile(),
),
],
)),
);
}
}

View File

@ -97,77 +97,5 @@ class TracksTableView extends HookConsumerWidget {
}).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/provider/Playback.dart';
import 'package:spotube/provider/UserPreferences.dart';
import 'package:spotube/utils/platform.dart';
useHotKeys(WidgetRef ref) {
final playback = ref.watch(playbackProvider);
@ -20,7 +21,7 @@ useHotKeys(WidgetRef ref) {
final _playOrPause = useTogglePlayPause(playback);
useEffect(() {
if (Platform.isIOS || Platform.isAndroid) return null;
if (kIsMobile) return null;
_hotKeys = [
GlobalKeyActions(
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/light-theme.dart';
import 'package:spotube/utils/AudioPlayerHandler.dart';
import 'package:spotube/utils/platform.dart';
void main() async {
// await JustAudioBackground.init(
// androidNotificationChannelId: 'oss.krtirtho.Spotube',
// androidNotificationChannelName: 'Spotube',
// androidNotificationOngoing: true,
// );
AudioPlayerHandler audioPlayerHandler = await AudioService.init(
builder: () => AudioPlayerHandler(),
config: const AudioServiceConfig(
@ -31,12 +27,11 @@ void main() async {
androidNotificationOngoing: true,
),
);
if (!Platform.isAndroid && !Platform.isIOS) {
if (kIsDesktop) {
WidgetsFlutterBinding.ensureInitialized();
await hotKeyManager.unregisterAll();
doWhenWindowReady(() {
appWindow.minSize =
Size(Platform.isAndroid || Platform.isIOS ? 280 : 359, 700);
appWindow.minSize = const Size(359, 700);
appWindow.alignment = Alignment.center;
appWindow.title = "Spotube";
appWindow.maximize();
@ -75,6 +70,7 @@ class Spotube extends HookConsumerWidget {
.watch(userPreferencesProvider.select((s) => s.backgroundColorScheme));
final player = ref.watch(audioPlayerProvider);
final youtube = ref.watch(youtubeProvider);
useEffect(() {
return () {
player.dispose();

View File

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

View File

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