refactor: use metadata plugin authentication instead

This commit is contained in:
Kingkor Roy Tirtho 2025-06-19 22:32:22 +06:00
parent 41cc79b5e6
commit aa65bf291d
22 changed files with 192 additions and 778 deletions

View File

@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/services/kv_store/kv_store.dart';
final rootNavigatorKey = GlobalKey<NavigatorState>();
@ -28,9 +28,10 @@ class AppRouter extends RootStackRouter {
guards: [
AutoRouteGuardCallback(
(resolver, router) async {
final auth = await ref.read(authenticationProvider.future);
final authenticated = await ref
.read(metadataPluginAuthenticatedProvider.future);
if (auth == null && !KVStoreService.doneGettingStarted) {
if (!authenticated && !KVStoreService.doneGettingStarted) {
resolver.redirect(const GettingStartedRoute());
} else {
resolver.next(true);
@ -209,11 +210,6 @@ class AppRouter extends RootStackRouter {
page: GettingStartedRoute.page,
// parentNavigatorKey: rootNavigatorKey,
),
AutoRoute(
path: "/login",
page: WebViewLoginRoute.page,
// parentNavigatorKey: rootNavigatorKey,
),
AutoRoute(
path: "/lastfm-login",
page: LastFMLoginRoute.page,

View File

@ -8,10 +8,10 @@
// coverage:ignore-file
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:auto_route/auto_route.dart' as _i40;
import 'package:flutter/material.dart' as _i41;
import 'package:shadcn_flutter/shadcn_flutter.dart' as _i43;
import 'package:spotube/models/metadata/metadata.dart' as _i42;
import 'package:auto_route/auto_route.dart' as _i39;
import 'package:flutter/material.dart' as _i40;
import 'package:shadcn_flutter/shadcn_flutter.dart' as _i42;
import 'package:spotube/models/metadata/metadata.dart' as _i41;
import 'package:spotube/pages/album/album.dart' as _i2;
import 'package:spotube/pages/artist/artist.dart' as _i3;
import 'package:spotube/pages/connect/connect.dart' as _i6;
@ -31,7 +31,6 @@ import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'
import 'package:spotube/pages/library/user_playlists.dart' as _i38;
import 'package:spotube/pages/lyrics/lyrics.dart' as _i15;
import 'package:spotube/pages/lyrics/mini_lyrics.dart' as _i16;
import 'package:spotube/pages/mobile_login/mobile_login.dart' as _i39;
import 'package:spotube/pages/player/lyrics.dart' as _i17;
import 'package:spotube/pages/player/queue.dart' as _i18;
import 'package:spotube/pages/player/sources.dart' as _i19;
@ -56,8 +55,8 @@ import 'package:spotube/pages/track/track.dart' as _i33;
/// generated route for
/// [_i1.AboutSpotubePage]
class AboutSpotubeRoute extends _i40.PageRouteInfo<void> {
const AboutSpotubeRoute({List<_i40.PageRouteInfo>? children})
class AboutSpotubeRoute extends _i39.PageRouteInfo<void> {
const AboutSpotubeRoute({List<_i39.PageRouteInfo>? children})
: super(
AboutSpotubeRoute.name,
initialChildren: children,
@ -65,7 +64,7 @@ class AboutSpotubeRoute extends _i40.PageRouteInfo<void> {
static const String name = 'AboutSpotubeRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i1.AboutSpotubePage();
@ -75,12 +74,12 @@ class AboutSpotubeRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i2.AlbumPage]
class AlbumRoute extends _i40.PageRouteInfo<AlbumRouteArgs> {
class AlbumRoute extends _i39.PageRouteInfo<AlbumRouteArgs> {
AlbumRoute({
_i41.Key? key,
_i40.Key? key,
required String id,
required _i42.SpotubeSimpleAlbumObject album,
List<_i40.PageRouteInfo>? children,
required _i41.SpotubeSimpleAlbumObject album,
List<_i39.PageRouteInfo>? children,
}) : super(
AlbumRoute.name,
args: AlbumRouteArgs(
@ -94,7 +93,7 @@ class AlbumRoute extends _i40.PageRouteInfo<AlbumRouteArgs> {
static const String name = 'AlbumRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
final args = data.argsAs<AlbumRouteArgs>();
@ -114,11 +113,11 @@ class AlbumRouteArgs {
required this.album,
});
final _i41.Key? key;
final _i40.Key? key;
final String id;
final _i42.SpotubeSimpleAlbumObject album;
final _i41.SpotubeSimpleAlbumObject album;
@override
String toString() {
@ -128,11 +127,11 @@ class AlbumRouteArgs {
/// generated route for
/// [_i3.ArtistPage]
class ArtistRoute extends _i40.PageRouteInfo<ArtistRouteArgs> {
class ArtistRoute extends _i39.PageRouteInfo<ArtistRouteArgs> {
ArtistRoute({
required String artistId,
_i41.Key? key,
List<_i40.PageRouteInfo>? children,
_i40.Key? key,
List<_i39.PageRouteInfo>? children,
}) : super(
ArtistRoute.name,
args: ArtistRouteArgs(
@ -145,7 +144,7 @@ class ArtistRoute extends _i40.PageRouteInfo<ArtistRouteArgs> {
static const String name = 'ArtistRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
final pathParams = data.inheritedPathParams;
@ -167,7 +166,7 @@ class ArtistRouteArgs {
final String artistId;
final _i41.Key? key;
final _i40.Key? key;
@override
String toString() {
@ -177,8 +176,8 @@ class ArtistRouteArgs {
/// generated route for
/// [_i4.BlackListPage]
class BlackListRoute extends _i40.PageRouteInfo<void> {
const BlackListRoute({List<_i40.PageRouteInfo>? children})
class BlackListRoute extends _i39.PageRouteInfo<void> {
const BlackListRoute({List<_i39.PageRouteInfo>? children})
: super(
BlackListRoute.name,
initialChildren: children,
@ -186,7 +185,7 @@ class BlackListRoute extends _i40.PageRouteInfo<void> {
static const String name = 'BlackListRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i4.BlackListPage();
@ -196,8 +195,8 @@ class BlackListRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i5.ConnectControlPage]
class ConnectControlRoute extends _i40.PageRouteInfo<void> {
const ConnectControlRoute({List<_i40.PageRouteInfo>? children})
class ConnectControlRoute extends _i39.PageRouteInfo<void> {
const ConnectControlRoute({List<_i39.PageRouteInfo>? children})
: super(
ConnectControlRoute.name,
initialChildren: children,
@ -205,7 +204,7 @@ class ConnectControlRoute extends _i40.PageRouteInfo<void> {
static const String name = 'ConnectControlRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i5.ConnectControlPage();
@ -215,8 +214,8 @@ class ConnectControlRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i6.ConnectPage]
class ConnectRoute extends _i40.PageRouteInfo<void> {
const ConnectRoute({List<_i40.PageRouteInfo>? children})
class ConnectRoute extends _i39.PageRouteInfo<void> {
const ConnectRoute({List<_i39.PageRouteInfo>? children})
: super(
ConnectRoute.name,
initialChildren: children,
@ -224,7 +223,7 @@ class ConnectRoute extends _i40.PageRouteInfo<void> {
static const String name = 'ConnectRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i6.ConnectPage();
@ -234,8 +233,8 @@ class ConnectRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i7.GettingStartedPage]
class GettingStartedRoute extends _i40.PageRouteInfo<void> {
const GettingStartedRoute({List<_i40.PageRouteInfo>? children})
class GettingStartedRoute extends _i39.PageRouteInfo<void> {
const GettingStartedRoute({List<_i39.PageRouteInfo>? children})
: super(
GettingStartedRoute.name,
initialChildren: children,
@ -243,7 +242,7 @@ class GettingStartedRoute extends _i40.PageRouteInfo<void> {
static const String name = 'GettingStartedRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i7.GettingStartedPage();
@ -254,12 +253,12 @@ class GettingStartedRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i8.HomeBrowseSectionItemsPage]
class HomeBrowseSectionItemsRoute
extends _i40.PageRouteInfo<HomeBrowseSectionItemsRouteArgs> {
extends _i39.PageRouteInfo<HomeBrowseSectionItemsRouteArgs> {
HomeBrowseSectionItemsRoute({
_i43.Key? key,
_i42.Key? key,
required String sectionId,
required _i42.SpotubeBrowseSectionObject<Object> section,
List<_i40.PageRouteInfo>? children,
required _i41.SpotubeBrowseSectionObject<Object> section,
List<_i39.PageRouteInfo>? children,
}) : super(
HomeBrowseSectionItemsRoute.name,
args: HomeBrowseSectionItemsRouteArgs(
@ -273,7 +272,7 @@ class HomeBrowseSectionItemsRoute
static const String name = 'HomeBrowseSectionItemsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
final args = data.argsAs<HomeBrowseSectionItemsRouteArgs>();
@ -293,11 +292,11 @@ class HomeBrowseSectionItemsRouteArgs {
required this.section,
});
final _i43.Key? key;
final _i42.Key? key;
final String sectionId;
final _i42.SpotubeBrowseSectionObject<Object> section;
final _i41.SpotubeBrowseSectionObject<Object> section;
@override
String toString() {
@ -307,8 +306,8 @@ class HomeBrowseSectionItemsRouteArgs {
/// generated route for
/// [_i9.HomePage]
class HomeRoute extends _i40.PageRouteInfo<void> {
const HomeRoute({List<_i40.PageRouteInfo>? children})
class HomeRoute extends _i39.PageRouteInfo<void> {
const HomeRoute({List<_i39.PageRouteInfo>? children})
: super(
HomeRoute.name,
initialChildren: children,
@ -316,7 +315,7 @@ class HomeRoute extends _i40.PageRouteInfo<void> {
static const String name = 'HomeRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i9.HomePage();
@ -326,8 +325,8 @@ class HomeRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i10.LastFMLoginPage]
class LastFMLoginRoute extends _i40.PageRouteInfo<void> {
const LastFMLoginRoute({List<_i40.PageRouteInfo>? children})
class LastFMLoginRoute extends _i39.PageRouteInfo<void> {
const LastFMLoginRoute({List<_i39.PageRouteInfo>? children})
: super(
LastFMLoginRoute.name,
initialChildren: children,
@ -335,7 +334,7 @@ class LastFMLoginRoute extends _i40.PageRouteInfo<void> {
static const String name = 'LastFMLoginRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i10.LastFMLoginPage();
@ -345,8 +344,8 @@ class LastFMLoginRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i11.LibraryPage]
class LibraryRoute extends _i40.PageRouteInfo<void> {
const LibraryRoute({List<_i40.PageRouteInfo>? children})
class LibraryRoute extends _i39.PageRouteInfo<void> {
const LibraryRoute({List<_i39.PageRouteInfo>? children})
: super(
LibraryRoute.name,
initialChildren: children,
@ -354,7 +353,7 @@ class LibraryRoute extends _i40.PageRouteInfo<void> {
static const String name = 'LibraryRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i11.LibraryPage();
@ -364,11 +363,11 @@ class LibraryRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i12.LikedPlaylistPage]
class LikedPlaylistRoute extends _i40.PageRouteInfo<LikedPlaylistRouteArgs> {
class LikedPlaylistRoute extends _i39.PageRouteInfo<LikedPlaylistRouteArgs> {
LikedPlaylistRoute({
_i41.Key? key,
required _i42.SpotubeSimplePlaylistObject playlist,
List<_i40.PageRouteInfo>? children,
_i40.Key? key,
required _i41.SpotubeSimplePlaylistObject playlist,
List<_i39.PageRouteInfo>? children,
}) : super(
LikedPlaylistRoute.name,
args: LikedPlaylistRouteArgs(
@ -380,7 +379,7 @@ class LikedPlaylistRoute extends _i40.PageRouteInfo<LikedPlaylistRouteArgs> {
static const String name = 'LikedPlaylistRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
final args = data.argsAs<LikedPlaylistRouteArgs>();
@ -398,9 +397,9 @@ class LikedPlaylistRouteArgs {
required this.playlist,
});
final _i41.Key? key;
final _i40.Key? key;
final _i42.SpotubeSimplePlaylistObject playlist;
final _i41.SpotubeSimplePlaylistObject playlist;
@override
String toString() {
@ -410,13 +409,13 @@ class LikedPlaylistRouteArgs {
/// generated route for
/// [_i13.LocalLibraryPage]
class LocalLibraryRoute extends _i40.PageRouteInfo<LocalLibraryRouteArgs> {
class LocalLibraryRoute extends _i39.PageRouteInfo<LocalLibraryRouteArgs> {
LocalLibraryRoute({
required String location,
_i41.Key? key,
_i40.Key? key,
bool isDownloads = false,
bool isCache = false,
List<_i40.PageRouteInfo>? children,
List<_i39.PageRouteInfo>? children,
}) : super(
LocalLibraryRoute.name,
args: LocalLibraryRouteArgs(
@ -430,7 +429,7 @@ class LocalLibraryRoute extends _i40.PageRouteInfo<LocalLibraryRouteArgs> {
static const String name = 'LocalLibraryRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
final args = data.argsAs<LocalLibraryRouteArgs>();
@ -454,7 +453,7 @@ class LocalLibraryRouteArgs {
final String location;
final _i41.Key? key;
final _i40.Key? key;
final bool isDownloads;
@ -468,8 +467,8 @@ class LocalLibraryRouteArgs {
/// generated route for
/// [_i14.LogsPage]
class LogsRoute extends _i40.PageRouteInfo<void> {
const LogsRoute({List<_i40.PageRouteInfo>? children})
class LogsRoute extends _i39.PageRouteInfo<void> {
const LogsRoute({List<_i39.PageRouteInfo>? children})
: super(
LogsRoute.name,
initialChildren: children,
@ -477,7 +476,7 @@ class LogsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'LogsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i14.LogsPage();
@ -487,8 +486,8 @@ class LogsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i15.LyricsPage]
class LyricsRoute extends _i40.PageRouteInfo<void> {
const LyricsRoute({List<_i40.PageRouteInfo>? children})
class LyricsRoute extends _i39.PageRouteInfo<void> {
const LyricsRoute({List<_i39.PageRouteInfo>? children})
: super(
LyricsRoute.name,
initialChildren: children,
@ -496,7 +495,7 @@ class LyricsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'LyricsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i15.LyricsPage();
@ -506,11 +505,11 @@ class LyricsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i16.MiniLyricsPage]
class MiniLyricsRoute extends _i40.PageRouteInfo<MiniLyricsRouteArgs> {
class MiniLyricsRoute extends _i39.PageRouteInfo<MiniLyricsRouteArgs> {
MiniLyricsRoute({
_i43.Key? key,
required _i43.Size prevSize,
List<_i40.PageRouteInfo>? children,
_i42.Key? key,
required _i42.Size prevSize,
List<_i39.PageRouteInfo>? children,
}) : super(
MiniLyricsRoute.name,
args: MiniLyricsRouteArgs(
@ -522,7 +521,7 @@ class MiniLyricsRoute extends _i40.PageRouteInfo<MiniLyricsRouteArgs> {
static const String name = 'MiniLyricsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
final args = data.argsAs<MiniLyricsRouteArgs>();
@ -540,9 +539,9 @@ class MiniLyricsRouteArgs {
required this.prevSize,
});
final _i43.Key? key;
final _i42.Key? key;
final _i43.Size prevSize;
final _i42.Size prevSize;
@override
String toString() {
@ -552,8 +551,8 @@ class MiniLyricsRouteArgs {
/// generated route for
/// [_i17.PlayerLyricsPage]
class PlayerLyricsRoute extends _i40.PageRouteInfo<void> {
const PlayerLyricsRoute({List<_i40.PageRouteInfo>? children})
class PlayerLyricsRoute extends _i39.PageRouteInfo<void> {
const PlayerLyricsRoute({List<_i39.PageRouteInfo>? children})
: super(
PlayerLyricsRoute.name,
initialChildren: children,
@ -561,7 +560,7 @@ class PlayerLyricsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'PlayerLyricsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i17.PlayerLyricsPage();
@ -571,8 +570,8 @@ class PlayerLyricsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i18.PlayerQueuePage]
class PlayerQueueRoute extends _i40.PageRouteInfo<void> {
const PlayerQueueRoute({List<_i40.PageRouteInfo>? children})
class PlayerQueueRoute extends _i39.PageRouteInfo<void> {
const PlayerQueueRoute({List<_i39.PageRouteInfo>? children})
: super(
PlayerQueueRoute.name,
initialChildren: children,
@ -580,7 +579,7 @@ class PlayerQueueRoute extends _i40.PageRouteInfo<void> {
static const String name = 'PlayerQueueRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i18.PlayerQueuePage();
@ -590,8 +589,8 @@ class PlayerQueueRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i19.PlayerTrackSourcesPage]
class PlayerTrackSourcesRoute extends _i40.PageRouteInfo<void> {
const PlayerTrackSourcesRoute({List<_i40.PageRouteInfo>? children})
class PlayerTrackSourcesRoute extends _i39.PageRouteInfo<void> {
const PlayerTrackSourcesRoute({List<_i39.PageRouteInfo>? children})
: super(
PlayerTrackSourcesRoute.name,
initialChildren: children,
@ -599,7 +598,7 @@ class PlayerTrackSourcesRoute extends _i40.PageRouteInfo<void> {
static const String name = 'PlayerTrackSourcesRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i19.PlayerTrackSourcesPage();
@ -609,12 +608,12 @@ class PlayerTrackSourcesRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i20.PlaylistPage]
class PlaylistRoute extends _i40.PageRouteInfo<PlaylistRouteArgs> {
class PlaylistRoute extends _i39.PageRouteInfo<PlaylistRouteArgs> {
PlaylistRoute({
_i41.Key? key,
_i40.Key? key,
required String id,
required _i42.SpotubeSimplePlaylistObject playlist,
List<_i40.PageRouteInfo>? children,
required _i41.SpotubeSimplePlaylistObject playlist,
List<_i39.PageRouteInfo>? children,
}) : super(
PlaylistRoute.name,
args: PlaylistRouteArgs(
@ -628,7 +627,7 @@ class PlaylistRoute extends _i40.PageRouteInfo<PlaylistRouteArgs> {
static const String name = 'PlaylistRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
final args = data.argsAs<PlaylistRouteArgs>();
@ -648,11 +647,11 @@ class PlaylistRouteArgs {
required this.playlist,
});
final _i41.Key? key;
final _i40.Key? key;
final String id;
final _i42.SpotubeSimplePlaylistObject playlist;
final _i41.SpotubeSimplePlaylistObject playlist;
@override
String toString() {
@ -662,8 +661,8 @@ class PlaylistRouteArgs {
/// generated route for
/// [_i21.ProfilePage]
class ProfileRoute extends _i40.PageRouteInfo<void> {
const ProfileRoute({List<_i40.PageRouteInfo>? children})
class ProfileRoute extends _i39.PageRouteInfo<void> {
const ProfileRoute({List<_i39.PageRouteInfo>? children})
: super(
ProfileRoute.name,
initialChildren: children,
@ -671,7 +670,7 @@ class ProfileRoute extends _i40.PageRouteInfo<void> {
static const String name = 'ProfileRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i21.ProfilePage();
@ -681,8 +680,8 @@ class ProfileRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i22.RootAppPage]
class RootAppRoute extends _i40.PageRouteInfo<void> {
const RootAppRoute({List<_i40.PageRouteInfo>? children})
class RootAppRoute extends _i39.PageRouteInfo<void> {
const RootAppRoute({List<_i39.PageRouteInfo>? children})
: super(
RootAppRoute.name,
initialChildren: children,
@ -690,7 +689,7 @@ class RootAppRoute extends _i40.PageRouteInfo<void> {
static const String name = 'RootAppRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i22.RootAppPage();
@ -700,8 +699,8 @@ class RootAppRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i23.SearchPage]
class SearchRoute extends _i40.PageRouteInfo<void> {
const SearchRoute({List<_i40.PageRouteInfo>? children})
class SearchRoute extends _i39.PageRouteInfo<void> {
const SearchRoute({List<_i39.PageRouteInfo>? children})
: super(
SearchRoute.name,
initialChildren: children,
@ -709,7 +708,7 @@ class SearchRoute extends _i40.PageRouteInfo<void> {
static const String name = 'SearchRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i23.SearchPage();
@ -719,8 +718,8 @@ class SearchRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i24.SettingsMetadataProviderPage]
class SettingsMetadataProviderRoute extends _i40.PageRouteInfo<void> {
const SettingsMetadataProviderRoute({List<_i40.PageRouteInfo>? children})
class SettingsMetadataProviderRoute extends _i39.PageRouteInfo<void> {
const SettingsMetadataProviderRoute({List<_i39.PageRouteInfo>? children})
: super(
SettingsMetadataProviderRoute.name,
initialChildren: children,
@ -728,7 +727,7 @@ class SettingsMetadataProviderRoute extends _i40.PageRouteInfo<void> {
static const String name = 'SettingsMetadataProviderRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i24.SettingsMetadataProviderPage();
@ -738,8 +737,8 @@ class SettingsMetadataProviderRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i25.SettingsPage]
class SettingsRoute extends _i40.PageRouteInfo<void> {
const SettingsRoute({List<_i40.PageRouteInfo>? children})
class SettingsRoute extends _i39.PageRouteInfo<void> {
const SettingsRoute({List<_i39.PageRouteInfo>? children})
: super(
SettingsRoute.name,
initialChildren: children,
@ -747,7 +746,7 @@ class SettingsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'SettingsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i25.SettingsPage();
@ -757,8 +756,8 @@ class SettingsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i26.StatsAlbumsPage]
class StatsAlbumsRoute extends _i40.PageRouteInfo<void> {
const StatsAlbumsRoute({List<_i40.PageRouteInfo>? children})
class StatsAlbumsRoute extends _i39.PageRouteInfo<void> {
const StatsAlbumsRoute({List<_i39.PageRouteInfo>? children})
: super(
StatsAlbumsRoute.name,
initialChildren: children,
@ -766,7 +765,7 @@ class StatsAlbumsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'StatsAlbumsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i26.StatsAlbumsPage();
@ -776,8 +775,8 @@ class StatsAlbumsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i27.StatsArtistsPage]
class StatsArtistsRoute extends _i40.PageRouteInfo<void> {
const StatsArtistsRoute({List<_i40.PageRouteInfo>? children})
class StatsArtistsRoute extends _i39.PageRouteInfo<void> {
const StatsArtistsRoute({List<_i39.PageRouteInfo>? children})
: super(
StatsArtistsRoute.name,
initialChildren: children,
@ -785,7 +784,7 @@ class StatsArtistsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'StatsArtistsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i27.StatsArtistsPage();
@ -795,8 +794,8 @@ class StatsArtistsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i28.StatsMinutesPage]
class StatsMinutesRoute extends _i40.PageRouteInfo<void> {
const StatsMinutesRoute({List<_i40.PageRouteInfo>? children})
class StatsMinutesRoute extends _i39.PageRouteInfo<void> {
const StatsMinutesRoute({List<_i39.PageRouteInfo>? children})
: super(
StatsMinutesRoute.name,
initialChildren: children,
@ -804,7 +803,7 @@ class StatsMinutesRoute extends _i40.PageRouteInfo<void> {
static const String name = 'StatsMinutesRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i28.StatsMinutesPage();
@ -814,8 +813,8 @@ class StatsMinutesRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i29.StatsPage]
class StatsRoute extends _i40.PageRouteInfo<void> {
const StatsRoute({List<_i40.PageRouteInfo>? children})
class StatsRoute extends _i39.PageRouteInfo<void> {
const StatsRoute({List<_i39.PageRouteInfo>? children})
: super(
StatsRoute.name,
initialChildren: children,
@ -823,7 +822,7 @@ class StatsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'StatsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i29.StatsPage();
@ -833,8 +832,8 @@ class StatsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i30.StatsPlaylistsPage]
class StatsPlaylistsRoute extends _i40.PageRouteInfo<void> {
const StatsPlaylistsRoute({List<_i40.PageRouteInfo>? children})
class StatsPlaylistsRoute extends _i39.PageRouteInfo<void> {
const StatsPlaylistsRoute({List<_i39.PageRouteInfo>? children})
: super(
StatsPlaylistsRoute.name,
initialChildren: children,
@ -842,7 +841,7 @@ class StatsPlaylistsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'StatsPlaylistsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i30.StatsPlaylistsPage();
@ -852,8 +851,8 @@ class StatsPlaylistsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i31.StatsStreamFeesPage]
class StatsStreamFeesRoute extends _i40.PageRouteInfo<void> {
const StatsStreamFeesRoute({List<_i40.PageRouteInfo>? children})
class StatsStreamFeesRoute extends _i39.PageRouteInfo<void> {
const StatsStreamFeesRoute({List<_i39.PageRouteInfo>? children})
: super(
StatsStreamFeesRoute.name,
initialChildren: children,
@ -861,7 +860,7 @@ class StatsStreamFeesRoute extends _i40.PageRouteInfo<void> {
static const String name = 'StatsStreamFeesRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i31.StatsStreamFeesPage();
@ -871,8 +870,8 @@ class StatsStreamFeesRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i32.StatsStreamsPage]
class StatsStreamsRoute extends _i40.PageRouteInfo<void> {
const StatsStreamsRoute({List<_i40.PageRouteInfo>? children})
class StatsStreamsRoute extends _i39.PageRouteInfo<void> {
const StatsStreamsRoute({List<_i39.PageRouteInfo>? children})
: super(
StatsStreamsRoute.name,
initialChildren: children,
@ -880,7 +879,7 @@ class StatsStreamsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'StatsStreamsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i32.StatsStreamsPage();
@ -890,11 +889,11 @@ class StatsStreamsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i33.TrackPage]
class TrackRoute extends _i40.PageRouteInfo<TrackRouteArgs> {
class TrackRoute extends _i39.PageRouteInfo<TrackRouteArgs> {
TrackRoute({
_i43.Key? key,
_i42.Key? key,
required String trackId,
List<_i40.PageRouteInfo>? children,
List<_i39.PageRouteInfo>? children,
}) : super(
TrackRoute.name,
args: TrackRouteArgs(
@ -907,7 +906,7 @@ class TrackRoute extends _i40.PageRouteInfo<TrackRouteArgs> {
static const String name = 'TrackRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
final pathParams = data.inheritedPathParams;
@ -927,7 +926,7 @@ class TrackRouteArgs {
required this.trackId,
});
final _i43.Key? key;
final _i42.Key? key;
final String trackId;
@ -939,8 +938,8 @@ class TrackRouteArgs {
/// generated route for
/// [_i34.UserAlbumsPage]
class UserAlbumsRoute extends _i40.PageRouteInfo<void> {
const UserAlbumsRoute({List<_i40.PageRouteInfo>? children})
class UserAlbumsRoute extends _i39.PageRouteInfo<void> {
const UserAlbumsRoute({List<_i39.PageRouteInfo>? children})
: super(
UserAlbumsRoute.name,
initialChildren: children,
@ -948,7 +947,7 @@ class UserAlbumsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'UserAlbumsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i34.UserAlbumsPage();
@ -958,8 +957,8 @@ class UserAlbumsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i35.UserArtistsPage]
class UserArtistsRoute extends _i40.PageRouteInfo<void> {
const UserArtistsRoute({List<_i40.PageRouteInfo>? children})
class UserArtistsRoute extends _i39.PageRouteInfo<void> {
const UserArtistsRoute({List<_i39.PageRouteInfo>? children})
: super(
UserArtistsRoute.name,
initialChildren: children,
@ -967,7 +966,7 @@ class UserArtistsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'UserArtistsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i35.UserArtistsPage();
@ -977,8 +976,8 @@ class UserArtistsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i36.UserDownloadsPage]
class UserDownloadsRoute extends _i40.PageRouteInfo<void> {
const UserDownloadsRoute({List<_i40.PageRouteInfo>? children})
class UserDownloadsRoute extends _i39.PageRouteInfo<void> {
const UserDownloadsRoute({List<_i39.PageRouteInfo>? children})
: super(
UserDownloadsRoute.name,
initialChildren: children,
@ -986,7 +985,7 @@ class UserDownloadsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'UserDownloadsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i36.UserDownloadsPage();
@ -996,8 +995,8 @@ class UserDownloadsRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i37.UserLocalLibraryPage]
class UserLocalLibraryRoute extends _i40.PageRouteInfo<void> {
const UserLocalLibraryRoute({List<_i40.PageRouteInfo>? children})
class UserLocalLibraryRoute extends _i39.PageRouteInfo<void> {
const UserLocalLibraryRoute({List<_i39.PageRouteInfo>? children})
: super(
UserLocalLibraryRoute.name,
initialChildren: children,
@ -1005,7 +1004,7 @@ class UserLocalLibraryRoute extends _i40.PageRouteInfo<void> {
static const String name = 'UserLocalLibraryRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i37.UserLocalLibraryPage();
@ -1015,8 +1014,8 @@ class UserLocalLibraryRoute extends _i40.PageRouteInfo<void> {
/// generated route for
/// [_i38.UserPlaylistsPage]
class UserPlaylistsRoute extends _i40.PageRouteInfo<void> {
const UserPlaylistsRoute({List<_i40.PageRouteInfo>? children})
class UserPlaylistsRoute extends _i39.PageRouteInfo<void> {
const UserPlaylistsRoute({List<_i39.PageRouteInfo>? children})
: super(
UserPlaylistsRoute.name,
initialChildren: children,
@ -1024,29 +1023,10 @@ class UserPlaylistsRoute extends _i40.PageRouteInfo<void> {
static const String name = 'UserPlaylistsRoute';
static _i40.PageInfo page = _i40.PageInfo(
static _i39.PageInfo page = _i39.PageInfo(
name,
builder: (data) {
return const _i38.UserPlaylistsPage();
},
);
}
/// generated route for
/// [_i39.WebViewLoginPage]
class WebViewLoginRoute extends _i40.PageRouteInfo<void> {
const WebViewLoginRoute({List<_i40.PageRouteInfo>? children})
: super(
WebViewLoginRoute.name,
initialChildren: children,
);
static const String name = 'WebViewLoginRoute';
static _i40.PageInfo page = _i40.PageInfo(
name,
builder: (data) {
return const _i39.WebViewLoginPage();
},
);
}

View File

@ -5,8 +5,8 @@ import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/utils/platform.dart';
class AnonymousFallback extends ConsumerWidget {
@ -18,13 +18,13 @@ class AnonymousFallback extends ConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final isLoggedIn = ref.watch(authenticationProvider);
final isLoggedIn = ref.watch(metadataPluginAuthenticatedProvider);
if (isLoggedIn.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (isLoggedIn.asData?.value != null && child != null) return child!;
if (isLoggedIn.asData?.value == true && child != null) return child!;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,

View File

@ -4,7 +4,7 @@ import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:spotube/components/heart_button/use_track_toggle_like.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/metadata/metadata.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/metadata_plugin/library/tracks.dart';
import 'package:spotube/provider/metadata_plugin/user.dart';
@ -29,9 +29,9 @@ class HeartButton extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final auth = ref.watch(authenticationProvider);
final authenticated = ref.watch(metadataPluginAuthenticatedProvider);
if (auth.asData?.value == null) return const SizedBox.shrink();
if (authenticated.asData?.value != true) return const SizedBox.shrink();
return Tooltip(
tooltip: TooltipContainer(child: Text(tooltip ?? "")).call,

View File

@ -226,6 +226,7 @@ class TrackPresentationTopSection extends HookConsumerWidget {
.imageProvider(
options.ownerImage!,
),
size: 20 * scale,
)
: null,
child: Text(

View File

@ -22,11 +22,11 @@ import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/database/database.dart';
import 'package:spotube/models/metadata/metadata.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/blacklist_provider.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/provider/local_tracks/local_tracks_provider.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/metadata_plugin/library/playlists.dart';
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
import 'package:spotube/provider/metadata_plugin/tracks/playlist.dart';
@ -181,7 +181,7 @@ class TrackOptions extends HookConsumerWidget {
final playlist = ref.watch(audioPlayerProvider);
final playback = ref.watch(audioPlayerProvider.notifier);
final auth = ref.watch(authenticationProvider);
final authenticated = ref.watch(metadataPluginAuthenticatedProvider);
ref.watch(downloadManagerProvider);
final downloadManager = ref.watch(downloadManagerProvider.notifier);
final blacklist = ref.watch(blacklistProvider);
@ -430,7 +430,7 @@ class TrackOptions extends HookConsumerWidget {
: context.l10n.save_as_favorite,
),
),
if (auth.asData?.value != null && !isLocalTrack) ...[
if (authenticated.asData?.value == true && !isLocalTrack) ...[
AdaptiveMenuButton(
value: TrackOptionValue.startRadio,
leading: const Icon(SpotubeIcons.radio),
@ -442,7 +442,9 @@ class TrackOptions extends HookConsumerWidget {
child: Text(context.l10n.add_to_playlist),
),
],
if (userPlaylist && auth.asData?.value != null && !isLocalTrack)
if (userPlaylist &&
authenticated.asData?.value == true &&
!isLocalTrack)
AdaptiveMenuButton(
value: TrackOptionValue.removeFromPlaylist,
leading: const Icon(SpotubeIcons.removeFilled),

View File

@ -2,7 +2,6 @@ import 'package:spotube/provider/metadata_plugin/tracks/playlist.dart';
import 'package:spotube/services/logger/logger.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart';

View File

@ -3,8 +3,8 @@ import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/metadata/metadata.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/metadata_plugin/album/releases.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/metadata_plugin/utils/common.dart';
class HomeNewReleasesSection extends HookConsumerWidget {
@ -12,13 +12,13 @@ class HomeNewReleasesSection extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final auth = ref.watch(authenticationProvider);
final authenticated = ref.watch(metadataPluginAuthenticatedProvider);
final newReleases = ref.watch(metadataPluginAlbumReleasesProvider);
final newReleasesNotifier =
ref.read(metadataPluginAlbumReleasesProvider.notifier);
if (auth.asData?.value == null ||
if (authenticated.asData?.value != true ||
newReleases.isLoading ||
newReleases.asData?.value.items.isEmpty == true) {
return const SizedBox.shrink();

View File

@ -20,8 +20,8 @@ import 'package:spotube/components/image/universal_image.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/modules/root/spotube_navigation_bar.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/server/active_track_sources.dart';
import 'package:spotube/provider/volume_provider.dart';
import 'package:spotube/services/sourced_track/sources/youtube.dart';
@ -41,7 +41,7 @@ class PlayerView extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final auth = ref.watch(authenticationProvider);
final authenticated = ref.watch(metadataPluginAuthenticatedProvider);
final sourcedCurrentTrack = ref.watch(activeTrackSourcesProvider);
final currentActiveTrack =
ref.watch(audioPlayerProvider.select((s) => s.activeTrack));
@ -242,8 +242,9 @@ class PlayerView extends HookConsumerWidget {
},
),
),
if (auth.asData?.value != null) const SizedBox(width: 10),
if (auth.asData?.value != null)
if (authenticated.asData?.value == true)
const SizedBox(width: 10),
if (authenticated.asData?.value == true)
Expanded(
child: OutlineButton(
leading: const Icon(SpotubeIcons.music),

View File

@ -16,8 +16,9 @@ import 'package:spotube/components/heart_button/heart_button.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/extensions/duration.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/local_tracks/local_tracks_provider.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/sleep_timer_provider.dart';
class PlayerActions extends HookConsumerWidget {
@ -49,17 +50,17 @@ class PlayerActions extends HookConsumerWidget {
downloader,
]);
final localTracks = [] /* ref.watch(localTracksProvider).value */;
final auth = ref.watch(authenticationProvider);
final localTracks = ref.watch(localTracksProvider).value;
final authenticated = ref.watch(metadataPluginAuthenticatedProvider);
final sleepTimer = ref.watch(sleepTimerProvider);
final sleepTimerNotifier = ref.watch(sleepTimerProvider.notifier);
final isDownloaded = useMemoized(() {
return localTracks.any(
return localTracks?.values.expand((e) => e).any(
(element) =>
element.name == playlist.activeTrack?.name &&
element.album?.name == playlist.activeTrack?.album.name &&
element.artists?.asString() ==
element.album.name == playlist.activeTrack?.album.name &&
element.artists.asString() ==
playlist.activeTrack?.artists.asString(),
) ==
true;
@ -175,7 +176,7 @@ class PlayerActions extends HookConsumerWidget {
),
if (playlist.activeTrack != null &&
!isLocalTrack &&
auth.asData?.value != null)
authenticated.asData?.value == true)
TrackHeartButton(track: playlist.activeTrack!),
AdaptivePopSheetList<Duration>(
tooltip: context.l10n.sleep_timer,

View File

@ -10,8 +10,8 @@ import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/metadata/metadata.dart';
import 'package:spotube/modules/connect/connect_device.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/metadata_plugin/user.dart';
class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
@ -33,7 +33,7 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
placeholder: ImagePlaceholder.artist,
);
final auth = ref.watch(authenticationProvider);
final authenticated = ref.watch(metadataPluginAuthenticatedProvider);
if (mediaQuery.mdAndDown) {
return Column(
@ -91,7 +91,7 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (auth.asData?.value != null && data == null)
if (authenticated.asData?.value == true && data == null)
const CircularProgressIndicator()
else if (data != null)
Flexible(

View File

@ -47,7 +47,7 @@ class AlbumPage extends HookConsumerWidget {
title: album.name,
description:
"${context.l10n.released}${album.releaseDate}${album.artists.first.name}",
tracks: [],
tracks: tracks.asData?.value.items ?? [],
pagination: PaginationProps(
hasNextPage: tracks.asData?.value.hasMore ?? false,
isLoading: tracks.isLoading || tracks.isLoadingNextPage,

View File

@ -10,9 +10,9 @@ import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/database/database.dart';
import 'package:spotube/models/metadata/metadata.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/blacklist_provider.dart';
import 'package:spotube/provider/metadata_plugin/artist/artist.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/metadata_plugin/library/artists.dart';
import 'package:spotube/utils/primitive_utils.dart';
@ -28,7 +28,7 @@ class ArtistPageHeader extends HookConsumerWidget {
final theme = Theme.of(context);
final ThemeData(:typography) = theme;
final auth = ref.watch(authenticationProvider);
final authenticated = ref.watch(metadataPluginAuthenticatedProvider);
ref.watch(blacklistProvider);
final blacklistNotifier = ref.watch(blacklistProvider.notifier);
final isBlackListed = blacklistNotifier.containsArtist(artist.id);
@ -41,7 +41,7 @@ class ArtistPageHeader extends HookConsumerWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (auth.asData?.value != null)
if (authenticated.asData?.value == true)
Consumer(
builder: (context, ref, _) {
final isFollowingQuery = ref.watch(

View File

@ -6,7 +6,6 @@ import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/modules/getting_started/blur_card.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/pages/mobile_login/hooks/login_callback.dart';
import 'package:spotube/services/kv_store/kv_store.dart';
import 'package:url_launcher/url_launcher_string.dart';
@ -15,8 +14,6 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final onLogin = useLoginCallback(ref);
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
@ -117,31 +114,6 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget {
},
child: Text(context.l10n.browse_anonymously),
),
const Gap(16),
Button.primary(
leading: const Icon(SpotubeIcons.spotify),
style: ButtonVariance.primary.copyWith(
decoration: (context, states, value) {
if (states.isNotEmpty) {
return ButtonVariance.primary
.decoration(context, states);
}
return BoxDecoration(
color: const Color(0xff1db954),
borderRadius: BorderRadius.circular(8),
);
},
),
onPressed: () async {
await KVStoreService.setDoneGettingStarted(true);
await onLogin();
},
child: Text(
context.l10n.connect_with_spotify,
style: const TextStyle(color: Colors.white),
),
),
],
),
),

View File

@ -14,7 +14,6 @@ import 'package:spotube/modules/album/album_card.dart';
import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart';
import 'package:spotube/components/fallbacks/anonymous_fallback.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/metadata_plugin/library/albums.dart';
import 'package:auto_route/auto_route.dart';

View File

@ -40,7 +40,7 @@ class UserPlaylistsPage extends HookConsumerWidget {
() => me.asData?.value == null
? null
: SpotubeSimplePlaylistObject(
id: "liked-tracks",
id: "user-liked-tracks",
name: context.l10n.liked_tracks,
description: context.l10n.liked_tracks_description,
externalUri: "",

View File

@ -1,81 +0,0 @@
import 'dart:io';
import 'package:auto_route/auto_route.dart';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart' hide join;
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/pages/mobile_login/no_webview_runtime_dialog.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/utils/platform.dart';
Future<void> Function() useLoginCallback(WidgetRef ref) {
final context = useContext();
final theme = Theme.of(context);
final authNotifier = ref.read(authenticationProvider.notifier);
return useCallback(() async {
if (kIsMobile || kIsMacOS) {
context.navigateTo(const WebViewLoginRoute());
return;
}
try {
final exp = RegExp(r"https:\/\/accounts.spotify.com\/.+\/status");
final applicationSupportDir = await getApplicationSupportDirectory();
final userDataFolder = Directory(
join(applicationSupportDir.path, "webview_window_Webview2"),
);
if (!await userDataFolder.exists()) {
await userDataFolder.create();
}
final webview = await WebviewWindow.create(
configuration: CreateConfiguration(
title: "Spotify Login",
titleBarTopPadding: kIsMacOS ? 20 : 0,
windowHeight: 720,
windowWidth: 1280,
userDataFolderWindows: userDataFolder.path,
),
);
webview
..setBrightness(theme.colorScheme.brightness)
..launch("https://accounts.spotify.com/")
..setOnUrlRequestCallback((url) {
if (exp.hasMatch(url)) {
webview.getAllCookies().then((cookies) async {
final cookieHeader =
"sp_dc=${cookies.firstWhere((element) => element.name.contains("sp_dc")).value.replaceAll("\u0000", "")}";
await authNotifier.login(cookieHeader);
webview.close();
if (context.mounted) {
context.navigateTo(const HomeRoute());
}
});
}
return true;
});
} on PlatformException catch (_) {
if (!await WebviewWindow.isWebviewAvailable()) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showDialog(
context: context,
builder: (context) {
return const NoWebviewRuntimeDialog();
},
);
});
}
}
}, [authNotifier, theme, context.navigateTo]);
}

View File

@ -1,80 +0,0 @@
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/components/button/back_button.dart';
import 'package:spotube/components/titlebar/titlebar.dart';
import 'package:spotube/provider/authentication/authentication.dart';
import 'package:spotube/utils/platform.dart';
import 'package:auto_route/auto_route.dart';
@RoutePage()
class WebViewLoginPage extends HookConsumerWidget {
static const name = "login";
const WebViewLoginPage({super.key});
@override
Widget build(BuildContext context, ref) {
final authenticationNotifier = ref.watch(authenticationProvider.notifier);
if (kIsDesktop) {
const Scaffold(
child: Center(
child: Text('This feature is not available on desktop'),
),
);
}
return SafeArea(
bottom: false,
child: Scaffold(
headers: const [
TitleBar(
leading: [BackButton(color: Colors.white)],
backgroundColor: Colors.transparent,
),
],
floatingHeader: true,
child: InAppWebView(
initialSettings: InAppWebViewSettings(
userAgent:
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 safari/537.36",
),
initialUrlRequest: URLRequest(
url: WebUri("https://accounts.spotify.com/"),
),
onPermissionRequest: (controller, permissionRequest) async {
return PermissionResponse(
resources: permissionRequest.resources,
action: PermissionResponseAction.GRANT,
);
},
onLoadStop: (controller, action) async {
if (action == null) return;
String url = action.toString();
if (url.endsWith("/")) {
url = url.substring(0, url.length - 1);
}
final exp = RegExp(r"https:\/\/accounts.spotify.com\/.+\/status");
if (exp.hasMatch(url)) {
final cookies =
await CookieManager.instance().getCookies(url: action);
final cookieHeader =
"sp_dc=${cookies.firstWhere((element) => element.name == "sp_dc").value}";
await authenticationNotifier.login(cookieHeader);
if (context.mounted) {
// ignore: use_build_context_synchronously
context.navigateTo(const HomeRoute());
}
}
},
),
),
);
}
}

View File

@ -1,57 +0,0 @@
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:spotube/extensions/context.dart';
import 'package:url_launcher/url_launcher_string.dart';
class NoWebviewRuntimeDialog extends StatelessWidget {
const NoWebviewRuntimeDialog({super.key});
@override
Widget build(BuildContext context) {
final ThemeData(:platform) = Theme.of(context);
return AlertDialog(
title: Text(context.l10n.webview_not_found),
content: Text(context.l10n.webview_not_found_description),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(context.l10n.cancel),
),
Button.primary(
onPressed: () async {
final url = switch (platform) {
TargetPlatform.windows =>
'https://developer.microsoft.com/en-us/microsoft-edge/webview2',
TargetPlatform.macOS => 'https://www.apple.com/safari/',
TargetPlatform.linux =>
'https://webkitgtk.org/reference/webkit2gtk/stable/',
_ => "",
};
if (url.isEmpty) {
showToast(
context: context,
builder: (context, overlay) {
return const SurfaceCard(
child: Basic(
title: Text('Unsupported platform'),
),
);
},
);
}
await launchUrlString(url);
},
child: Text(switch (platform) {
TargetPlatform.windows => 'Download Edge WebView2',
TargetPlatform.macOS => 'Download Safari',
TargetPlatform.linux => 'Download Webkit2Gtk',
_ => 'Download Webview',
}),
),
],
);
}
}

View File

@ -17,6 +17,7 @@ import 'package:spotube/hooks/controllers/use_shadcn_text_editing_controller.dar
import 'package:spotube/pages/search/sections/albums.dart';
import 'package:spotube/pages/search/sections/artists.dart';
import 'package:spotube/pages/search/sections/playlists.dart';
import 'package:spotube/pages/search/sections/tracks.dart';
import 'package:spotube/provider/metadata_plugin/auth.dart';
import 'package:spotube/provider/metadata_plugin/search/all.dart';
import 'package:spotube/services/kv_store/kv_store.dart';
@ -227,7 +228,7 @@ class SearchPage extends HookConsumerWidget {
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// SearchTracksSection(),
SearchTracksSection(),
SearchPlaylistsSection(),
Gap(20),
SearchArtistsSection(),

View File

@ -1,309 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:collection/collection.dart';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:dio/dio.dart';
import 'package:dio_http2_adapter/dio_http2_adapter.dart';
import 'package:drift/drift.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'
hide X509Certificate;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/routes.dart';
import 'package:spotube/components/dialogs/prompt_dialog.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/database/database.dart';
import 'package:spotube/provider/database/database.dart';
import 'package:spotube/services/logger/logger.dart';
import 'package:spotube/utils/platform.dart';
import 'package:otp_util/otp_util.dart';
// ignore: implementation_imports
import 'package:otp_util/src/utils/generic_util.dart';
import 'package:spotube/utils/service_utils.dart';
extension ExpirationAuthenticationTableData on AuthenticationTableData {
bool get isExpired => DateTime.now().isAfter(expiration);
String? getCookie(String key) => cookie.value
.split("; ")
.firstWhereOrNull((c) => c.trim().startsWith("$key="))
?.trim()
.split("=")
.last
.replaceAll(";", "");
}
class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
static final Dio dio = () {
final dio = Dio()
..httpClientAdapter = Http2Adapter(
ConnectionManager(
idleTimeout: const Duration(seconds: 10),
onClientCreate: (uri, clientSettings) {
clientSettings.onBadCertificate = (X509Certificate cert) {
return uri.host.endsWith("spotify.com");
};
},
),
);
return dio;
}();
@override
build() async {
final database = ref.watch(databaseProvider);
final data = await (database.select(database.authenticationTable)
..where((s) => s.id.equals(0)))
.getSingleOrNull();
Timer? refreshTimer;
listenSelf((prevData, newData) async {
if (newData.asData?.value == null) return;
if (newData.asData!.value!.isExpired) {
await refreshCredentials();
}
// set the refresh timer
refreshTimer?.cancel();
refreshTimer = Timer(
newData.asData!.value!.expiration.difference(DateTime.now()),
() => refreshCredentials(),
);
});
final subscription =
database.select(database.authenticationTable).watch().listen(
(event) {
state = AsyncData(event.isEmpty ? null : event.first);
},
);
ref.onDispose(() {
subscription.cancel();
refreshTimer?.cancel();
});
return data;
}
Future<void> refreshCredentials() async {
final database = ref.read(databaseProvider);
final refreshedCredentials =
await credentialsFromCookie(state.asData!.value!.cookie.value);
await database
.update(database.authenticationTable)
.replace(refreshedCredentials);
}
Future<void> login(String cookie) async {
final database = ref.read(databaseProvider);
final refreshedCredentials = await credentialsFromCookie(cookie);
await database
.into(database.authenticationTable)
.insert(refreshedCredentials, mode: InsertMode.replace);
}
String base32FromBytes(Uint8List e, String secretSauce) {
var t = 0;
var n = 0;
var r = "";
for (int i = 0; i < e.length; i++) {
n = n << 8 | e[i];
t += 8;
while (t >= 5) {
r += secretSauce[n >>> t - 5 & 31];
t -= 5;
}
}
if (t > 0) {
r += secretSauce[n << 5 - t & 31];
}
return r;
}
Uint8List cleanBuffer(String e) {
e = e.replaceAll(" ", "");
final t = List.filled(e.length ~/ 2, 0);
final n = Uint8List.fromList(t);
for (int r = 0; r < e.length; r += 2) {
n[r ~/ 2] = int.parse(e.substring(r, r + 2), radix: 16);
}
return n;
}
Future<String> generateTotp() async {
const secretSauce = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
final secretCipherBytes = const [
12,
56,
76,
33,
88,
44,
88,
33,
78,
78,
11,
66,
22,
22,
55,
69,
54
].mapIndexed((t, e) => e ^ t % 33 + 9).toList();
final secretBytes = cleanBuffer(
utf8
.encode(secretCipherBytes.join(""))
.map((e) => e.toRadixString(16))
.join(),
);
final secret = base32FromBytes(secretBytes, secretSauce);
final res = await dio.get(
"https://open.spotify.com/server-time",
options: Options(
headers: {
"Host": "open.spotify.com",
"User-Agent": ServiceUtils.randomUserAgent(
kIsDesktop ? UserAgentDevice.desktop : UserAgentDevice.mobile,
),
"accept": "*/*",
},
),
);
final serverTimeSeconds = res.data["serverTime"] as int;
final totp = TOTP(
secret: secret,
algorithm: OTPAlgorithm.SHA1,
digits: 6,
interval: 30,
);
return totp.generateOTP(
input: Util.timeFormat(
time: DateTime.fromMillisecondsSinceEpoch(serverTimeSeconds * 1000),
interval: 30,
),
);
}
Future<Response> getToken({
required String totp,
required int timestamp,
String mode = "transport",
String? spDc,
}) async {
assert(mode == "transport" || mode == "init");
final accessTokenUrl = Uri.parse(
"https://open.spotify.com/get_access_token?reason=$mode&productType=web-player"
"&totp=$totp&totpVer=5&ts=$timestamp",
);
final res = await dio.getUri(
accessTokenUrl,
options: Options(
headers: {
"Cookie": spDc ?? "",
"User-Agent": ServiceUtils.randomUserAgent(
kIsDesktop ? UserAgentDevice.desktop : UserAgentDevice.mobile,
),
},
),
);
return res;
}
Future<AuthenticationTableCompanion> credentialsFromCookie(
String cookie,
) async {
try {
final spDc = cookie
.split("; ")
.firstWhereOrNull((c) => c.trim().startsWith("sp_dc="))
?.trim();
final totp = await generateTotp();
final timestamp = (DateTime.now().millisecondsSinceEpoch / 1000).floor();
var res = await getToken(
totp: totp,
timestamp: timestamp,
spDc: spDc,
mode: "transport",
);
if ((res.data["accessToken"]?.length ?? 0) != 374) {
res = await getToken(
totp: totp,
timestamp: timestamp,
spDc: spDc,
mode: "init",
);
}
final body = res.data as Map<String, dynamic>;
if (body["accessToken"] == null) {
AppLogger.reportError(
"The access token is only ${body["accessToken"]?.length} characters long instead of 374\n"
"Your authentication probably doesn't work",
StackTrace.current,
);
}
return AuthenticationTableCompanion.insert(
id: const Value(0),
cookie: DecryptedText("${res.headers["set-cookie"]?.join(";")}; $spDc"),
accessToken: DecryptedText(body['accessToken']),
expiration: DateTime.fromMillisecondsSinceEpoch(
body['accessTokenExpirationTimestampMs'],
),
);
} catch (e) {
if (rootNavigatorKey.currentContext != null) {
showPromptDialog(
context: rootNavigatorKey.currentContext!,
title: rootNavigatorKey.currentContext!.l10n
.error("Authentication Failure"),
message: e.toString(),
cancelText: null,
);
}
rethrow;
}
}
Future<void> logout() async {
state = const AsyncData(null);
final database = ref.read(databaseProvider);
await (database.delete(database.authenticationTable)
..where((s) => s.id.equals(0)))
.go();
if (kIsMobile) {
WebStorageManager.instance().deleteAllData();
CookieManager.instance().deleteAllCookies();
}
if (kIsDesktop) {
await WebviewWindow.clearAll();
}
}
}
final authenticationProvider =
AsyncNotifierProvider<AuthenticationNotifier, AuthenticationTableData?>(
() => AuthenticationNotifier(),
);

View File

@ -1,7 +1,6 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/models/metadata/metadata.dart';
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
import 'package:spotube/provider/metadata_plugin/user.dart';
import 'package:spotube/provider/metadata_plugin/utils/common.dart';
import 'package:spotube/provider/metadata_plugin/utils/paginated.dart';
@ -11,17 +10,7 @@ class MetadataPluginSavedTracksNotifier
@override
fetch(offset, limit) async {
final user = await ref.read(metadataPluginUserProvider.future);
if (user == null) {
throw Exception(
'User not found \n'
'You need to be logged in to access saved tracks.',
);
}
final tracks = await (await metadataPlugin).album.tracks(
user.id,
final tracks = await (await metadataPlugin).user.savedTracks(
offset: offset,
limit: limit,
);