diff --git a/lib/components/Artist/ArtistAlbumView.dart b/lib/components/Artist/ArtistAlbumView.dart index b90a78a6..b65c67eb 100644 --- a/lib/components/Artist/ArtistAlbumView.dart +++ b/lib/components/Artist/ArtistAlbumView.dart @@ -4,6 +4,7 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/Album/AlbumCard.dart'; import 'package:spotube/components/Shared/PageWindowTitleBar.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/SpotifyDI.dart'; class ArtistAlbumView extends ConsumerStatefulWidget { @@ -23,6 +24,8 @@ class _ArtistAlbumViewState extends ConsumerState { final PagingController _pagingController = PagingController(firstPageKey: 0); + final logger = createLogger(ArtistAlbumView); + @override void initState() { super.initState(); @@ -51,8 +54,7 @@ class _ArtistAlbumViewState extends ConsumerState { _pagingController.appendPage(items, albums.nextOffset); } } catch (e, stack) { - print("[ArtistAlbumView._fetchPage] $e"); - print(stack); + logger.e(e, null, stack); _pagingController.error = e; } } diff --git a/lib/components/Category/CategoryCard.dart b/lib/components/Category/CategoryCard.dart index fec5085b..19571664 100644 --- a/lib/components/Category/CategoryCard.dart +++ b/lib/components/Category/CategoryCard.dart @@ -5,17 +5,20 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/Playlist/PlaylistCard.dart'; import 'package:spotube/hooks/usePagingController.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/SpotifyDI.dart'; class CategoryCard extends HookWidget { final Category category; final Iterable? playlists; - const CategoryCard( + CategoryCard( this.category, { Key? key, this.playlists, }) : super(key: key); + final logger = createLogger(CategoryCard); + @override Widget build(BuildContext context) { return Column( @@ -68,9 +71,7 @@ class CategoryCard extends HookWidget { if (!_error.value) _error.value = true; pagingController.error = e; } - print( - "[CategoryCard.pagingController.addPageRequestListener] $e"); - print(stack); + logger.e("pagingController.addPageRequestListener", e, stack); } } diff --git a/lib/components/Home/Home.dart b/lib/components/Home/Home.dart index 4395daa4..97101a6e 100644 --- a/lib/components/Home/Home.dart +++ b/lib/components/Home/Home.dart @@ -23,6 +23,7 @@ import 'package:spotube/hooks/useHotKeys.dart'; import 'package:spotube/hooks/usePagingController.dart'; import 'package:spotube/hooks/useSharedPreferences.dart'; import 'package:spotube/models/LocalStorageKeys.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/models/generated_secrets.dart'; import 'package:spotube/provider/Auth.dart'; import 'package:spotube/provider/SpotifyDI.dart'; @@ -38,7 +39,8 @@ List spotifyScopes = [ ]; class Home extends HookConsumerWidget { - const Home({Key? key}) : super(key: key); + Home({Key? key}) : super(key: key); + final logger = createLogger(Home); @override Widget build(BuildContext context, ref) { @@ -82,8 +84,7 @@ class Home extends HookConsumerWidget { } } catch (e, stack) { pagingController.error = e; - print("[Home.pagingController.addPageRequestListener] $e"); - print(stack); + logger.e("pagingController.addPageRequestListener", e, stack); } }, []); @@ -146,16 +147,14 @@ class Home extends HookConsumerWidget { clientSecret: clientSecret, ); } - print("[Home.useEffect.spotify.getCredentials]: $e"); - print(stack); + logger.e("useEffect.spotify.getCredentials", e, stack); }); } else { pagingController.addPageRequestListener(listener); pagingController.notifyPageRequestListeners(0); } } catch (e, stack) { - print("[Home.initState]: $e"); - print(stack); + logger.e("initState", e, stack); } return () { pagingController.removePageRequestListener(listener); @@ -218,7 +217,7 @@ class Home extends HookConsumerWidget { ), ), // player itself - const Player(), + Player(), SpotubeNavigationBar( selectedIndex: _selectedIndex.value, onSelectedIndexChanged: _onSelectedIndexChanged, diff --git a/lib/components/Library/UserArtists.dart b/lib/components/Library/UserArtists.dart index 17fae18e..dc6a55c7 100644 --- a/lib/components/Library/UserArtists.dart +++ b/lib/components/Library/UserArtists.dart @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/Artist/ArtistCard.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/SpotifyDI.dart'; class UserArtists extends ConsumerStatefulWidget { @@ -15,6 +16,7 @@ class UserArtists extends ConsumerStatefulWidget { class _UserArtistsState extends ConsumerState { final PagingController _pagingController = PagingController(firstPageKey: ""); + final logger = createLogger(UserArtists); @override void initState() { @@ -36,8 +38,7 @@ class _UserArtistsState extends ConsumerState { } } catch (e, stack) { _pagingController.error = e; - print("[UserArtists.pagingController]: $e"); - print(stack); + logger.e("pagingController", e, stack); } }); }); diff --git a/lib/components/Login.dart b/lib/components/Login.dart index 8ac03136..918c2e5a 100644 --- a/lib/components/Login.dart +++ b/lib/components/Login.dart @@ -8,11 +8,13 @@ import 'package:spotube/components/Shared/PageWindowTitleBar.dart'; import 'package:spotube/helpers/oauth-login.dart'; import 'package:spotube/hooks/useBreakpoints.dart'; import 'package:spotube/models/LocalStorageKeys.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/Auth.dart'; import 'package:spotube/provider/UserPreferences.dart'; class Login extends HookConsumerWidget { - const Login({Key? key}) : super(key: key); + Login({Key? key}) : super(key: key); + final log = createLogger(Login); @override Widget build(BuildContext context, ref) { @@ -37,7 +39,7 @@ class Login extends HookConsumerWidget { (value) => GoRouter.of(context).pop(), ); } catch (e) { - print("[Login.handleLogin] $e"); + log.e("[Login.handleLogin] $e"); } } diff --git a/lib/components/Player/Player.dart b/lib/components/Player/Player.dart index f3cf3ba5..6f94bf28 100644 --- a/lib/components/Player/Player.dart +++ b/lib/components/Player/Player.dart @@ -11,11 +11,14 @@ import 'package:spotube/components/Player/PlayerControls.dart'; import 'package:spotube/helpers/image-to-url-string.dart'; import 'package:spotube/hooks/useBreakpoints.dart'; import 'package:spotube/models/LocalStorageKeys.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/Playback.dart'; import 'package:flutter/material.dart'; class Player extends HookConsumerWidget { - const Player({Key? key}) : super(key: key); + Player({Key? key}) : super(key: key); + + final logger = createLogger(Player); @override Widget build(BuildContext context, ref) { Playback playback = ref.watch(playbackProvider); @@ -37,7 +40,9 @@ class Player extends HookConsumerWidget { /// [disposeAllPlayers] method which is throwing /// [UnimplementedException] in the [PlatformInterface] /// implementation - player.setAsset("assets/warmer.mp3"); + playback.audioSession + ?.setActive(true) + .then((_) => player.setAsset("assets/warmer.mp3")); return null; }, []); @@ -65,8 +70,7 @@ class Player extends HookConsumerWidget { entryRef.value = null; } catch (e, stack) { if (e is! AssertionError) { - print("[Player.useEffect.cleanup] $e"); - print(stack); + logger.e("useEffect.cleanup", e, stack); } } } @@ -107,7 +111,7 @@ class Player extends HookConsumerWidget { children: [ Expanded(child: PlayerTrackDetails(albumArt: albumArt)), // controls - const Expanded( + Expanded( flex: 3, child: PlayerControls(), ), @@ -133,8 +137,7 @@ class Player extends HookConsumerWidget { ); }); } catch (e, stack) { - print("[VolumeSlider.onChange()] $e"); - print(stack); + logger.e("onChange", e, stack); } }, ), diff --git a/lib/components/Player/PlayerControls.dart b/lib/components/Player/PlayerControls.dart index 376e1165..8b1c91b3 100644 --- a/lib/components/Player/PlayerControls.dart +++ b/lib/components/Player/PlayerControls.dart @@ -4,15 +4,18 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:just_audio/just_audio.dart'; import 'package:spotube/helpers/zero-pad-num-str.dart'; import 'package:spotube/hooks/playback.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/Playback.dart'; class PlayerControls extends HookConsumerWidget { final Color? iconColor; - const PlayerControls({ + PlayerControls({ this.iconColor, Key? key, }) : super(key: key); + final logger = createLogger(PlayerControls); + @override Widget build(BuildContext context, ref) { final Playback playback = ref.watch(playbackProvider); @@ -115,8 +118,7 @@ class PlayerControls extends HookConsumerWidget { _shuffled.value = false; } } catch (e, stack) { - print("[PlayerControls.onShuffle()] $e"); - print(stack); + logger.e("onShuffle", e, stack); } }), IconButton( @@ -150,8 +152,7 @@ class PlayerControls extends HookConsumerWidget { _shuffled.value = false; playback.reset(); } catch (e, stack) { - print("[PlayerControls.onStop()] $e"); - print(stack); + logger.e("onStop", e, stack); } } : null, diff --git a/lib/helpers/getLyrics.dart b/lib/helpers/getLyrics.dart index 8fc4867a..c571e673 100644 --- a/lib/helpers/getLyrics.dart +++ b/lib/helpers/getLyrics.dart @@ -3,8 +3,11 @@ import 'package:html/parser.dart' as parser; import 'package:html/dom.dart'; import 'package:http/http.dart' as http; import 'package:spotube/helpers/get-random-element.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/models/generated_secrets.dart'; +final logger = createLogger("GetLyrics"); + String getTitle(String title, String artist) { return "$title $artist" .toLowerCase() @@ -40,8 +43,7 @@ Future extractLyrics(Uri url) async { return lyrics; } catch (e, stack) { - print("[extractLyrics] $e"); - print(stack); + logger.e("extractLyrics", e, stack); rethrow; } } @@ -78,8 +80,7 @@ Future searchSong( }).toList(); return results; } catch (e, stack) { - print("[searchSong] $e"); - print(stack); + logger.e("searchSong", e, stack); rethrow; } } @@ -103,8 +104,7 @@ Future getLyrics( String? lyrics = await extractLyrics(Uri.parse(results.first["url"])); return lyrics; } catch (e, stack) { - print("[getLyrics] $e"); - print(stack); + logger.e("getLyrics", e, stack); return null; } } diff --git a/lib/helpers/oauth-login.dart b/lib/helpers/oauth-login.dart index 32229297..ea78ab89 100644 --- a/lib/helpers/oauth-login.dart +++ b/lib/helpers/oauth-login.dart @@ -3,9 +3,11 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/components/Home/Home.dart'; import 'package:spotube/helpers/server_ipc.dart'; import 'package:spotube/models/LocalStorageKeys.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/Auth.dart'; const redirectUri = "http://localhost:4304/auth/spotify/callback"; +final logger = createLogger("OAuthLogin"); Future oauthLogin(Auth auth, {required String clientId, required String clientSecret}) async { @@ -57,8 +59,7 @@ Future oauthLogin(Auth auth, isLoggedIn: true, ); } catch (e, stack) { - print("[oauthLogin()] $e"); - print(stack); + logger.e("oauthLogin", e, stack); rethrow; } } diff --git a/lib/helpers/server_ipc.dart b/lib/helpers/server_ipc.dart index 42b291ee..f455c28e 100644 --- a/lib/helpers/server_ipc.dart +++ b/lib/helpers/server_ipc.dart @@ -1,15 +1,18 @@ import 'dart:io'; +import 'package:spotube/models/Logger.dart'; import 'package:url_launcher/url_launcher.dart'; +final logger = createLogger("ServerIPC"); + Future connectIpc(String authUri, String redirectUri) async { try { - print("[Launching]: $authUri"); + logger.i("[Launching]: $authUri"); await launch(authUri); HttpServer server = await HttpServer.bind(InternetAddress.loopbackIPv4, 4304); - print("Server started"); + logger.i("Server started"); await for (HttpRequest request in server) { if (request.uri.path == "/auth/spotify/callback" && @@ -30,9 +33,8 @@ Future connectIpc(String authUri, String redirectUri) async { } } } - } catch (error, stack) { - print("[connectIpc]: $error"); - print(stack); + } catch (e, stack) { + logger.e("connectIpc", e, stack); rethrow; } } diff --git a/lib/hooks/playback.dart b/lib/hooks/playback.dart index f113d315..a37bb245 100644 --- a/lib/hooks/playback.dart +++ b/lib/hooks/playback.dart @@ -1,5 +1,8 @@ +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/Playback.dart'; +final logger = createLogger("PlaybackHook"); + Future Function() useNextTrack(Playback playback) { return () async { try { @@ -7,8 +10,7 @@ Future Function() useNextTrack(Playback playback) { await playback.player.seek(Duration.zero); playback.movePlaylistPositionBy(1); } catch (e, stack) { - print("[PlayerControls.onNext()] $e"); - print(stack); + logger.e("useNextTrack", e, stack); } }; } @@ -20,8 +22,7 @@ Future Function() usePreviousTrack(Playback playback) { await playback.player.seek(Duration.zero); playback.movePlaylistPositionBy(-1); } catch (e, stack) { - print("[PlayerControls.onPrevious()] $e"); - print(stack); + logger.e("onPrevious", e, stack); } }; } @@ -34,8 +35,7 @@ Future Function([dynamic]) useTogglePlayPause(Playback playback) { ? await playback.player.pause() : await playback.player.play(); } catch (e, stack) { - print("[PlayPauseShortcut] $e"); - print(stack); + logger.e("useTogglePlayPause", e, stack); } }; } diff --git a/lib/main.dart b/lib/main.dart index e51be40e..35aa3bdc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:hotkey_manager/hotkey_manager.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotube/models/GoRouteDeclarations.dart'; import 'package:spotube/models/LocalStorageKeys.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/AudioPlayer.dart'; import 'package:spotube/provider/ThemeProvider.dart'; import 'package:spotube/provider/YouTube.dart'; @@ -38,6 +39,7 @@ void main() async { class MyApp extends HookConsumerWidget { final GoRouter _router = createGoRouter(); + final logger = createLogger(MyApp); MyApp({Key? key}) : super(key: key); @override diff --git a/lib/models/GoRouteDeclarations.dart b/lib/models/GoRouteDeclarations.dart index 022e109a..e734b7bd 100644 --- a/lib/models/GoRouteDeclarations.dart +++ b/lib/models/GoRouteDeclarations.dart @@ -15,12 +15,12 @@ GoRouter createGoRouter() => GoRouter( routes: [ GoRoute( path: "/", - builder: (context, state) => const Home(), + builder: (context, state) => Home(), ), GoRoute( path: "/login", pageBuilder: (context, state) => SpotubePage( - child: const Login(), + child: Login(), ), ), GoRoute( diff --git a/lib/models/Logger.dart b/lib/models/Logger.dart new file mode 100644 index 00000000..cc9a5fab --- /dev/null +++ b/lib/models/Logger.dart @@ -0,0 +1,25 @@ +import 'dart:io'; + +import 'package:logger/logger.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:path/path.dart' as path; + +_SpotubeLogger createLogger(T owner) => + _SpotubeLogger(owner is String ? owner : owner.toString()); + +class _SpotubeLogger extends Logger { + String owner; + _SpotubeLogger(this.owner); + + @override + void log(Level level, message, [error, StackTrace? stackTrace]) { + getApplicationDocumentsDirectory().then((dir) async { + final file = File(path.join(dir.path, ".spotube_logs")); + if (level == Level.error) { + await file.writeAsString("[${DateTime.now()}]\n$message\n$stackTrace", + mode: FileMode.writeOnlyAppend); + } + }); + super.log(level, "[$owner] $message", error, stackTrace); + } +} diff --git a/lib/provider/Playback.dart b/lib/provider/Playback.dart index 27f9a468..2059127a 100644 --- a/lib/provider/Playback.dart +++ b/lib/provider/Playback.dart @@ -9,6 +9,7 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/helpers/artist-to-string.dart'; import 'package:spotube/helpers/image-to-url-string.dart'; import 'package:spotube/helpers/search-youtube.dart'; +import 'package:spotube/models/Logger.dart'; import 'package:spotube/provider/AudioPlayer.dart'; import 'package:spotube/provider/YouTube.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; @@ -47,6 +48,7 @@ class CurrentPlaylist { } class Playback extends ChangeNotifier { + final _logger = createLogger(Playback); CurrentPlaylist? _currentPlaylist; Track? _currentTrack; @@ -109,8 +111,7 @@ class Playback extends ChangeNotifier { movePlaylistPositionBy(1); } } catch (e, stack) { - print("[PrecessingStateStreamListener] $e"); - print(stack); + _logger.e("PrecessingStateStreamListener", e, stack); } }); @@ -126,6 +127,7 @@ class Playback extends ChangeNotifier { CurrentPlaylist? get currentPlaylist => _currentPlaylist; Track? get currentTrack => _currentTrack; bool get isPlaying => _isPlaying; + AudioSession? get audioSession => _audioSession; /// this duration field is almost static & changes occasionally /// @@ -258,8 +260,7 @@ class Playback extends ChangeNotifier { } } } catch (e, stack) { - print("[Playback.startPlaying] $e"); - print(stack); + _logger.e("startPlaying", e, stack); } } } diff --git a/lib/provider/UserPreferences.dart b/lib/provider/UserPreferences.dart index b9a70cf3..7d586873 100644 --- a/lib/provider/UserPreferences.dart +++ b/lib/provider/UserPreferences.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hotkey_manager/hotkey_manager.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotube/models/LocalStorageKeys.dart'; +import 'package:spotube/models/Logger.dart'; class UserPreferences extends ChangeNotifier { String geniusAccessToken; @@ -20,6 +21,8 @@ class UserPreferences extends ChangeNotifier { onInit(); } + final logger = createLogger(UserPreferences); + Future _getHotKeyFromLocalStorage( SharedPreferences preferences, String key) async { String? str = preferences.getString(key); @@ -68,8 +71,7 @@ class UserPreferences extends ChangeNotifier { ); notifyListeners(); } catch (e, stack) { - print("[UserPreferences.onInit]: $e"); - print(stack); + logger.e("onInit", e, stack); } } diff --git a/pubspec.lock b/pubspec.lock index 2f0cc03a..1b75402c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -373,6 +373,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + logger: + dependency: "direct main" + description: + name: logger + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" logging: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index da6bac66..ff4d9a40 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,7 @@ dependencies: palette_generator: ^0.3.3 audio_session: ^0.1.6+1 just_audio_background: ^0.0.1-beta.5 + logger: ^1.1.0 dev_dependencies: flutter_test: