From 09160b1a5365f93dfad431bc57be882f5777918a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 28 May 2022 19:16:20 +0600 Subject: [PATCH] Fixed statusbar color issue created by the new theme ChooseColorSchemeDialog now scrollable Initial FutureProvider integration Uri launches in System Webview in android fix --- AppImageBuilder.yml | 51 ++++++++++++- .../app/FlutterMultiDexApplication.java | 9 ++- lib/components/Home/Home.dart | 14 ++-- lib/components/Library/UserAlbums.dart | 39 +++++----- lib/components/Library/UserPlaylists.dart | 72 +++++++++---------- lib/components/Player/PlayerView.dart | 12 ++-- .../Settings/ColorSchemePickerDialog.dart | 34 ++++----- lib/helpers/server_ipc.dart | 6 +- lib/provider/SpotifyRequests.dart | 30 ++++++++ 9 files changed, 172 insertions(+), 95 deletions(-) create mode 100644 lib/provider/SpotifyRequests.dart diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml index 7d7514be..0644d570 100644 --- a/AppImageBuilder.yml +++ b/AppImageBuilder.yml @@ -1 +1,50 @@ -{"version":1,"script":["rm -rf AppDir || true","cp -r build/linux/x64/release/bundle AppDir","mkdir -p AppDir/usr/share/icons/hicolor/64x64/apps/","cp assets/spotube-logo.png AppDir/usr/share/icons/hicolor/"],"AppDir":{"path":"AppDir","app_info":{"id":"oss.krtirtho.spotube","icon":"spotube-logo","name":"spotube","version":"2.0.0+8","exec":"spotube","exec_args":"$@"},"apt":{"arch":"amd64","allow_unauthenticated":true,"sources":[{"sourceline":"deb http://archive.ubuntu.com/ubuntu/ hirsute main restricted"},{"sourceline":"deb http://archive.ubuntu.com/ubuntu/ hirsute-updates main restricted"},{"sourceline":"deb http://archive.ubuntu.com/ubuntu/ hirsute universe"},{"sourceline":"deb http://archive.ubuntu.com/ubuntu/ hirsute-updates universe"},{"sourceline":"deb http://archive.ubuntu.com/ubuntu/ hirsute multiverse"},{"sourceline":"deb http://archive.ubuntu.com/ubuntu/ hirsute-updates multiverse"},{"sourceline":"deb http://archive.ubuntu.com/ubuntu/ hirsute-backports main restricted universe multiverse"},{"sourceline":"deb http://security.ubuntu.com/ubuntu hirsute-security main restricted"},{"sourceline":"deb http://security.ubuntu.com/ubuntu hirsute-security universe"},{"sourceline":"deb http://security.ubuntu.com/ubuntu hirsute-security multiverse"}],"include":["libkeybinder-3.0-0"],"exclude":["libx11-6","libgtk-3-0","libglib2.0-0","libc6"]},"files":{"include":[],"exclude":[]}},"AppImage":{"arch":"x86_64","update-information":"guess"}} \ No newline at end of file +# appimage-builder recipe see https://appimage-builder.readthedocs.io for details +version: 1 +script: + - rm -rf AppDir || true + - cp -r build/linux/x64/release/bundle AppDir + - mkdir -p AppDir/usr/share/icons/hicolor/64x64/apps/ + - cp assets/spotube-logo.png AppDir/usr/share/icons/hicolor/64x64/apps/ +AppDir: + path: ./AppDir + app_info: + id: oss.krtirtho.spotube + name: Spotube + icon: spotube-logo + version: 2.0.0 + exec: spotube + exec_args: $@ + apt: + arch: amd64 + allow_unauthenticated: true + sources: + - sourceline: deb http://bd.archive.ubuntu.com/ubuntu/ hirsute main restricted + - sourceline: deb http://bd.archive.ubuntu.com/ubuntu/ hirsute-updates main restricted + - sourceline: deb http://bd.archive.ubuntu.com/ubuntu/ hirsute universe + - sourceline: deb http://bd.archive.ubuntu.com/ubuntu/ hirsute-updates universe + - sourceline: deb http://bd.archive.ubuntu.com/ubuntu/ hirsute multiverse + - sourceline: deb http://bd.archive.ubuntu.com/ubuntu/ hirsute-updates multiverse + - sourceline: + deb http://bd.archive.ubuntu.com/ubuntu/ hirsute-backports main + restricted universe multiverse + - sourceline: deb http://security.ubuntu.com/ubuntu hirsute-security main restricted + - sourceline: deb http://security.ubuntu.com/ubuntu hirsute-security universe + - sourceline: deb http://security.ubuntu.com/ubuntu hirsute-security multiverse + include: + - libkeybinder-3.0-0 + exclude: + - libx11-6 + - libgtk-3-0 + - libglib2.0-0 + - libc6 + files: + include: [] + exclude: + - usr/share/man + - usr/share/doc/*/README.* + - usr/share/doc/*/changelog.* + - usr/share/doc/*/NEWS.* + - usr/share/doc/*/TODO.* +AppImage: + arch: x86_64 + update-information: guess diff --git a/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java b/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java index 9213f130..752fc185 100644 --- a/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java +++ b/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java @@ -1,16 +1,21 @@ // Generated file. +// // If you wish to remove Flutter's multidex support, delete this entire file. +// +// Modifications to this file should be done in a copy under a different name +// as this file may be regenerated. package io.flutter.app; +import android.app.Application; import android.content.Context; import androidx.annotation.CallSuper; import androidx.multidex.MultiDex; /** - * Extension of {@link io.flutter.app.FlutterApplication}, adding multidex support. + * Extension of {@link android.app.Application}, adding multidex support. */ -public class FlutterMultiDexApplication extends FlutterApplication { +public class FlutterMultiDexApplication extends Application { @Override @CallSuper protected void attachBaseContext(Context base) { diff --git a/lib/components/Home/Home.dart b/lib/components/Home/Home.dart index b7527b89..b927504b 100644 --- a/lib/components/Home/Home.dart +++ b/lib/components/Home/Home.dart @@ -127,21 +127,19 @@ class Home extends HookConsumerWidget { ], )); - final brightness = Theme.of(context).brightness; + final backgroundColor = Theme.of(context).backgroundColor; useEffect(() { SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( - statusBarColor: brightness == Brightness.dark - ? Colors.blueGrey[900] - : Colors.white, // status bar color - statusBarIconBrightness: brightness == Brightness.dark - ? Brightness.light - : Brightness.dark, + statusBarColor: backgroundColor, // status bar color + statusBarIconBrightness: backgroundColor.computeLuminance() > 0.179 + ? Brightness.dark + : Brightness.light, ), ); return null; - }, [brightness]); + }, [backgroundColor]); return SafeArea( child: Scaffold( diff --git a/lib/components/Library/UserAlbums.dart b/lib/components/Library/UserAlbums.dart index c945293d..7c89c2d5 100644 --- a/lib/components/Library/UserAlbums.dart +++ b/lib/components/Library/UserAlbums.dart @@ -1,37 +1,32 @@ import 'package:flutter/material.dart' hide Image; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:spotify/spotify.dart'; import 'package:spotube/components/Album/AlbumCard.dart'; import 'package:spotube/helpers/simple-album-to-album.dart'; -import 'package:spotube/provider/SpotifyDI.dart'; +import 'package:spotube/provider/SpotifyRequests.dart'; class UserAlbums extends ConsumerWidget { const UserAlbums({Key? key}) : super(key: key); @override Widget build(BuildContext context, ref) { - SpotifyApi spotifyApi = ref.watch(spotifyProvider); + final albums = ref.watch(currentUserAlbumsQuery); - return FutureBuilder>( - future: spotifyApi.me.savedAlbums().all(), - builder: (context, snapshot) { - if (!snapshot.hasData && snapshot.data == null) { - return const Center(child: CircularProgressIndicator.adaptive()); - } - return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - spacing: 20, // gap between adjacent chips - runSpacing: 20, // gap between lines - alignment: WrapAlignment.center, - children: snapshot.data! - .map((album) => AlbumCard(simpleAlbumToAlbum(album))) - .toList(), - ), + return albums.when( + data: (data) => SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 20, // gap between adjacent chips + runSpacing: 20, // gap between lines + alignment: WrapAlignment.center, + children: data + .map((album) => AlbumCard(simpleAlbumToAlbum(album))) + .toList(), ), - ); - }, + ), + ), + loading: () => const Center(child: CircularProgressIndicator.adaptive()), + error: (_, __) => const Text("Failure is the pillar of success"), ); } } diff --git a/lib/components/Library/UserPlaylists.dart b/lib/components/Library/UserPlaylists.dart index d8db87a9..a3ca21d4 100644 --- a/lib/components/Library/UserPlaylists.dart +++ b/lib/components/Library/UserPlaylists.dart @@ -3,51 +3,47 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/Playlist/PlaylistCard.dart'; import 'package:spotube/components/Playlist/PlaylistCreateDialog.dart'; -import 'package:spotube/provider/SpotifyDI.dart'; +import 'package:spotube/provider/SpotifyRequests.dart'; class UserPlaylists extends ConsumerWidget { const UserPlaylists({Key? key}) : super(key: key); @override Widget build(BuildContext context, ref) { - SpotifyApi spotifyApi = ref.watch(spotifyProvider); + final playlists = ref.watch(currentUserPlaylistsQuery); - return FutureBuilder>( - future: spotifyApi.playlists.me.all(), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return const Center(child: CircularProgressIndicator.adaptive()); - } - Image image = Image(); - image.height = 300; - image.width = 300; - PlaylistSimple likedTracksPlaylist = PlaylistSimple(); - likedTracksPlaylist.name = "Liked Tracks"; - likedTracksPlaylist.type = "playlist"; - likedTracksPlaylist.collaborative = false; - likedTracksPlaylist.public = false; - likedTracksPlaylist.id = "user-liked-tracks"; - image.url = - "https://t.scdn.co/images/3099b3803ad9496896c43f22fe9be8c4.png"; - likedTracksPlaylist.images = [image]; - return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - spacing: 20, // gap between adjacent chips - runSpacing: 20, // gap between lines - alignment: WrapAlignment.center, - children: [ - const PlaylistCreateDialog(), - PlaylistCard(likedTracksPlaylist), - ...snapshot.data! - .map((playlist) => PlaylistCard(playlist)) - .toList(), - ], + return playlists.when( + loading: () => + const Center(child: CircularProgressIndicator.adaptive()), + data: (data) { + Image image = Image(); + image.height = 300; + image.width = 300; + PlaylistSimple likedTracksPlaylist = PlaylistSimple(); + likedTracksPlaylist.name = "Liked Tracks"; + likedTracksPlaylist.type = "playlist"; + likedTracksPlaylist.collaborative = false; + likedTracksPlaylist.public = false; + likedTracksPlaylist.id = "user-liked-tracks"; + image.url = + "https://t.scdn.co/images/3099b3803ad9496896c43f22fe9be8c4.png"; + likedTracksPlaylist.images = [image]; + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 20, // gap between adjacent chips + runSpacing: 20, // gap between lines + alignment: WrapAlignment.center, + children: [ + const PlaylistCreateDialog(), + PlaylistCard(likedTracksPlaylist), + ...data.map((playlist) => PlaylistCard(playlist)).toList(), + ], + ), ), - ), - ); - }, - ); + ); + }, + error: (_, __) => const Text("Failure is the pillar of success")); } } diff --git a/lib/components/Player/PlayerView.dart b/lib/components/Player/PlayerView.dart index 8216af3e..352b84f9 100644 --- a/lib/components/Player/PlayerView.dart +++ b/lib/components/Player/PlayerView.dart @@ -46,7 +46,7 @@ class PlayerView extends HookConsumerWidget { final PaletteColor paletteColor = usePaletteColor(context, albumArt); - final brightness = Theme.of(context).brightness; + final backgroundColor = Theme.of(context).backgroundColor; useEffect(() { SystemChrome.setSystemUIOverlayStyle( @@ -61,12 +61,10 @@ class PlayerView extends HookConsumerWidget { return () { SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( - statusBarColor: brightness == Brightness.dark - ? Colors.blueGrey[900] - : Colors.white, // status bar color - statusBarIconBrightness: brightness == Brightness.dark - ? Brightness.light - : Brightness.dark, + statusBarColor: backgroundColor, // status bar color + statusBarIconBrightness: backgroundColor.computeLuminance() > 0.179 + ? Brightness.dark + : Brightness.light, ), ); }; diff --git a/lib/components/Settings/ColorSchemePickerDialog.dart b/lib/components/Settings/ColorSchemePickerDialog.dart index 89d2984b..7ec221ed 100644 --- a/lib/components/Settings/ColorSchemePickerDialog.dart +++ b/lib/components/Settings/ColorSchemePickerDialog.dart @@ -75,22 +75,24 @@ class ColorSchemePickerDialog extends HookConsumerWidget { content: SizedBox( height: 200, width: 400, - child: Center( - child: Wrap( - spacing: 10, - runSpacing: 10, - children: colorsMap.entries - .map( - (e) => ColorTile( - color: e.value, - isActive: active.value == e.key, - tooltip: e.key, - onPressed: () { - active.value = e.key; - }, - ), - ) - .toList(), + child: SingleChildScrollView( + child: Center( + child: Wrap( + spacing: 10, + runSpacing: 10, + children: colorsMap.entries + .map( + (e) => ColorTile( + color: e.value, + isActive: active.value == e.key, + tooltip: e.key, + onPressed: () { + active.value = e.key; + }, + ), + ) + .toList(), + ), ), ), ), diff --git a/lib/helpers/server_ipc.dart b/lib/helpers/server_ipc.dart index c8f0de2e..bc541c21 100644 --- a/lib/helpers/server_ipc.dart +++ b/lib/helpers/server_ipc.dart @@ -8,7 +8,10 @@ final logger = getLogger("ServerIPC"); Future connectIpc(String authUri, String redirectUri) async { try { logger.i("[Launching]: $authUri"); - await launchUrl(Uri.parse(authUri)); + await launchUrl( + Uri.parse(authUri), + mode: LaunchMode.externalApplication, + ); HttpServer server = await HttpServer.bind(InternetAddress.loopbackIPv4, 4304); @@ -37,4 +40,5 @@ Future connectIpc(String authUri, String redirectUri) async { logger.e("connectIpc", e, stack); rethrow; } + return null; } diff --git a/lib/provider/SpotifyRequests.dart b/lib/provider/SpotifyRequests.dart new file mode 100644 index 00000000..a2854f7d --- /dev/null +++ b/lib/provider/SpotifyRequests.dart @@ -0,0 +1,30 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:spotube/provider/SpotifyDI.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/provider/UserPreferences.dart'; + +final categoriesQuery = FutureProvider.family, int>( + (ref, pageKey) { + final spotify = ref.watch(spotifyProvider); + final recommendationMarket = ref.watch( + userPreferencesProvider.select((s) => s.recommendationMarket), + ); + return spotify.categories + .list(country: recommendationMarket) + .getPage(15, pageKey); + }, +); + +final currentUserPlaylistsQuery = FutureProvider>( + (ref) { + final spotify = ref.watch(spotifyProvider); + return spotify.playlists.me.all(); + }, +); + +final currentUserAlbumsQuery = FutureProvider>( + (ref) { + final spotify = ref.watch(spotifyProvider); + return spotify.me.savedAlbums().all(); + }, +);