From 7ef6ace46f55cb20848864f8ae9e1cd215c07ce2 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 12:25:41 +0400 Subject: [PATCH 01/16] optimized player functions --- lib/services/audio_handler.dart | 20 ++++++++------------ lib/services/audio_manager.dart | 28 +++++----------------------- 2 files changed, 13 insertions(+), 35 deletions(-) diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index a4cee8004..3525ebed0 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -143,22 +143,15 @@ class MyAudioHandler extends BaseAudioHandler { @override Future seek(Duration position) => audioPlayer!.seek(position); - @override - Future skipToQueueItem(int index) async { - late int ind; - if (index < 0 || index >= queue.value.length) return; - if (audioPlayer!.shuffleModeEnabled) { - ind = audioPlayer!.shuffleIndices![index]; - } - await audioPlayer!.seek(Duration.zero, index: ind); - } - @override Future skipToNext() async { if (activePlaylist.isEmpty) { await audioPlayer!.seekToNext(); } else { - await playNext(); + if (id + 1 <= activePlaylist.length) { + await playSong(activePlaylist[id + 1]); + id = id + 1; + } } } @@ -167,7 +160,10 @@ class MyAudioHandler extends BaseAudioHandler { if (activePlaylist.isEmpty) { await audioPlayer!.seekToPrevious(); } else { - await playPrevious(); + if (id - 1 >= 0) { + await playSong(activePlaylist[id - 1]); + id = id - 1; + } } } diff --git a/lib/services/audio_manager.dart b/lib/services/audio_manager.dart index 4fee6a2c2..15d60774a 100644 --- a/lib/services/audio_manager.dart +++ b/lib/services/audio_manager.dart @@ -157,33 +157,15 @@ Future enableBooster() async { await _loudnessEnhancer.setTargetGain(1); } -Future? play() => _audioHandler.play(); +Future play() => _audioHandler.play(); -Future? pause() => _audioHandler.pause(); +Future pause() => _audioHandler.pause(); -Future? stop() => _audioHandler.stop(); +Future stop() => _audioHandler.stop(); -Future playNext() async { - if (activePlaylist.isEmpty) { - await _audioHandler.skipToNext(); - } else { - if (id + 1 <= activePlaylist.length) { - await playSong(activePlaylist[id + 1]); - id = id + 1; - } - } -} +Future playNext() => _audioHandler.skipToNext(); -Future playPrevious() async { - if (activePlaylist.isEmpty) { - await _audioHandler.skipToPrevious(); - } else { - if (id - 1 >= 0) { - await playSong(activePlaylist[id - 1]); - id = id - 1; - } - } -} +Future playPrevious() => _audioHandler.skipToPrevious(); Future mute(bool muted) async { if (muted) { From 20e75a7069af2bd848b89ad48bdbd7d29287e1aa Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 12:57:29 +0400 Subject: [PATCH 02/16] changelog: updated dependencies song bar changed little bit --- lib/customWidgets/song_bar.dart | 8 ++++---- pubspec.lock | 14 +++++++------- pubspec.yaml | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/customWidgets/song_bar.dart b/lib/customWidgets/song_bar.dart index b9fba600c..c383a4867 100644 --- a/lib/customWidgets/song_bar.dart +++ b/lib/customWidgets/song_bar.dart @@ -29,10 +29,10 @@ class SongBar extends StatelessWidget { Navigator.pop(context); } }, - splashColor: accent, - hoverColor: accent, - focusColor: accent, - highlightColor: accent, + splashColor: accent.withOpacity(0.4), + hoverColor: accent.withOpacity(0.4), + focusColor: accent.withOpacity(0.4), + highlightColor: accent.withOpacity(0.4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/pubspec.lock b/pubspec.lock index b3ca7c644..b31511fc9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -140,7 +140,7 @@ packages: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.2" + version: "6.1.4" flutter: dependency: "direct main" description: flutter @@ -166,7 +166,7 @@ packages: name: flutter_downloader url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.3" flutter_launcher_icons: dependency: "direct dev" description: @@ -244,7 +244,7 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.4" + version: "0.13.5" http_parser: dependency: transitive description: @@ -377,7 +377,7 @@ packages: name: package_info_plus url: "https://pub.dartlang.org" source: hosted - version: "1.4.3" + version: "1.4.3+1" package_info_plus_linux: dependency: transitive description: @@ -433,7 +433,7 @@ packages: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.17" + version: "2.0.19" path_provider_ios: dependency: transitive description: @@ -468,7 +468,7 @@ packages: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.2" pedantic: dependency: transitive description: @@ -564,7 +564,7 @@ packages: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.3+1" sqflite_common: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d1f239ce9..a82fd27fd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,19 +32,19 @@ dependencies: cached_network_image: ^3.2.1 flutter: sdk: flutter - flutter_downloader: ^1.8.1 + flutter_downloader: ^1.8.3 flutter_localizations: sdk: flutter fluttertoast: ^8.0.9 get_it: ^7.2.0 hive: ^2.2.3 hive_flutter: ^1.1.0 - http: ^0.13.4 + http: ^0.13.5 intl: ^0.17.0 just_audio: ^0.9.28 material_design_icons_flutter: ^5.0.6996 on_audio_query: ^2.6.1 - package_info_plus: ^1.4.3 + package_info_plus: ^1.4.3+1 path_provider: ^2.0.11 permission_handler: ^10.0.0 youtube_explode_dart: ^1.12.0 From f8946569b1c59b1830b89218ebbae1b9dca3c506 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 13:15:26 +0400 Subject: [PATCH 03/16] improved get local songs function --- lib/API/musify.dart | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/API/musify.dart b/lib/API/musify.dart index e89d0cbac..9a875393d 100644 --- a/lib/API/musify.dart +++ b/lib/API/musify.dart @@ -277,16 +277,12 @@ Future getSongDetails(dynamic songIndex, dynamic songId) async { } Future> getLocalSongs() async { - // DEFAULT: - // SongSortType.TITLE, - // OrderType.ASC_OR_SMALLER, - // UriType.EXTERNAL, - if (localSongs.isEmpty) { - if (await Permission.storage.request().isGranted) { - localSongs = await _audioQuery.querySongs(uriType: UriType.EXTERNAL); - localSongs.addAll(await _audioQuery.querySongs( - path: await ExtStorageProvider.getExtStorage(dirName: 'Musify'))); - } + if (await Permission.storage.request().isGranted) { + localSongs = [ + ...await _audioQuery.querySongs(uriType: UriType.EXTERNAL), + ...await _audioQuery.querySongs( + path: await ExtStorageProvider.getExtStorage(dirName: 'Musify')) + ]; } return localSongs; From e03e494548d3f105bec3108fff5f22e1761b0d6d Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 13:26:19 +0400 Subject: [PATCH 04/16] changelog: improved code improved downloader function --- lib/API/musify.dart | 13 +++-- lib/customWidgets/song_bar.dart | 1 + lib/services/audio_manager.dart | 66 +----------------------- lib/services/download_manager.dart | 81 ++++++++++++++++++++++++++++++ lib/ui/player.dart | 1 + 5 files changed, 90 insertions(+), 72 deletions(-) create mode 100644 lib/services/download_manager.dart diff --git a/lib/API/musify.dart b/lib/API/musify.dart index 9a875393d..0a00db38a 100644 --- a/lib/API/musify.dart +++ b/lib/API/musify.dart @@ -253,14 +253,13 @@ Future getPlaylistInfoForWidget(dynamic id) async { return playlist; } -Future getSongUrl(dynamic songId) async { +Future getSong(dynamic songId, bool geturl) async { final manifest = await yt.videos.streamsClient.getManifest(songId); - return manifest.audioOnly.withHighestBitrate().url.toString(); -} - -Future getSongStream(dynamic songId) async { - final manifest = await yt.videos.streamsClient.getManifest(songId); - return manifest.audioOnly.withHighestBitrate(); + if (geturl) { + return manifest.audioOnly.withHighestBitrate().url.toString(); + } else { + return manifest.audioOnly.withHighestBitrate(); + } } Future getSongDetails(dynamic songIndex, dynamic songId) async { diff --git a/lib/customWidgets/song_bar.dart b/lib/customWidgets/song_bar.dart index c383a4867..d1fa0bf1b 100644 --- a/lib/customWidgets/song_bar.dart +++ b/lib/customWidgets/song_bar.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:musify/API/musify.dart'; import 'package:musify/services/audio_manager.dart'; +import 'package:musify/services/download_manager.dart'; import 'package:musify/style/appColors.dart'; class SongBar extends StatelessWidget { diff --git a/lib/services/audio_manager.dart b/lib/services/audio_manager.dart index 15d60774a..55459b067 100644 --- a/lib/services/audio_manager.dart +++ b/lib/services/audio_manager.dart @@ -51,76 +51,12 @@ String get positionText => bool isMuted = false; -Future downloadSong(dynamic song) async { - PermissionStatus status = await Permission.storage.status; - if (status.isDenied) { - await [ - Permission.storage, - Permission.accessMediaLocation, - Permission.mediaLibrary, - ].request(); - status = await Permission.storage.status; - if (status.isPermanentlyDenied) { - await openAppSettings(); - } - } - final filename = song['title'] - .replaceAll(r'\', '') - .replaceAll('/', '') - .replaceAll('*', '') - .replaceAll('?', '') - .replaceAll('"', '') - .replaceAll('<', '') - .replaceAll('>', '') - .replaceAll('|', '') + - '.' + - prefferedFileExtension.value; - - String filepath = ''; - final String? dlPath = - await ExtStorageProvider.getExtStorage(dirName: 'Musify'); - try { - await File('${dlPath!}/$filename') - .create(recursive: true) - .then((value) => filepath = value.path); - } catch (e) { - await [Permission.manageExternalStorage].request(); - await File('${dlPath!}/$filename') - .create(recursive: true) - .then((value) => filepath = value.path); - } - await Fluttertoast.showToast( - msg: 'Download Started!', - toastLength: Toast.LENGTH_SHORT, - gravity: ToastGravity.BOTTOM, - backgroundColor: accent, - textColor: accent != const Color(0xFFFFFFFF) ? Colors.white : Colors.black, - fontSize: 14, - ); - final audioStream = await getSongStream(song['ytid'].toString()); - final File file = File(filepath); - final fileStream = file.openWrite(); - await yt.videos.streamsClient.get(audioStream as StreamInfo).pipe(fileStream); - await fileStream.flush(); - await fileStream.close(); - - debugPrint('Done'); - await Fluttertoast.showToast( - msg: 'Download Completed!', - toastLength: Toast.LENGTH_SHORT, - gravity: ToastGravity.BOTTOM, - backgroundColor: accent, - textColor: accent != const Color(0xFFFFFFFF) ? Colors.white : Colors.black, - fontSize: 14, - ); -} - Future playSong(Map song) async { if (song['ytid'].length == 0) { await MyAudioHandler() .addQueueItem(mapToMediaItem(song, song['songUrl'].toString())); } else { - final songUrl = await getSongUrl(song['ytid']); + final songUrl = await getSong(song['ytid'], true); await MyAudioHandler().addQueueItem(mapToMediaItem(song, songUrl)); } await play(); diff --git a/lib/services/download_manager.dart b/lib/services/download_manager.dart new file mode 100644 index 000000000..6be32dadf --- /dev/null +++ b/lib/services/download_manager.dart @@ -0,0 +1,81 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:musify/API/musify.dart'; +import 'package:musify/services/audio_manager.dart'; +import 'package:musify/services/ext_storage.dart'; +import 'package:musify/style/appColors.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart'; + +Future downloadSong(dynamic song) async { + PermissionStatus status = await Permission.storage.status; + if (status.isDenied) { + await [ + Permission.storage, + Permission.accessMediaLocation, + Permission.mediaLibrary, + ].request(); + status = await Permission.storage.status; + if (status.isPermanentlyDenied) { + await openAppSettings(); + } + } + + await Fluttertoast.showToast( + msg: 'Download Started!', + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: accent, + textColor: accent != const Color(0xFFFFFFFF) ? Colors.white : Colors.black, + fontSize: 14, + ); + + final filename = song['title'] + .replaceAll(r'\', '') + .replaceAll('/', '') + .replaceAll('*', '') + .replaceAll('?', '') + .replaceAll('"', '') + .replaceAll('<', '') + .replaceAll('>', '') + .replaceAll('|', '') + + '.' + + prefferedFileExtension.value; + + String filepath = ''; + final String? dlPath = + await ExtStorageProvider.getExtStorage(dirName: 'Musify'); + try { + await File('${dlPath!}/$filename') + .create(recursive: true) + .then((value) => filepath = value.path); + await downloadFileFromYT(filename, filepath, dlPath, song); + } catch (e) { + await [Permission.manageExternalStorage].request(); + await File('${dlPath!}/$filename') + .create(recursive: true) + .then((value) => filepath = value.path); + await downloadFileFromYT(filename, filepath, dlPath, song); + } + + await Fluttertoast.showToast( + msg: 'Download Completed!', + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: accent, + textColor: accent != const Color(0xFFFFFFFF) ? Colors.white : Colors.black, + fontSize: 14, + ); +} + +Future downloadFileFromYT( + String filename, String filepath, String dlPath, dynamic song) async { + final audioStream = await getSong(song['ytid'].toString(), false); + final File file = File(filepath); + final fileStream = file.openWrite(); + await yt.videos.streamsClient.get(audioStream as StreamInfo).pipe(fileStream); + await fileStream.flush(); + await fileStream.close(); +} diff --git a/lib/ui/player.dart b/lib/ui/player.dart index 023108bb0..41d813559 100644 --- a/lib/ui/player.dart +++ b/lib/ui/player.dart @@ -10,6 +10,7 @@ import 'package:musify/API/musify.dart'; import 'package:musify/customWidgets/spinner.dart'; import 'package:musify/helper/mediaitem.dart'; import 'package:musify/services/audio_manager.dart'; +import 'package:musify/services/download_manager.dart'; import 'package:musify/style/appColors.dart'; import 'package:on_audio_query/on_audio_query.dart'; From a6ba59466fe03cacf80790b88930e4c20de0b2a0 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 13:33:53 +0400 Subject: [PATCH 05/16] improved code --- lib/main.dart | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 81e30e6a4..6a38ad10e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:audio_service/audio_service.dart'; import 'package:audio_session/audio_session.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -153,13 +154,10 @@ void main() async { await Hive.openBox('user'); await Hive.openBox('cache'); await FlutterDownloader.initialize( - debug: - true, // optional: set to false to disable printing logs to console (default: true) - ignoreSsl: - true // option: set to false to disable working with http links (default: false) - , + debug: kDebugMode, + ignoreSsl: true, ); - FlutterDownloader.registerCallback(TestClass.callback); + FlutterDownloader.registerCallback(downloadCallback); final PackageInfo packageInfo = await PackageInfo.fromPlatform(); version = packageInfo.version; await enableBooster(); @@ -183,7 +181,5 @@ Future initialisation() async { getIt.registerSingleton(audioHandler); } -// ignore: avoid_classes_with_only_static_members -class TestClass { - static void callback(String id, DownloadTaskStatus status, int progress) {} -} +@pragma('vm:entry-point') +void downloadCallback(String id, DownloadTaskStatus status, int progress) {} From b4ba01f71e73ffb5e0d5b010877d7e2e15bf6844 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 13:48:22 +0400 Subject: [PATCH 06/16] removed unused imports --- lib/services/audio_handler.dart | 2 +- lib/services/audio_manager.dart | 6 ------ renovate.json | 7 ------- 3 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 renovate.json diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index 3525ebed0..4d99fb8a4 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -38,7 +38,7 @@ class MyAudioHandler extends BaseAudioHandler { systemActions: const { MediaAction.seek, }, - androidCompactActionIndices: const [0, 1, 3], + androidCompactActionIndices: const [0, 1, 2], processingState: const { ProcessingState.idle: AudioProcessingState.idle, ProcessingState.loading: AudioProcessingState.loading, diff --git a/lib/services/audio_manager.dart b/lib/services/audio_manager.dart index 55459b067..46b6ef052 100644 --- a/lib/services/audio_manager.dart +++ b/lib/services/audio_manager.dart @@ -1,20 +1,14 @@ import 'dart:async'; -import 'dart:io'; import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:hive/hive.dart'; import 'package:just_audio/just_audio.dart'; import 'package:musify/API/musify.dart'; import 'package:musify/helper/mediaitem.dart'; import 'package:musify/main.dart'; import 'package:musify/services/audio_handler.dart'; -import 'package:musify/services/ext_storage.dart'; -import 'package:musify/style/appColors.dart'; import 'package:musify/ui/player.dart'; -import 'package:permission_handler/permission_handler.dart'; -import 'package:youtube_explode_dart/youtube_explode_dart.dart'; final _equalizer = AndroidEqualizer(); final _loudnessEnhancer = AndroidLoudnessEnhancer(); diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 71a3716b7..000000000 --- a/renovate.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "labels": ["dependencies"], - "extends": [ - "config:base" - ] -} \ No newline at end of file From fb542e2a11cac19774ccb9b6c9b642f422a50aa6 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 14:34:24 +0400 Subject: [PATCH 07/16] improved code --- lib/API/musify.dart | 2 +- lib/main.dart | 2 +- lib/services/audio_handler.dart | 2 +- lib/services/audio_manager.dart | 12 ++++++------ lib/ui/rootPage.dart | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/API/musify.dart b/lib/API/musify.dart index 0a00db38a..927545e67 100644 --- a/lib/API/musify.dart +++ b/lib/API/musify.dart @@ -227,7 +227,7 @@ Future setActivePlaylist(List plist) async { } await MyAudioHandler().addQueueItems(activeTempPlaylist); - await play(); + play(); } else { activePlaylist = plist; id = 0; diff --git a/lib/main.dart b/lib/main.dart index 6a38ad10e..94e582554 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -153,6 +153,7 @@ void main() async { await Hive.openBox('settings'); await Hive.openBox('user'); await Hive.openBox('cache'); + await initialisation(); await FlutterDownloader.initialize( debug: kDebugMode, ignoreSsl: true, @@ -161,7 +162,6 @@ void main() async { final PackageInfo packageInfo = await PackageInfo.fromPlatform(); version = packageInfo.version; await enableBooster(); - await initialisation(); runApp(const MyApp()); } diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index 4d99fb8a4..3525ebed0 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -38,7 +38,7 @@ class MyAudioHandler extends BaseAudioHandler { systemActions: const { MediaAction.seek, }, - androidCompactActionIndices: const [0, 1, 2], + androidCompactActionIndices: const [0, 1, 3], processingState: const { ProcessingState.idle: AudioProcessingState.idle, ProcessingState.loading: AudioProcessingState.loading, diff --git a/lib/services/audio_manager.dart b/lib/services/audio_manager.dart index 46b6ef052..e1830e36f 100644 --- a/lib/services/audio_manager.dart +++ b/lib/services/audio_manager.dart @@ -53,7 +53,7 @@ Future playSong(Map song) async { final songUrl = await getSong(song['ytid'], true); await MyAudioHandler().addQueueItem(mapToMediaItem(song, songUrl)); } - await play(); + play(); } Future changeShuffleStatus() async { @@ -87,15 +87,15 @@ Future enableBooster() async { await _loudnessEnhancer.setTargetGain(1); } -Future play() => _audioHandler.play(); +void play() => _audioHandler.play(); -Future pause() => _audioHandler.pause(); +void pause() => _audioHandler.pause(); -Future stop() => _audioHandler.stop(); +void stop() => _audioHandler.stop(); -Future playNext() => _audioHandler.skipToNext(); +void playNext() => _audioHandler.skipToNext(); -Future playPrevious() => _audioHandler.skipToPrevious(); +void playPrevious() => _audioHandler.skipToPrevious(); Future mute(bool muted) async { if (muted) { diff --git a/lib/ui/rootPage.dart b/lib/ui/rootPage.dart index 857162ca6..6b1224b65 100644 --- a/lib/ui/rootPage.dart +++ b/lib/ui/rootPage.dart @@ -53,7 +53,7 @@ class AppState extends State { void initAudioPlayer() { audioPlayer!.processingStateStream.listen((state) async { if (state == ProcessingState.completed) { - await pause(); + pause(); await audioPlayer!.seek(Duration.zero); if (hasNext) { if (activePlaylist.isEmpty && playNextSongAutomatically.value) { From 8fbe4c621f1e15a33e05bcfe1d9fdfdd03974f4b Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 14:42:16 +0400 Subject: [PATCH 08/16] enabled multidex --- android/app/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/app/build.gradle b/android/app/build.gradle index a9f5e732c..8afd08325 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -60,6 +60,7 @@ android { targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } signingConfigs { @@ -91,4 +92,5 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support:multidex:1.0.3' } From 93a6643dfb9ceb4ebd4a7a0464eee4ab4f648fe2 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Fri, 19 Aug 2022 20:33:00 +0400 Subject: [PATCH 09/16] optimized search/play playlist/lyrics functions --- lib/API/musify.dart | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/lib/API/musify.dart b/lib/API/musify.dart index 927545e67..d2f08ed03 100644 --- a/lib/API/musify.dart +++ b/lib/API/musify.dart @@ -35,9 +35,8 @@ int id = 0; Future fetchSongsList(String searchQuery) async { final List list = await yt.search.search(searchQuery); - searchedList = []; - for (final s in list) { - searchedList.add( + searchedList = [ + for (final s in list) returnSongLayout( 0, s.id.toString(), @@ -48,9 +47,9 @@ Future fetchSongsList(String searchQuery) async { s.thumbnails.lowResUrl.toString(), s.thumbnails.maxResUrl.toString(), s.title.split('-')[0].toString(), - ), - ); - } + ) + ]; + return searchedList; } @@ -221,10 +220,10 @@ Future setActivePlaylist(List plist) async { if (plist is List) { activePlaylist = []; id = 0; - final List activeTempPlaylist = []; - for (final song in plist) { - activeTempPlaylist.add(songModelToMediaItem(song, song.data)); - } + final List activeTempPlaylist = [ + for (final song in plist) songModelToMediaItem(song, song.data) + ]; + await MyAudioHandler().addQueueItems(activeTempPlaylist); play(); @@ -288,17 +287,14 @@ Future> getLocalSongs() async { } Future getSongLyrics(String artist, String title) async { - if (_lastLyricsUrl != - 'https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}') { - if (await getData('cache', - 'lyrics-https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}') != - null) { - lyrics.value = await getData('cache', - 'lyrics-https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}'); + final String currentApiUrl = + 'https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}'; + if (_lastLyricsUrl != currentApiUrl) { + if (await getData('cache', 'lyrics-$currentApiUrl') != null) { + lyrics.value = await getData('cache', 'lyrics-$currentApiUrl'); } else { lyrics.value = 'null'; - _lastLyricsUrl = - 'https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}'; + _lastLyricsUrl = currentApiUrl; final response = await http.get( Uri.parse(_lastLyricsUrl), headers: {'Accept': 'application/json'}, From b9fb3ffc4977027ec59a3ec7970157d9c87762f3 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Sat, 20 Aug 2022 10:32:33 +0400 Subject: [PATCH 10/16] changelog: added sponsorblock support changed play next song automatically icon --- lib/API/musify.dart | 37 +++++++++++++++++ lib/services/audio_handler.dart | 40 +++++++++++++++++- lib/services/audio_manager.dart | 38 ++++++++++++++++- lib/ui/player.dart | 74 ++++++++++++++++++++------------- 4 files changed, 157 insertions(+), 32 deletions(-) diff --git a/lib/API/musify.dart b/lib/API/musify.dart index d2f08ed03..dfbbf95f8 100644 --- a/lib/API/musify.dart +++ b/lib/API/musify.dart @@ -286,6 +286,43 @@ Future> getLocalSongs() async { return localSongs; } +Future>> getSkipSegments(String id) async { + try { + final res = await http.get(Uri( + scheme: 'https', + host: 'sponsor.ajay.app', + path: '/api/skipSegments', + queryParameters: { + 'videoID': id, + 'category': [ + 'sponsor', + 'selfpromo', + 'interaction', + 'intro', + 'outro', + 'music_offtopic' + ], + 'actionType': 'skip' + }, + )); + if (res.body != 'Not Found') { + final data = jsonDecode(res.body); + final segments = data.map((obj) { + return Map.castFrom({ + 'start': obj['segment'].first.toInt(), + 'end': obj['segment'].last.toInt(), + }); + }).toList(); + return List.castFrom>(segments); + } else { + return List.castFrom>([]); + } + } catch (e, stack) { + debugPrint('$e $stack'); + return List.castFrom>([]); + } +} + Future getSongLyrics(String artist, String title) async { final String currentApiUrl = 'https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}'; diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index 3525ebed0..420031165 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -111,8 +111,14 @@ class MyAudioHandler extends BaseAudioHandler { } @override - Future addQueueItem(MediaItem mediaItem) async { - final audioSource = _createAudioSource(mediaItem); + Future addQueueItem(MediaItem mediaItem, [start, end]) async { + final dynamic audioSource; + if (start != null || end != null) { + audioSource = _createClippingAudioSource(mediaItem, start, end); + } else { + audioSource = _createAudioSource(mediaItem); + } + await _playlist.add(audioSource); final newQueue = queue.value..add(mediaItem); @@ -126,6 +132,36 @@ class MyAudioHandler extends BaseAudioHandler { ); } + ClippingAudioSource _createClippingAudioSource(MediaItem mediaItem, + [start, end]) { + if (start != null && end == null) { + return ClippingAudioSource( + start: start, + tag: mediaItem, + child: AudioSource.uri( + Uri.parse(mediaItem.extras!['url'].toString()), + tag: mediaItem, + )); + } else if (end != null && start == null) { + return ClippingAudioSource( + end: end, + tag: mediaItem, + child: AudioSource.uri( + Uri.parse(mediaItem.extras!['url'].toString()), + tag: mediaItem, + )); + } else { + return ClippingAudioSource( + start: start, + end: end, + tag: mediaItem, + child: AudioSource.uri( + Uri.parse(mediaItem.extras!['url'].toString()), + tag: mediaItem, + )); + } + } + @override Future removeQueueItemAt(int index) async { await _playlist.removeAt(index); diff --git a/lib/services/audio_manager.dart b/lib/services/audio_manager.dart index e1830e36f..350dea5aa 100644 --- a/lib/services/audio_manager.dart +++ b/lib/services/audio_manager.dart @@ -8,6 +8,7 @@ import 'package:musify/API/musify.dart'; import 'package:musify/helper/mediaitem.dart'; import 'package:musify/main.dart'; import 'package:musify/services/audio_handler.dart'; +import 'package:musify/services/data_manager.dart'; import 'package:musify/ui/player.dart'; final _equalizer = AndroidEqualizer(); @@ -28,7 +29,10 @@ final shuffleNotifier = ValueNotifier(false); final repeatNotifier = ValueNotifier(false); final prefferedFileExtension = ValueNotifier( Hive.box('settings').get('audioFileType', defaultValue: 'mp3') as String); -final playNextSongAutomatically = ValueNotifier(false); +final playNextSongAutomatically = ValueNotifier( + Hive.box('settings').get('playNextSongAutomatically', defaultValue: false)); +final sponsorBlockSupport = ValueNotifier( + Hive.box('settings').get('sponsorBlockSupport', defaultValue: false)); bool get hasNext => activePlaylist.isEmpty ? audioPlayer!.hasNext @@ -51,7 +55,25 @@ Future playSong(Map song) async { .addQueueItem(mapToMediaItem(song, song['songUrl'].toString())); } else { final songUrl = await getSong(song['ytid'], true); - await MyAudioHandler().addQueueItem(mapToMediaItem(song, songUrl)); + + if (sponsorBlockSupport.value) { + final segments = await getSkipSegments(song['ytid']); + if (segments.isNotEmpty) { + if (segments.length == 1) { + await MyAudioHandler().addQueueItem(mapToMediaItem(song, songUrl), + Duration(seconds: segments[0]['end']!)); + } else { + await MyAudioHandler().addQueueItem( + mapToMediaItem(song, songUrl), + Duration(seconds: segments[0]['end']!), + Duration(seconds: segments[1]['start']!)); + } + } else { + await MyAudioHandler().addQueueItem(mapToMediaItem(song, songUrl)); + } + } else { + await MyAudioHandler().addQueueItem(mapToMediaItem(song, songUrl)); + } } play(); } @@ -67,8 +89,10 @@ Future changeShuffleStatus() async { void changeAutoPlayNextStatus() { if (playNextSongAutomatically.value == false) { playNextSongAutomatically.value = true; + addOrUpdateData('settings', 'playNextSongAutomatically', true); } else { playNextSongAutomatically.value = false; + addOrUpdateData('settings', 'playNextSongAutomatically', false); } } @@ -82,6 +106,16 @@ Future changeLoopStatus() async { } } +void changeSponsorBlockStatus() { + if (sponsorBlockSupport.value == false) { + sponsorBlockSupport.value = true; + addOrUpdateData('settings', 'sponsorBlockSupport', true); + } else { + sponsorBlockSupport.value = false; + addOrUpdateData('settings', 'sponsorBlockSupport', false); + } +} + Future enableBooster() async { await _loudnessEnhancer.setEnabled(true); await _loudnessEnhancer.setTargetGain(1); diff --git a/lib/ui/player.dart b/lib/ui/player.dart index 41d813559..2f3ff9df7 100644 --- a/lib/ui/player.dart +++ b/lib/ui/player.dart @@ -289,19 +289,35 @@ class AudioAppState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (metadata.extras['ytid'].toString().isNotEmpty) - IconButton( - padding: EdgeInsets.zero, - icon: const Icon( - MdiIcons.download, - color: Colors.white, - ), - iconSize: size.width * 0.056, - splashColor: Colors.transparent, - onPressed: () { - downloadSong( - mediaItemToMap(metadata as MediaItem), - ); - }, + Column( + children: [ + IconButton( + padding: EdgeInsets.zero, + icon: const Icon( + MdiIcons.download, + color: Colors.white, + ), + iconSize: size.width * 0.056, + splashColor: Colors.transparent, + onPressed: () { + downloadSong( + mediaItemToMap(metadata as MediaItem), + ); + }, + ), + IconButton( + padding: EdgeInsets.zero, + icon: Icon( + sponsorBlockSupport.value + ? MdiIcons.playCircle + : MdiIcons.playCircleOutline, + color: Colors.white, + ), + iconSize: size.width * 0.056, + splashColor: Colors.transparent, + onPressed: () => + setState(changeSponsorBlockStatus)), + ], ), IconButton( padding: EdgeInsets.zero, @@ -374,21 +390,6 @@ class AudioAppState extends State { if (metadata.extras['ytid'].toString().isNotEmpty) Column( children: [ - ValueListenableBuilder( - valueListenable: playNextSongAutomatically, - builder: (_, value, __) { - return IconButton( - padding: EdgeInsets.zero, - icon: Icon( - MdiIcons.chevronRight, - color: value ? accent : Colors.white, - ), - iconSize: size.width * 0.056, - splashColor: Colors.transparent, - onPressed: changeAutoPlayNextStatus, - ); - }, - ), ValueListenableBuilder( valueListenable: songLikeStatus, builder: (_, value, __) { @@ -417,6 +418,23 @@ class AudioAppState extends State { } }, ), + ValueListenableBuilder( + valueListenable: playNextSongAutomatically, + builder: (_, value, __) { + return IconButton( + padding: EdgeInsets.zero, + icon: Icon( + value + ? MdiIcons.skipNextCircleOutline + : MdiIcons.skipNextCircle, + color: value ? accent : Colors.white, + ), + iconSize: size.width * 0.056, + splashColor: Colors.transparent, + onPressed: changeAutoPlayNextStatus, + ); + }, + ), ], ), ], From d11c3b8861ebbdb61e12d0b36484b5d11f745e3f Mon Sep 17 00:00:00 2001 From: gokadzev Date: Sat, 20 Aug 2022 13:08:18 +0400 Subject: [PATCH 11/16] now more song lyrics should be available --- lib/API/musify.dart | 32 +++++++++++++++++++++++++++----- lib/main.dart | 1 + 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/API/musify.dart b/lib/API/musify.dart index dfbbf95f8..f35db3bac 100644 --- a/lib/API/musify.dart +++ b/lib/API/musify.dart @@ -30,6 +30,7 @@ List localSongs = []; final lyrics = ValueNotifier('null'); String _lastLyricsUrl = ''; +String _alternateApiUrl = ''; int id = 0; @@ -323,12 +324,33 @@ Future>> getSkipSegments(String id) async { } } +Future getAlternateApiUrl() async { + final response = await http.get( + Uri.parse('https://jsapi.apiary.io/apis/lyricsovh'), + headers: {'Accept': 'application/json'}, + ).timeout(const Duration(seconds: 10)); + + if (response.statusCode == 200) { + final proxyResponse = await json.decode(response.body); + if (proxyResponse['urls']['proxy'] != null) { + _alternateApiUrl = proxyResponse['urls']['proxy']; + } + } +} + Future getSongLyrics(String artist, String title) async { - final String currentApiUrl = - 'https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}'; + String currentApiUrl; + if (_alternateApiUrl != '') { + currentApiUrl = + '$_alternateApiUrl${artist.replaceAll(RegExp(r'[^\w\s]+'), '')}/${title.split(" (")[0].split("|")[0].trim().replaceAll(RegExp(r'[^\w\s]+'), '')}'; + } else { + currentApiUrl = + 'https://api.lyrics.ovh/v1/${artist.replaceAll(RegExp(r'[^\w\s]+'), '')}/${title.split(" (")[0].split("|")[0].trim().replaceAll(RegExp(r'[^\w\s]+'), '')}'; + } + if (_lastLyricsUrl != currentApiUrl) { - if (await getData('cache', 'lyrics-$currentApiUrl') != null) { - lyrics.value = await getData('cache', 'lyrics-$currentApiUrl'); + if (await getData('cache', 'lyrics-$artist-$title') != null) { + lyrics.value = await getData('cache', 'lyrics-$artist-$title'); } else { lyrics.value = 'null'; _lastLyricsUrl = currentApiUrl; @@ -341,7 +363,7 @@ Future getSongLyrics(String artist, String title) async { final lyricsResponse = await json.decode(response.body); if (lyricsResponse['lyrics'] != null) { lyrics.value = lyricsResponse['lyrics'].toString(); - addOrUpdateData('cache', 'lyrics-$_lastLyricsUrl', + addOrUpdateData('cache', 'lyrics-$artist-$title', lyricsResponse['lyrics'].toString()); } else { lyrics.value = 'not found'; diff --git a/lib/main.dart b/lib/main.dart index 94e582554..f36dcbb52 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -161,6 +161,7 @@ void main() async { FlutterDownloader.registerCallback(downloadCallback); final PackageInfo packageInfo = await PackageInfo.fromPlatform(); version = packageInfo.version; + await getAlternateApiUrl(); await enableBooster(); runApp(const MyApp()); } From 9c13c9bb5870013977076dbc7761ebfb1e2ea47b Mon Sep 17 00:00:00 2001 From: gokadzev Date: Sat, 20 Aug 2022 13:17:56 +0400 Subject: [PATCH 12/16] miscellaneous small changes --- README.md | 1 + flutter_launcher_icons.yaml | 7 ------ flutter_native_splash.yaml | 8 ------- .../AppIcon.appiconset/Icon-App-50x50@1x.png | Bin 0 -> 1042 bytes .../AppIcon.appiconset/Icon-App-50x50@2x.png | Bin 0 -> 2370 bytes .../AppIcon.appiconset/Icon-App-57x57@1x.png | Bin 0 -> 1201 bytes .../AppIcon.appiconset/Icon-App-57x57@2x.png | Bin 0 -> 2809 bytes .../AppIcon.appiconset/Icon-App-72x72@1x.png | Bin 0 -> 1552 bytes .../AppIcon.appiconset/Icon-App-72x72@2x.png | Bin 0 -> 3824 bytes pubspec.lock | 16 +++++++++++++- pubspec.yaml | 20 +++++++++++++++++- 11 files changed, 35 insertions(+), 17 deletions(-) delete mode 100644 flutter_launcher_icons.yaml delete mode 100644 flutter_native_splash.yaml create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png diff --git a/README.md b/README.md index 038188766..6a3a06217 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Play Local / Downloaded Songs Support :open_file_folder:
High Quality mp3 / m4a / flac Format :fire:
Lyrics Support :pencil:
+ SponsorBlock Support :scissors:
No Ads :no_entry_sign:
No Subscriptions :dollar:
12 Supported Languages :us:
diff --git a/flutter_launcher_icons.yaml b/flutter_launcher_icons.yaml deleted file mode 100644 index aa8e3147a..000000000 --- a/flutter_launcher_icons.yaml +++ /dev/null @@ -1,7 +0,0 @@ -flutter_icons: - android: "launcher_icon" - adaptive_icon_background: "#191919" - adaptive_icon_foreground: "assets/images/ic_launcher_foreground.png" - adaptive_icon_round: "assets/images/ic_launcher_round.png" - image_path: "assets/images/ic_launcher.png" - ios: true \ No newline at end of file diff --git a/flutter_native_splash.yaml b/flutter_native_splash.yaml deleted file mode 100644 index 8d4dfb253..000000000 --- a/flutter_native_splash.yaml +++ /dev/null @@ -1,8 +0,0 @@ - flutter_native_splash: - image: assets/images/splash.png - color: "151515" - - - android_12: - image: assets/images/splash.png - color: "151515" \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..076a59c5f27bfd82651714093518cf77d1dd5f3c GIT binary patch literal 1042 zcmV+t1nv8YP))i-LM62!evv=qKNlvc8bL#-JwwbwUOb# zJ-zF?APl0~>s|eln9O!Uj4>lN>R97)74Po#weJsyzg^G1t_#9u;+T;jG!Z8D>2@zU z!9Z>xE7bHr6sy%YCuJT7kB+M;T0y5Hr$23ThhQu4NG8tQ7MKkXktB*<7gHdjxOJHw&>N9VEY`0#Km= z5X$=sMr2mB-}bUkG{&tX&Jwrd@~y{6ZkOG$dVM0{6&>;mDZx~)m@e!G&v(2g6GP#TL`}|p&-PhVA+;K@YHVyQ4|dIbs#eM zIU~Fzafk(}+;kY8x*f?M%yC;`83sBZA>7plSNTe<_OWaiY4WFpf!K?y;90TlSNJfe zJ@q>=(D4XuEzMZcxChpP#fS#_M48NxFp%QvE$matD1Oe88q{n*i4Uz8(et!Llqp>a z12J11AnA=^3dZeSk0NgqBEcSv`n%A1_YCVw#zmR^Wna{dxRW%M)Et6NEVZh(B?VhS zIjjpj+Jazckb!rtsA$*+#bQsjBB>&nHi92tu>LA0%4CLwfyBNC@c!`yEZ=;bCAvw= zcaj3&K=DWrA0A#5Wp0v$F27&jK0sn@6iXWqBEPU)3okVhg}>_wx}RS~H2g)RxeN)f z?1P`4X~UAg5X!vyhz|Ed9hVbM>5|rKjg1b-y0xxy+d)QC4#a5E2a(llOO!51JRbE? z>Rgq4+hr`p6R{wr>PYr^JrFe*{BqmjbZ;Xt5g3Vusx%brzr&8=*_U)dMn;17dwuPv z-0rdi7OSlkf1QRRk%)yE#67>?cMdZI;TaMb8uDLZ<0gOc2&vl!GZPD^F#Ftt^4{Coi&Jq#irT_o{ M07*qoM6N<$f`~xxwEzGB literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4b3d1cf37e003d452fe6086e2866ca8f6de148a0 GIT binary patch literal 2370 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 Date: Sat, 20 Aug 2022 15:02:29 +0400 Subject: [PATCH 13/16] changelog: improved / reformat code disabled automatically play next song since it doesn't work --- lib/API/musify.dart | 32 +++++---------------------- lib/main.dart | 38 ++++++++++++++++++++++++++------- lib/services/audio_handler.dart | 19 +++++++++++++++++ lib/ui/player.dart | 6 +++--- lib/ui/rootPage.dart | 19 ----------------- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/lib/API/musify.dart b/lib/API/musify.dart index f35db3bac..ecad67007 100644 --- a/lib/API/musify.dart +++ b/lib/API/musify.dart @@ -19,6 +19,8 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart'; final yt = YoutubeExplode(); final OnAudioQuery _audioQuery = OnAudioQuery(); +final random = Random(); + List ytplaylists = []; List searchedList = []; List playlists = []; @@ -160,34 +162,10 @@ Future searchPlaylist(String query) async { } Future getRandomSong() async { - if (playlists.isEmpty) { - playlists = - json.decode(await rootBundle.loadString('assets/db/playlists.db.json')) - as List; - } - final random = Random(); - final playlistId = playlists[random.nextInt(playlists.length)]['ytid']; - final playlistSongs = - await getData('cache', 'playlistSongs$playlistId') ?? []; + final playlistId = 'PLgzTt0k8mXzEk586ze4BjvDXR7c-TUSnx'; + final List playlistSongs = await getSongsFromPlaylist(playlistId); - if (playlistSongs.isEmpty) { - final songs = await yt.playlists.getVideos(playlistId).take(5).toList(); - final choosedSong = songs[random.nextInt(playlistSongs.length)]; - - return returnSongLayout( - 0, - choosedSong.id.toString(), - formatSongTitle( - choosedSong.title.split('-')[choosedSong.title.split('-').length - 1], - ), - choosedSong.thumbnails.standardResUrl, - choosedSong.thumbnails.lowResUrl, - choosedSong.thumbnails.maxResUrl, - choosedSong.title.split('-')[0], - ); - } else { - return playlistSongs[random.nextInt(playlistSongs.length)]; - } + return playlistSongs[random.nextInt(playlistSongs.length)]; } Future getSongsFromPlaylist(dynamic playlistid) async { diff --git a/lib/main.dart b/lib/main.dart index f36dcbb52..17d115d82 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,6 +17,7 @@ import 'package:musify/ui/rootPage.dart'; import 'package:package_info_plus/package_info_plus.dart'; GetIt getIt = GetIt.instance; +bool _interrupted = false; class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @@ -71,6 +72,8 @@ class _MyAppState extends State { }; _locale = Locale(codes[Hive.box('settings') .get('language', defaultValue: 'English') as String]!); + + FlutterDownloader.registerCallback(downloadCallback); } @override @@ -154,21 +157,33 @@ void main() async { await Hive.openBox('user'); await Hive.openBox('cache'); await initialisation(); - await FlutterDownloader.initialize( - debug: kDebugMode, - ignoreSsl: true, - ); - FlutterDownloader.registerCallback(downloadCallback); - final PackageInfo packageInfo = await PackageInfo.fromPlatform(); - version = packageInfo.version; await getAlternateApiUrl(); - await enableBooster(); runApp(const MyApp()); } Future initialisation() async { final session = await AudioSession.instance; await session.configure(const AudioSessionConfiguration.music()); + session.interruptionEventStream.listen((event) { + if (event.begin) { + if (audioPlayer!.playing) { + pause(); + _interrupted = true; + } + } else { + switch (event.type) { + case AudioInterruptionType.pause: + case AudioInterruptionType.duck: + if (!audioPlayer!.playing && _interrupted) { + play(); + } + break; + case AudioInterruptionType.unknown: + break; + } + _interrupted = false; + } + }); final AudioHandler audioHandler = await AudioService.init( builder: MyAudioHandler.new, config: const AudioServiceConfig( @@ -180,6 +195,13 @@ Future initialisation() async { ), ); getIt.registerSingleton(audioHandler); + await enableBooster(); + await FlutterDownloader.initialize( + debug: kDebugMode, + ignoreSsl: true, + ); + final PackageInfo packageInfo = await PackageInfo.fromPlatform(); + version = packageInfo.version; } @pragma('vm:entry-point') diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index 420031165..b9613ae1d 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -14,6 +14,7 @@ class MyAudioHandler extends BaseAudioHandler { _listenForDurationChanges(); _listenForCurrentSongIndexChanges(); _listenForSequenceStateChanges(); + _listenProcessingStates(); } Future _loadEmptyPlaylist() async { @@ -64,6 +65,24 @@ class MyAudioHandler extends BaseAudioHandler { }); } + void _listenProcessingStates() { + audioPlayer!.processingStateStream.listen((state) async { + if (state == ProcessingState.completed) { + await pause(); + await audioPlayer!.seek(Duration.zero); + // if (hasNext) { + // await playSong(activePlaylist[id + 1]); + // id = id + 1; + // } + + // if (!hasNext && playNextSongAutomatically.value) { + // final randomSong = await getRandomSong(); + // await playSong(randomSong); + // } + } + }); + } + void _listenForDurationChanges() { audioPlayer!.durationStream.listen((duration) { var index = audioPlayer!.currentIndex; diff --git a/lib/ui/player.dart b/lib/ui/player.dart index 2f3ff9df7..8978cf680 100644 --- a/lib/ui/player.dart +++ b/lib/ui/player.dart @@ -425,8 +425,8 @@ class AudioAppState extends State { padding: EdgeInsets.zero, icon: Icon( value - ? MdiIcons.skipNextCircleOutline - : MdiIcons.skipNextCircle, + ? MdiIcons.skipNextCircle + : MdiIcons.skipNextCircleOutline, color: value ? accent : Colors.white, ), iconSize: size.width * 0.056, @@ -625,7 +625,7 @@ class AudioAppState extends State { } else { return IconButton( icon: const Icon(MdiIcons.replay), - iconSize: 64.0, + iconSize: size.width * 0.056, onPressed: () => audioPlayer! .seek(Duration.zero, index: audioPlayer!.effectiveIndices!.first), ); diff --git a/lib/ui/rootPage.dart b/lib/ui/rootPage.dart index 6b1224b65..9792c98bf 100644 --- a/lib/ui/rootPage.dart +++ b/lib/ui/rootPage.dart @@ -4,7 +4,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:just_audio/just_audio.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; -import 'package:musify/API/musify.dart'; import 'package:musify/customWidgets/custom_animated_bottom_bar.dart'; import 'package:musify/helper/version.dart'; import 'package:musify/services/audio_manager.dart'; @@ -30,7 +29,6 @@ class AppState extends State { @override void initState() { super.initState(); - initAudioPlayer(); checkAppUpdates().then( (value) => { if (value == true) @@ -50,23 +48,6 @@ class AppState extends State { ); } - void initAudioPlayer() { - audioPlayer!.processingStateStream.listen((state) async { - if (state == ProcessingState.completed) { - pause(); - await audioPlayer!.seek(Duration.zero); - if (hasNext) { - if (activePlaylist.isEmpty && playNextSongAutomatically.value) { - await playSong(await getRandomSong()); - } else { - await playSong(activePlaylist[id + 1]); - id = id + 1; - } - } - } - }); - } - @override Widget build(BuildContext context) { final pages = [ From a10a76828e916091d3784f350d507fd03d06e351 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Sat, 20 Aug 2022 19:11:05 +0400 Subject: [PATCH 14/16] improved player and mini player code --- lib/main.dart | 8 +-- lib/services/audio_handler.dart | 67 ++++++++++---------- lib/services/audio_manager.dart | 19 +++--- lib/ui/player.dart | 106 ++++++++++++++------------------ lib/ui/rootPage.dart | 77 ++++++++++------------- 5 files changed, 125 insertions(+), 152 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 17d115d82..7c6dea071 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -79,7 +79,7 @@ class _MyAppState extends State { @override void dispose() { Hive.close(); - audioPlayer!.dispose(); + audioPlayer.dispose(); super.dispose(); } @@ -152,11 +152,11 @@ class _MyAppState extends State { void main() async { WidgetsFlutterBinding.ensureInitialized(); + await initialisation(); await Hive.initFlutter(); await Hive.openBox('settings'); await Hive.openBox('user'); await Hive.openBox('cache'); - await initialisation(); await getAlternateApiUrl(); runApp(const MyApp()); } @@ -166,7 +166,7 @@ Future initialisation() async { await session.configure(const AudioSessionConfiguration.music()); session.interruptionEventStream.listen((event) { if (event.begin) { - if (audioPlayer!.playing) { + if (audioPlayer.playing) { pause(); _interrupted = true; } @@ -174,7 +174,7 @@ Future initialisation() async { switch (event.type) { case AudioInterruptionType.pause: case AudioInterruptionType.duck: - if (!audioPlayer!.playing && _interrupted) { + if (!audioPlayer.playing && _interrupted) { play(); } break; diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index b9613ae1d..1395e8449 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -19,15 +19,15 @@ class MyAudioHandler extends BaseAudioHandler { Future _loadEmptyPlaylist() async { try { - await audioPlayer!.setAudioSource(_playlist); + await audioPlayer.setAudioSource(_playlist); } catch (e) { debugPrint('Error: $e'); } } void _notifyAudioHandlerAboutPlaybackEvents() { - audioPlayer!.playbackEventStream.listen((PlaybackEvent event) { - final bool playing = audioPlayer!.playing; + audioPlayer.playbackEventStream.listen((PlaybackEvent event) { + final bool playing = audioPlayer.playing; playbackState.add( playbackState.value.copyWith( controls: [ @@ -46,19 +46,19 @@ class MyAudioHandler extends BaseAudioHandler { ProcessingState.buffering: AudioProcessingState.buffering, ProcessingState.ready: AudioProcessingState.ready, ProcessingState.completed: AudioProcessingState.completed, - }[audioPlayer!.processingState]!, + }[audioPlayer.processingState]!, repeatMode: const { LoopMode.off: AudioServiceRepeatMode.none, LoopMode.one: AudioServiceRepeatMode.one, LoopMode.all: AudioServiceRepeatMode.all, - }[audioPlayer!.loopMode]!, - shuffleMode: (audioPlayer!.shuffleModeEnabled) + }[audioPlayer.loopMode]!, + shuffleMode: (audioPlayer.shuffleModeEnabled) ? AudioServiceShuffleMode.all : AudioServiceShuffleMode.none, playing: playing, - updatePosition: audioPlayer!.position, - bufferedPosition: audioPlayer!.bufferedPosition, - speed: audioPlayer!.speed, + updatePosition: audioPlayer.position, + bufferedPosition: audioPlayer.bufferedPosition, + speed: audioPlayer.speed, queueIndex: event.currentIndex, ), ); @@ -66,10 +66,11 @@ class MyAudioHandler extends BaseAudioHandler { } void _listenProcessingStates() { - audioPlayer!.processingStateStream.listen((state) async { - if (state == ProcessingState.completed) { + audioPlayer.playerStateStream.listen((state) async { + playerState.value = state; + if (state.processingState == ProcessingState.completed) { await pause(); - await audioPlayer!.seek(Duration.zero); + await audioPlayer.seek(Duration.zero); // if (hasNext) { // await playSong(activePlaylist[id + 1]); // id = id + 1; @@ -84,12 +85,12 @@ class MyAudioHandler extends BaseAudioHandler { } void _listenForDurationChanges() { - audioPlayer!.durationStream.listen((duration) { - var index = audioPlayer!.currentIndex; + audioPlayer.durationStream.listen((duration) { + var index = audioPlayer.currentIndex; final List newQueue = queue.value; if (index == null || newQueue.isEmpty) return; - if (audioPlayer!.shuffleModeEnabled) { - index = audioPlayer!.shuffleIndices![index]; + if (audioPlayer.shuffleModeEnabled) { + index = audioPlayer.shuffleIndices![index]; } final MediaItem oldMediaItem = newQueue[index]; final MediaItem newMediaItem = oldMediaItem.copyWith(duration: duration); @@ -100,18 +101,18 @@ class MyAudioHandler extends BaseAudioHandler { } void _listenForCurrentSongIndexChanges() { - audioPlayer!.currentIndexStream.listen((index) { + audioPlayer.currentIndexStream.listen((index) { final List playlist = queue.value; if (index == null || playlist.isEmpty) return; - if (audioPlayer!.shuffleModeEnabled) { - index = audioPlayer!.shuffleIndices![index]; + if (audioPlayer.shuffleModeEnabled) { + index = audioPlayer.shuffleIndices![index]; } mediaItem.add(playlist[index]); }); } void _listenForSequenceStateChanges() { - audioPlayer!.sequenceStateStream.listen((SequenceState? sequenceState) { + audioPlayer.sequenceStateStream.listen((SequenceState? sequenceState) { final sequence = sequenceState?.effectiveSequence; if (sequence == null || sequence.isEmpty) return; final items = sequence.map((source) => source.tag as MediaItem); @@ -190,18 +191,18 @@ class MyAudioHandler extends BaseAudioHandler { } @override - Future play() => audioPlayer!.play(); + Future play() => audioPlayer.play(); @override - Future pause() => audioPlayer!.pause(); + Future pause() => audioPlayer.pause(); @override - Future seek(Duration position) => audioPlayer!.seek(position); + Future seek(Duration position) => audioPlayer.seek(position); @override Future skipToNext() async { if (activePlaylist.isEmpty) { - await audioPlayer!.seekToNext(); + await audioPlayer.seekToNext(); } else { if (id + 1 <= activePlaylist.length) { await playSong(activePlaylist[id + 1]); @@ -213,7 +214,7 @@ class MyAudioHandler extends BaseAudioHandler { @override Future skipToPrevious() async { if (activePlaylist.isEmpty) { - await audioPlayer!.seekToPrevious(); + await audioPlayer.seekToPrevious(); } else { if (id - 1 >= 0) { await playSong(activePlaylist[id - 1]); @@ -226,14 +227,14 @@ class MyAudioHandler extends BaseAudioHandler { Future setRepeatMode(AudioServiceRepeatMode repeatMode) async { switch (repeatMode) { case AudioServiceRepeatMode.none: - await audioPlayer!.setLoopMode(LoopMode.off); + await audioPlayer.setLoopMode(LoopMode.off); break; case AudioServiceRepeatMode.one: - await audioPlayer!.setLoopMode(LoopMode.one); + await audioPlayer.setLoopMode(LoopMode.one); break; case AudioServiceRepeatMode.group: case AudioServiceRepeatMode.all: - await audioPlayer!.setLoopMode(LoopMode.all); + await audioPlayer.setLoopMode(LoopMode.all); break; } } @@ -241,24 +242,24 @@ class MyAudioHandler extends BaseAudioHandler { @override Future setShuffleMode(AudioServiceShuffleMode shuffleMode) async { if (shuffleMode == AudioServiceShuffleMode.none) { - await audioPlayer!.setShuffleModeEnabled(false); + await audioPlayer.setShuffleModeEnabled(false); } else { - await audioPlayer!.shuffle(); - await audioPlayer!.setShuffleModeEnabled(true); + await audioPlayer.shuffle(); + await audioPlayer.setShuffleModeEnabled(true); } } @override Future customAction(String name, [Map? extras]) async { if (name == 'dispose') { - await audioPlayer!.dispose(); + await audioPlayer.dispose(); await super.stop(); } } @override Future stop() async { - await audioPlayer!.stop(); + await audioPlayer.stop(); return super.stop(); } } diff --git a/lib/services/audio_manager.dart b/lib/services/audio_manager.dart index 350dea5aa..a218601c3 100644 --- a/lib/services/audio_manager.dart +++ b/lib/services/audio_manager.dart @@ -15,7 +15,7 @@ final _equalizer = AndroidEqualizer(); final _loudnessEnhancer = AndroidLoudnessEnhancer(); final _audioHandler = getIt(); -AudioPlayer? audioPlayer = AudioPlayer( +AudioPlayer audioPlayer = AudioPlayer( audioPipeline: AudioPipeline( androidAudioEffects: [ _loudnessEnhancer, @@ -27,6 +27,7 @@ AudioPlayer? audioPlayer = AudioPlayer( final durationNotifier = ValueNotifier(Duration.zero); final shuffleNotifier = ValueNotifier(false); final repeatNotifier = ValueNotifier(false); +final playerState = ValueNotifier(audioPlayer.playerState); final prefferedFileExtension = ValueNotifier( Hive.box('settings').get('audioFileType', defaultValue: 'mp3') as String); final playNextSongAutomatically = ValueNotifier( @@ -35,11 +36,11 @@ final sponsorBlockSupport = ValueNotifier( Hive.box('settings').get('sponsorBlockSupport', defaultValue: false)); bool get hasNext => activePlaylist.isEmpty - ? audioPlayer!.hasNext + ? audioPlayer.hasNext : id + 1 <= activePlaylist.length; bool get hasPrevious => - activePlaylist.isEmpty ? audioPlayer!.hasPrevious : id - 1 >= 0; + activePlaylist.isEmpty ? audioPlayer.hasPrevious : id - 1 >= 0; String get durationText => duration != null ? duration.toString().split('.').first : ''; @@ -80,9 +81,9 @@ Future playSong(Map song) async { Future changeShuffleStatus() async { if (shuffleNotifier.value == true) { - await audioPlayer?.setShuffleModeEnabled(false); + await audioPlayer.setShuffleModeEnabled(false); } else { - await audioPlayer?.setShuffleModeEnabled(true); + await audioPlayer.setShuffleModeEnabled(true); } } @@ -99,10 +100,10 @@ void changeAutoPlayNextStatus() { Future changeLoopStatus() async { if (repeatNotifier.value == false) { repeatNotifier.value = true; - await audioPlayer?.setLoopMode(LoopMode.one); + await audioPlayer.setLoopMode(LoopMode.one); } else { repeatNotifier.value = false; - await audioPlayer?.setLoopMode(LoopMode.off); + await audioPlayer.setLoopMode(LoopMode.off); } } @@ -133,8 +134,8 @@ void playPrevious() => _audioHandler.skipToPrevious(); Future mute(bool muted) async { if (muted) { - await audioPlayer?.setVolume(0); + await audioPlayer.setVolume(0); } else { - await audioPlayer?.setVolume(1); + await audioPlayer.setVolume(1); } } diff --git a/lib/ui/player.dart b/lib/ui/player.dart index 8978cf680..d319be99b 100644 --- a/lib/ui/player.dart +++ b/lib/ui/player.dart @@ -37,9 +37,9 @@ class AudioAppState extends State { void initState() { super.initState(); - positionSubscription = audioPlayer?.positionStream + positionSubscription = audioPlayer.positionStream .listen((p) => {if (mounted) setState(() => position = p)}); - durationSubscription = audioPlayer?.durationStream.listen( + durationSubscription = audioPlayer.durationStream.listen( (d) => { if (mounted) {setState(() => duration = d)} }, @@ -84,7 +84,7 @@ class AudioAppState extends State { child: Padding( padding: EdgeInsets.only(top: size.height * 0.012), child: StreamBuilder( - stream: audioPlayer!.sequenceStateStream, + stream: audioPlayer.sequenceStateStream, builder: (context, snapshot) { final state = snapshot.data; if (state?.sequence.isEmpty ?? true) { @@ -268,7 +268,7 @@ class AudioAppState extends State { value: position?.inMilliseconds.toDouble() ?? 0.0, onChanged: (double? value) { setState(() { - audioPlayer!.seek( + audioPlayer.seek( Duration( milliseconds: value!.round(), ), @@ -346,25 +346,48 @@ class AudioAppState extends State { color: accent, borderRadius: BorderRadius.circular(100), ), - child: StreamBuilder( - stream: audioPlayer!.playerStateStream, - builder: (context, snapshot) { - if (snapshot.hasData) { - final playerState = snapshot.data; - return _playerControllers(playerState!, size); - } else { - return Container( - margin: const EdgeInsets.all(8), - width: size.width * 0.08, - height: size.width * 0.08, - child: const CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Color.fromARGB(255, 0, 0, 0)), - ), - ); - } - }, - ), + child: ValueListenableBuilder( + valueListenable: playerState, + builder: (_, value, __) { + if (value.processingState == + ProcessingState.loading || + value.processingState == + ProcessingState.buffering) { + return Container( + margin: const EdgeInsets.all(8), + width: size.width * 0.08, + height: size.width * 0.08, + child: const CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + Color.fromARGB(255, 0, 0, 0)), + ), + ); + } else if (value.playing != true) { + return IconButton( + icon: const Icon(MdiIcons.play), + iconSize: size.width * 0.1, + onPressed: play, + splashColor: Colors.transparent, + ); + } else if (value.processingState != + ProcessingState.completed) { + return IconButton( + icon: const Icon(MdiIcons.pause), + iconSize: size.width * 0.1, + onPressed: pause, + splashColor: Colors.transparent, + ); + } else { + return IconButton( + icon: const Icon(MdiIcons.replay), + iconSize: size.width * 0.056, + onPressed: () => audioPlayer.seek( + Duration.zero, + index: audioPlayer + .effectiveIndices!.first), + ); + } + }), ), IconButton( padding: EdgeInsets.zero, @@ -594,41 +617,4 @@ class AudioAppState extends State { ) ], ); - - Widget _playerControllers(PlayerState playerState, Size size) { - final processingState = playerState.processingState; - if (processingState == ProcessingState.loading || - processingState == ProcessingState.buffering) { - return Container( - margin: const EdgeInsets.all(8), - width: size.width * 0.08, - height: size.width * 0.08, - child: const CircularProgressIndicator( - valueColor: - AlwaysStoppedAnimation(Color.fromARGB(255, 0, 0, 0)), - ), - ); - } else if (audioPlayer!.playing != true) { - return IconButton( - icon: const Icon(MdiIcons.play), - iconSize: size.width * 0.1, - onPressed: play, - splashColor: Colors.transparent, - ); - } else if (processingState != ProcessingState.completed) { - return IconButton( - icon: const Icon(MdiIcons.pause), - iconSize: size.width * 0.1, - onPressed: pause, - splashColor: Colors.transparent, - ); - } else { - return IconButton( - icon: const Icon(MdiIcons.replay), - iconSize: size.width * 0.056, - onPressed: () => audioPlayer! - .seek(Duration.zero, index: audioPlayer!.effectiveIndices!.first), - ); - } - } } diff --git a/lib/ui/rootPage.dart b/lib/ui/rootPage.dart index 9792c98bf..5382dc5a8 100644 --- a/lib/ui/rootPage.dart +++ b/lib/ui/rootPage.dart @@ -111,7 +111,7 @@ class AppState extends State { mainAxisSize: MainAxisSize.min, children: [ StreamBuilder( - stream: audioPlayer!.sequenceStateStream, + stream: audioPlayer.sequenceStateStream, builder: (context, snapshot) { final state = snapshot.data; if (state?.sequence.isEmpty ?? true) { @@ -230,14 +230,13 @@ class AppState extends State { const Spacer(), Padding( padding: const EdgeInsets.only(right: 8), - child: StreamBuilder( - stream: audioPlayer!.playerStateStream, - builder: (context, snapshot) { - if (snapshot.hasData) { - final playerState = snapshot.data; - return _playerControllers( - playerState!, MediaQuery.of(context).size); - } else { + child: ValueListenableBuilder( + valueListenable: playerState, + builder: (_, value, __) { + if (value.processingState == + ProcessingState.loading || + value.processingState == + ProcessingState.buffering) { return Container( margin: const EdgeInsets.all(8), width: MediaQuery.of(context).size.width * 0.08, @@ -248,6 +247,29 @@ class AppState extends State { AlwaysStoppedAnimation(accent), ), ); + } else if (value.playing != true) { + return IconButton( + icon: Icon(MdiIcons.play, color: accent), + iconSize: 45, + onPressed: play, + splashColor: Colors.transparent, + ); + } else if (value.processingState != + ProcessingState.completed) { + return IconButton( + icon: Icon(MdiIcons.pause, color: accent), + iconSize: 45, + onPressed: pause, + splashColor: Colors.transparent, + ); + } else { + return IconButton( + icon: Icon(MdiIcons.replay, color: accent), + iconSize: 45, + onPressed: () => audioPlayer.seek(Duration.zero, + index: audioPlayer.effectiveIndices!.first), + splashColor: Colors.transparent, + ); } }, ), @@ -276,41 +298,4 @@ class AppState extends State { ), ); } - - Widget _playerControllers(PlayerState playerState, Size size) { - final processingState = playerState.processingState; - if (processingState == ProcessingState.loading || - processingState == ProcessingState.buffering) { - return Container( - margin: const EdgeInsets.all(8), - width: size.width * 0.08, - height: size.width * 0.08, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(accent), - ), - ); - } else if (audioPlayer!.playing != true) { - return IconButton( - icon: Icon(MdiIcons.play, color: accent), - iconSize: 45, - onPressed: play, - splashColor: Colors.transparent, - ); - } else if (processingState != ProcessingState.completed) { - return IconButton( - icon: Icon(MdiIcons.pause, color: accent), - iconSize: 45, - onPressed: pause, - splashColor: Colors.transparent, - ); - } else { - return IconButton( - icon: Icon(MdiIcons.replay, color: accent), - iconSize: 45, - onPressed: () => audioPlayer! - .seek(Duration.zero, index: audioPlayer!.effectiveIndices!.first), - splashColor: Colors.transparent, - ); - } - } } From 70c8a5bd0be1601487a14b3c1ce81bd33a6a69bd Mon Sep 17 00:00:00 2001 From: gokadzev Date: Sat, 20 Aug 2022 21:30:39 +0400 Subject: [PATCH 15/16] play next song and play random next song features are working now maybe there's possibility to improve function logic, i will see later --- lib/main.dart | 2 +- lib/services/audio_handler.dart | 43 ++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 7c6dea071..d38626f2a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -152,11 +152,11 @@ class _MyAppState extends State { void main() async { WidgetsFlutterBinding.ensureInitialized(); - await initialisation(); await Hive.initFlutter(); await Hive.openBox('settings'); await Hive.openBox('user'); await Hive.openBox('cache'); + await initialisation(); await getAlternateApiUrl(); runApp(const MyApp()); } diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index 1395e8449..7c29b9178 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -2,6 +2,7 @@ import 'package:audio_service/audio_service.dart'; import 'package:flutter/widgets.dart'; import 'package:just_audio/just_audio.dart'; import 'package:musify/API/musify.dart'; +import 'package:musify/helper/mediaitem.dart'; import 'package:musify/services/audio_manager.dart'; class MyAudioHandler extends BaseAudioHandler { @@ -14,6 +15,7 @@ class MyAudioHandler extends BaseAudioHandler { _listenForDurationChanges(); _listenForCurrentSongIndexChanges(); _listenForSequenceStateChanges(); + _listenForPositionChanges(); _listenProcessingStates(); } @@ -71,15 +73,6 @@ class MyAudioHandler extends BaseAudioHandler { if (state.processingState == ProcessingState.completed) { await pause(); await audioPlayer.seek(Duration.zero); - // if (hasNext) { - // await playSong(activePlaylist[id + 1]); - // id = id + 1; - // } - - // if (!hasNext && playNextSongAutomatically.value) { - // final randomSong = await getRandomSong(); - // await playSong(randomSong); - // } } }); } @@ -100,6 +93,38 @@ class MyAudioHandler extends BaseAudioHandler { }); } + bool canBeSkipped = false; + + void _listenForPositionChanges() { + audioPlayer.positionStream.listen((position) async { + if (playerState.value.processingState != ProcessingState.loading && + audioPlayer.duration != null && + position.inSeconds == audioPlayer.duration!.inSeconds - 5) { + if (!hasNext && playNextSongAutomatically.value) { + final randomSong = await getRandomSong(); + final randomSongUrl = await getSong(randomSong['ytid'], true); + await addQueueItem(mapToMediaItem(randomSong, randomSongUrl)); + } + } else if (playerState.value.processingState != ProcessingState.loading && + audioPlayer.duration != null && + position.inSeconds == audioPlayer.duration!.inSeconds - 1) { + canBeSkipped = true; + } else if (playerState.value.processingState != ProcessingState.loading && + audioPlayer.duration != null && + position.inSeconds == audioPlayer.duration!.inSeconds) { + if (canBeSkipped && hasNext) { + await skipToNext(); + canBeSkipped = false; + } else if (canBeSkipped && + !hasNext && + playNextSongAutomatically.value) { + await play(); + canBeSkipped = false; + } + } + }); + } + void _listenForCurrentSongIndexChanges() { audioPlayer.currentIndexStream.listen((index) { final List playlist = queue.value; From 5ea0b2f0321c10271cec68ab19eba69b67b7d9f9 Mon Sep 17 00:00:00 2001 From: gokadzev Date: Sun, 21 Aug 2022 09:59:53 +0400 Subject: [PATCH 16/16] improved code --- analysis_options.yaml | 6 + lib/API/musify.dart | 58 +++-- .../custom_animated_bottom_bar.dart | 4 +- lib/customWidgets/delayed_display.dart | 22 +- lib/customWidgets/setting_bar.dart | 4 +- lib/customWidgets/song_bar.dart | 16 +- lib/customWidgets/spinner.dart | 2 +- lib/helper/material_color_creator.dart | 8 +- lib/helper/version.dart | 5 +- lib/main.dart | 22 +- lib/services/audio_handler.dart | 57 ++--- lib/services/audio_manager.dart | 22 +- lib/services/data_manager.dart | 23 +- lib/services/download_manager.dart | 15 +- lib/services/ext_storage.dart | 2 +- lib/ui/aboutPage.dart | 4 +- lib/ui/homePage.dart | 20 +- lib/ui/localSongsPage.dart | 213 +++++++++--------- lib/ui/player.dart | 112 ++++----- lib/ui/playlistPage.dart | 13 +- lib/ui/playlistsPage.dart | 12 +- lib/ui/rootPage.dart | 8 +- lib/ui/searchPage.dart | 56 +++-- lib/ui/settingsPage.dart | 10 +- lib/ui/userLikedSongsPage.dart | 9 +- lib/ui/userPlaylistsPage.dart | 4 +- 26 files changed, 394 insertions(+), 333 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 9ac9620e8..af3b8bcd2 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -43,6 +43,7 @@ linter: - non_constant_identifier_names - noop_primitive_operations - null_closures + - omit_local_variable_types - overridden_fields - package_api_docs - package_names @@ -64,9 +65,13 @@ linter: - prefer_single_quotes - prefer_typing_uninitialized_variables - recursive_getters + - require_trailing_commas - sized_box_for_whitespace - slash_for_doc_comments - sort_child_properties_last + - sort_constructors_first + - sort_pub_dependencies + - sort_unnamed_constructors_first - test_types_in_equals - throw_in_finally - type_init_formals @@ -88,5 +93,6 @@ linter: - use_is_even_rather_than_modulo - use_named_constants - use_rethrow_when_possible + - use_super_parameters - valid_regexps - void_checks \ No newline at end of file diff --git a/lib/API/musify.dart b/lib/API/musify.dart index ecad67007..169a99791 100644 --- a/lib/API/musify.dart +++ b/lib/API/musify.dart @@ -60,7 +60,7 @@ Future get10Music(dynamic playlistid) async { final List playlistSongs = await getData('cache', 'playlist10Songs$playlistid') ?? []; if (playlistSongs.isEmpty) { - int index = 0; + var index = 0; await for (final song in yt.playlists.getVideos(playlistid).take(10)) { playlistSongs.add( returnSongLayout( @@ -156,8 +156,10 @@ Future searchPlaylist(String query) async { } return playlists - .where((playlist) => - playlist['title'].toLowerCase().contains(query.toLowerCase())) + .where( + (playlist) => + playlist['title'].toLowerCase().contains(query.toLowerCase()), + ) .toList(); } @@ -172,7 +174,7 @@ Future getSongsFromPlaylist(dynamic playlistid) async { final List playlistSongs = await getData('cache', 'playlistSongs$playlistid') ?? []; if (playlistSongs.isEmpty) { - int index = 0; + var index = 0; await for (final song in yt.playlists.getVideos(playlistid)) { playlistSongs.add( returnSongLayout( @@ -199,7 +201,7 @@ Future setActivePlaylist(List plist) async { if (plist is List) { activePlaylist = []; id = 0; - final List activeTempPlaylist = [ + final activeTempPlaylist = [ for (final song in plist) songModelToMediaItem(song, song.data) ]; @@ -258,7 +260,8 @@ Future> getLocalSongs() async { localSongs = [ ...await _audioQuery.querySongs(uriType: UriType.EXTERNAL), ...await _audioQuery.querySongs( - path: await ExtStorageProvider.getExtStorage(dirName: 'Musify')) + path: await ExtStorageProvider.getExtStorage(dirName: 'Musify'), + ) ]; } @@ -267,23 +270,25 @@ Future> getLocalSongs() async { Future>> getSkipSegments(String id) async { try { - final res = await http.get(Uri( - scheme: 'https', - host: 'sponsor.ajay.app', - path: '/api/skipSegments', - queryParameters: { - 'videoID': id, - 'category': [ - 'sponsor', - 'selfpromo', - 'interaction', - 'intro', - 'outro', - 'music_offtopic' - ], - 'actionType': 'skip' - }, - )); + final res = await http.get( + Uri( + scheme: 'https', + host: 'sponsor.ajay.app', + path: '/api/skipSegments', + queryParameters: { + 'videoID': id, + 'category': [ + 'sponsor', + 'selfpromo', + 'interaction', + 'intro', + 'outro', + 'music_offtopic' + ], + 'actionType': 'skip' + }, + ), + ); if (res.body != 'Not Found') { final data = jsonDecode(res.body); final segments = data.map((obj) { @@ -341,8 +346,11 @@ Future getSongLyrics(String artist, String title) async { final lyricsResponse = await json.decode(response.body); if (lyricsResponse['lyrics'] != null) { lyrics.value = lyricsResponse['lyrics'].toString(); - addOrUpdateData('cache', 'lyrics-$artist-$title', - lyricsResponse['lyrics'].toString()); + addOrUpdateData( + 'cache', + 'lyrics-$artist-$title', + lyricsResponse['lyrics'].toString(), + ); } else { lyrics.value = 'not found'; } diff --git a/lib/customWidgets/custom_animated_bottom_bar.dart b/lib/customWidgets/custom_animated_bottom_bar.dart index eaeaf7bc1..24b88e451 100644 --- a/lib/customWidgets/custom_animated_bottom_bar.dart +++ b/lib/customWidgets/custom_animated_bottom_bar.dart @@ -3,7 +3,7 @@ import 'package:musify/ui/rootPage.dart'; class CustomAnimatedBottomBar extends StatelessWidget { CustomAnimatedBottomBar({ - Key? key, + super.key, this.showElevation = true, this.onTap, this.selectedItemColor, @@ -17,7 +17,7 @@ class CustomAnimatedBottomBar extends StatelessWidget { this.curve = Curves.easeOutQuint, this.radius = BorderRadius.zero, required this.items, - }) : super(key: key); + }); final Color? backgroundColor; final bool showElevation; final List items; diff --git a/lib/customWidgets/delayed_display.dart b/lib/customWidgets/delayed_display.dart index 67bdeff98..39e863a50 100644 --- a/lib/customWidgets/delayed_display.dart +++ b/lib/customWidgets/delayed_display.dart @@ -5,6 +5,16 @@ import 'dart:async'; import 'package:flutter/material.dart'; class DelayedDisplay extends StatefulWidget { + /// DelayedDisplay constructor + const DelayedDisplay({ + required this.child, + this.delay = Duration.zero, + this.fadingDuration = const Duration(milliseconds: 800), + this.slidingCurve = Curves.decelerate, + this.slidingBeginOffset = const Offset(0, 0.35), + this.fadeIn = true, + }); + /// Child that will be displayed with the animation and delay final Widget child; @@ -23,16 +33,6 @@ class DelayedDisplay extends StatefulWidget { /// If true, make the child appear, disappear otherwise. Default to true. final bool fadeIn; - /// DelayedDisplay constructor - const DelayedDisplay({ - required this.child, - this.delay = Duration.zero, - this.fadingDuration = const Duration(milliseconds: 800), - this.slidingCurve = Curves.decelerate, - this.slidingBeginOffset = const Offset(0, 0.35), - this.fadeIn = true, - }); - @override _DelayedDisplayState createState() => _DelayedDisplayState(); } @@ -74,7 +74,7 @@ class _DelayedDisplayState extends State duration: opacityTransitionDuration, ); - final CurvedAnimation curvedAnimation = CurvedAnimation( + final curvedAnimation = CurvedAnimation( curve: slidingCurve, parent: _opacityController, ); diff --git a/lib/customWidgets/setting_bar.dart b/lib/customWidgets/setting_bar.dart index fe1c36bc6..e7e84ab09 100644 --- a/lib/customWidgets/setting_bar.dart +++ b/lib/customWidgets/setting_bar.dart @@ -2,12 +2,12 @@ import 'package:flutter/material.dart'; import 'package:musify/style/appColors.dart'; class SettingBar extends StatelessWidget { + SettingBar(this.tileName, this.tileIcon, this.onTap); + final Function() onTap; final String tileName; final IconData tileIcon; - SettingBar(this.tileName, this.tileIcon, this.onTap); - @override Widget build(BuildContext context) { return Padding( diff --git a/lib/customWidgets/song_bar.dart b/lib/customWidgets/song_bar.dart index d1fa0bf1b..63f79911d 100644 --- a/lib/customWidgets/song_bar.dart +++ b/lib/customWidgets/song_bar.dart @@ -7,7 +7,7 @@ import 'package:musify/services/download_manager.dart'; import 'package:musify/style/appColors.dart'; class SongBar extends StatelessWidget { - SongBar(this.song, this.moveBackAfterPlay, {Key? key}) : super(key: key); + SongBar(this.song, this.moveBackAfterPlay, {super.key}); late final dynamic song; late final bool moveBackAfterPlay; @@ -66,9 +66,10 @@ class SongBar extends StatelessWidget { .replaceAll('"', '"') .replaceAll('&', '&'), style: TextStyle( - color: accent, - fontSize: 16, - fontWeight: FontWeight.w700), + color: accent, + fontSize: 16, + fontWeight: FontWeight.w700, + ), ), ), const SizedBox( @@ -80,9 +81,10 @@ class SongBar extends StatelessWidget { overflow: TextOverflow.ellipsis, song['more_info']['singers'].toString(), style: const TextStyle( - color: Colors.white70, - fontWeight: FontWeight.w400, - fontSize: 14), + color: Colors.white70, + fontWeight: FontWeight.w400, + fontSize: 14, + ), ), ), ], diff --git a/lib/customWidgets/spinner.dart b/lib/customWidgets/spinner.dart index 892fdff52..47f05f0f7 100644 --- a/lib/customWidgets/spinner.dart +++ b/lib/customWidgets/spinner.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:musify/style/appColors.dart'; class Spinner extends StatelessWidget { - const Spinner({Key? key}) : super(key: key); + const Spinner({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/helper/material_color_creator.dart b/lib/helper/material_color_creator.dart index 0a83c7cd4..e722f486b 100644 --- a/lib/helper/material_color_creator.dart +++ b/lib/helper/material_color_creator.dart @@ -2,14 +2,14 @@ import 'package:flutter/material.dart'; MaterialColor createMaterialColor(Color color) { final List strengths = [.05]; - final Map swatch = {}; - final int r = color.red, g = color.green, b = color.blue; + final swatch = {}; + final r = color.red, g = color.green, b = color.blue; - for (int i = 1; i < 10; i++) { + for (var i = 1; i < 10; i++) { strengths.add(0.1 * i); } for (var strength in strengths) { - final double ds = 0.5 - strength; + final ds = 0.5 - strength; swatch[(strength * 1000).round()] = Color.fromRGBO( r + ((ds < 0 ? r : (255 - r)) * ds).round(), g + ((ds < 0 ? g : (255 - g)) * ds).round(), diff --git a/lib/helper/version.dart b/lib/helper/version.dart index bbe200989..e4248825a 100644 --- a/lib/helper/version.dart +++ b/lib/helper/version.dart @@ -33,9 +33,8 @@ Future downloadAppUpdates() async { } else { dlUrl = map['url'].toString(); } - final String? dlPath = - await ExtStorageProvider.getExtStorage(dirName: 'Download'); - final File file = File('${dlPath!}/Musify.apk'); + final dlPath = await ExtStorageProvider.getExtStorage(dirName: 'Download'); + final file = File('${dlPath!}/Musify.apk'); if (await file.exists()) { await file.delete(); } diff --git a/lib/main.dart b/lib/main.dart index d38626f2a..651a2073e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -20,16 +20,18 @@ GetIt getIt = GetIt.instance; bool _interrupted = false; class MyApp extends StatefulWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); static Future setLocale(BuildContext context, Locale newLocale) async { - final _MyAppState state = context.findAncestorStateOfType<_MyAppState>()!; + final state = context.findAncestorStateOfType<_MyAppState>()!; state.changeLanguage(newLocale); } static Future setAccentColor( - BuildContext context, Color newAccentColor) async { - final _MyAppState state = context.findAncestorStateOfType<_MyAppState>()!; + BuildContext context, + Color newAccentColor, + ) async { + final state = context.findAncestorStateOfType<_MyAppState>()!; state.changeAccentColor(newAccentColor); } @@ -56,7 +58,7 @@ class _MyAppState extends State { void initState() { super.initState(); getLocalSongs(); - final Map codes = { + final codes = { 'English': 'en', 'Georgian': 'ka', 'Chinese': 'zh', @@ -70,8 +72,10 @@ class _MyAppState extends State { 'Turkish': 'tr', 'Ukrainian': 'uk', }; - _locale = Locale(codes[Hive.box('settings') - .get('language', defaultValue: 'English') as String]!); + _locale = Locale( + codes[Hive.box('settings').get('language', defaultValue: 'English') + as String]!, + ); FlutterDownloader.registerCallback(downloadCallback); } @@ -184,7 +188,7 @@ Future initialisation() async { _interrupted = false; } }); - final AudioHandler audioHandler = await AudioService.init( + final audioHandler = await AudioService.init( builder: MyAudioHandler.new, config: const AudioServiceConfig( androidNotificationChannelId: 'com.gokadzev.musify', @@ -200,7 +204,7 @@ Future initialisation() async { debug: kDebugMode, ignoreSsl: true, ); - final PackageInfo packageInfo = await PackageInfo.fromPlatform(); + final packageInfo = await PackageInfo.fromPlatform(); version = packageInfo.version; } diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index 7c29b9178..2352f496f 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -6,9 +6,6 @@ import 'package:musify/helper/mediaitem.dart'; import 'package:musify/services/audio_manager.dart'; class MyAudioHandler extends BaseAudioHandler { - final ConcatenatingAudioSource _playlist = - ConcatenatingAudioSource(children: []); - MyAudioHandler() { _loadEmptyPlaylist(); _notifyAudioHandlerAboutPlaybackEvents(); @@ -18,6 +15,8 @@ class MyAudioHandler extends BaseAudioHandler { _listenForPositionChanges(); _listenProcessingStates(); } + final ConcatenatingAudioSource _playlist = + ConcatenatingAudioSource(children: []); Future _loadEmptyPlaylist() async { try { @@ -29,7 +28,7 @@ class MyAudioHandler extends BaseAudioHandler { void _notifyAudioHandlerAboutPlaybackEvents() { audioPlayer.playbackEventStream.listen((PlaybackEvent event) { - final bool playing = audioPlayer.playing; + final playing = audioPlayer.playing; playbackState.add( playbackState.value.copyWith( controls: [ @@ -80,13 +79,13 @@ class MyAudioHandler extends BaseAudioHandler { void _listenForDurationChanges() { audioPlayer.durationStream.listen((duration) { var index = audioPlayer.currentIndex; - final List newQueue = queue.value; + final newQueue = queue.value; if (index == null || newQueue.isEmpty) return; if (audioPlayer.shuffleModeEnabled) { index = audioPlayer.shuffleIndices![index]; } - final MediaItem oldMediaItem = newQueue[index]; - final MediaItem newMediaItem = oldMediaItem.copyWith(duration: duration); + final oldMediaItem = newQueue[index]; + final newMediaItem = oldMediaItem.copyWith(duration: duration); newQueue[index] = newMediaItem; queue.add(newQueue); mediaItem.add(newMediaItem); @@ -127,7 +126,7 @@ class MyAudioHandler extends BaseAudioHandler { void _listenForCurrentSongIndexChanges() { audioPlayer.currentIndexStream.listen((index) { - final List playlist = queue.value; + final playlist = queue.value; if (index == null || playlist.isEmpty) return; if (audioPlayer.shuffleModeEnabled) { index = audioPlayer.shuffleIndices![index]; @@ -177,33 +176,39 @@ class MyAudioHandler extends BaseAudioHandler { ); } - ClippingAudioSource _createClippingAudioSource(MediaItem mediaItem, - [start, end]) { + ClippingAudioSource _createClippingAudioSource( + MediaItem mediaItem, [ + start, + end, + ]) { if (start != null && end == null) { return ClippingAudioSource( - start: start, + start: start, + tag: mediaItem, + child: AudioSource.uri( + Uri.parse(mediaItem.extras!['url'].toString()), tag: mediaItem, - child: AudioSource.uri( - Uri.parse(mediaItem.extras!['url'].toString()), - tag: mediaItem, - )); + ), + ); } else if (end != null && start == null) { return ClippingAudioSource( - end: end, + end: end, + tag: mediaItem, + child: AudioSource.uri( + Uri.parse(mediaItem.extras!['url'].toString()), tag: mediaItem, - child: AudioSource.uri( - Uri.parse(mediaItem.extras!['url'].toString()), - tag: mediaItem, - )); + ), + ); } else { return ClippingAudioSource( - start: start, - end: end, + start: start, + end: end, + tag: mediaItem, + child: AudioSource.uri( + Uri.parse(mediaItem.extras!['url'].toString()), tag: mediaItem, - child: AudioSource.uri( - Uri.parse(mediaItem.extras!['url'].toString()), - tag: mediaItem, - )); + ), + ); } } diff --git a/lib/services/audio_manager.dart b/lib/services/audio_manager.dart index a218601c3..a27c88690 100644 --- a/lib/services/audio_manager.dart +++ b/lib/services/audio_manager.dart @@ -29,11 +29,14 @@ final shuffleNotifier = ValueNotifier(false); final repeatNotifier = ValueNotifier(false); final playerState = ValueNotifier(audioPlayer.playerState); final prefferedFileExtension = ValueNotifier( - Hive.box('settings').get('audioFileType', defaultValue: 'mp3') as String); + Hive.box('settings').get('audioFileType', defaultValue: 'mp3') as String, +); final playNextSongAutomatically = ValueNotifier( - Hive.box('settings').get('playNextSongAutomatically', defaultValue: false)); + Hive.box('settings').get('playNextSongAutomatically', defaultValue: false), +); final sponsorBlockSupport = ValueNotifier( - Hive.box('settings').get('sponsorBlockSupport', defaultValue: false)); + Hive.box('settings').get('sponsorBlockSupport', defaultValue: false), +); bool get hasNext => activePlaylist.isEmpty ? audioPlayer.hasNext @@ -61,13 +64,16 @@ Future playSong(Map song) async { final segments = await getSkipSegments(song['ytid']); if (segments.isNotEmpty) { if (segments.length == 1) { - await MyAudioHandler().addQueueItem(mapToMediaItem(song, songUrl), - Duration(seconds: segments[0]['end']!)); + await MyAudioHandler().addQueueItem( + mapToMediaItem(song, songUrl), + Duration(seconds: segments[0]['end']!), + ); } else { await MyAudioHandler().addQueueItem( - mapToMediaItem(song, songUrl), - Duration(seconds: segments[0]['end']!), - Duration(seconds: segments[1]['start']!)); + mapToMediaItem(song, songUrl), + Duration(seconds: segments[0]['end']!), + Duration(seconds: segments[1]['start']!), + ); } } else { await MyAudioHandler().addQueueItem(mapToMediaItem(song, songUrl)); diff --git a/lib/services/data_manager.dart b/lib/services/data_manager.dart index ae9250957..5a10cee6c 100644 --- a/lib/services/data_manager.dart +++ b/lib/services/data_manager.dart @@ -37,20 +37,19 @@ void clearCache() async { } Future backupData() async { - final List boxNames = ['user', 'settings']; - final String? dlPath = - await ExtStorageProvider.getExtStorage(dirName: 'Musify/Data'); + final boxNames = ['user', 'settings']; + final dlPath = await ExtStorageProvider.getExtStorage(dirName: 'Musify/Data'); - for (int i = 0; i < boxNames.length; i++) { - await Hive.openBox(boxNames[i].toString()); + for (var i = 0; i < boxNames.length; i++) { + await Hive.openBox(boxNames[i]); try { - await File(Hive.box(boxNames[i].toString()).path!) + await File(Hive.box(boxNames[i]).path!) .copy('$dlPath/${boxNames[i]}Data.hive'); } catch (e) { await [ Permission.manageExternalStorage, ].request(); - await File(Hive.box(boxNames[i].toString()).path!) + await File(Hive.box(boxNames[i]).path!) .copy('$dlPath/${boxNames[i]}Data.hive'); return 'Permissions problem, if you already gave requested permission, Backup data again!'; } @@ -59,14 +58,14 @@ Future backupData() async { } Future restoreData() async { - final List boxNames = ['user', 'settings']; - final String? uplPath = + final boxNames = ['user', 'settings']; + final uplPath = await ExtStorageProvider.getExtStorage(dirName: 'Musify/Data'); - for (int i = 0; i < boxNames.length; i++) { - await Hive.openBox(boxNames[i].toString()); + for (var i = 0; i < boxNames.length; i++) { + await Hive.openBox(boxNames[i]); try { - final Box box = await Hive.openBox(boxNames[i].toString()); + final box = await Hive.openBox(boxNames[i]); final boxPath = box.path; await File('${uplPath!}/${boxNames[i]}Data.hive').copy(boxPath!); } catch (e) { diff --git a/lib/services/download_manager.dart b/lib/services/download_manager.dart index 6be32dadf..66a759107 100644 --- a/lib/services/download_manager.dart +++ b/lib/services/download_manager.dart @@ -10,7 +10,7 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; Future downloadSong(dynamic song) async { - PermissionStatus status = await Permission.storage.status; + var status = await Permission.storage.status; if (status.isDenied) { await [ Permission.storage, @@ -44,9 +44,8 @@ Future downloadSong(dynamic song) async { '.' + prefferedFileExtension.value; - String filepath = ''; - final String? dlPath = - await ExtStorageProvider.getExtStorage(dirName: 'Musify'); + var filepath = ''; + final dlPath = await ExtStorageProvider.getExtStorage(dirName: 'Musify'); try { await File('${dlPath!}/$filename') .create(recursive: true) @@ -71,9 +70,13 @@ Future downloadSong(dynamic song) async { } Future downloadFileFromYT( - String filename, String filepath, String dlPath, dynamic song) async { + String filename, + String filepath, + String dlPath, + dynamic song, +) async { final audioStream = await getSong(song['ytid'].toString(), false); - final File file = File(filepath); + final file = File(filepath); final fileStream = file.openWrite(); await yt.videos.streamsClient.get(audioStream as StreamInfo).pipe(fileStream); await fileStream.flush(); diff --git a/lib/services/ext_storage.dart b/lib/services/ext_storage.dart index eea1eb16f..8ea5571e3 100644 --- a/lib/services/ext_storage.dart +++ b/lib/services/ext_storage.dart @@ -29,7 +29,7 @@ class ExtStorageProvider { directory = await getExternalStorageDirectory(); // getting main path - final String newPath = directory!.path + final newPath = directory!.path .replaceFirst('Android/data/com.gokadzev.musify/files', dirName); directory = Directory(newPath); diff --git a/lib/ui/aboutPage.dart b/lib/ui/aboutPage.dart index 212b8e7fa..b0a6fb534 100644 --- a/lib/ui/aboutPage.dart +++ b/lib/ui/aboutPage.dart @@ -4,7 +4,7 @@ import 'package:musify/helper/version.dart'; import 'package:musify/style/appColors.dart'; class AboutPage extends StatelessWidget { - const AboutPage({Key? key}) : super(key: key); + const AboutPage({super.key}); @override Widget build(BuildContext context) { @@ -35,7 +35,7 @@ class AboutPage extends StatelessWidget { } class AboutCards extends StatelessWidget { - const AboutCards({Key? key}) : super(key: key); + const AboutCards({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/ui/homePage.dart b/lib/ui/homePage.dart index 9c2b3f20d..a6945c201 100644 --- a/lib/ui/homePage.dart +++ b/lib/ui/homePage.dart @@ -102,17 +102,19 @@ class _HomePageState extends State { if (data.hasError) { // print(data.error); return Center( - child: Text( - 'Error!', - style: TextStyle(color: accent, fontSize: 18), - )); + child: Text( + 'Error!', + style: TextStyle(color: accent, fontSize: 18), + ), + ); } if (!data.hasData) { return Center( - child: Text( - 'Nothing Found!', - style: TextStyle(color: accent, fontSize: 18), - )); + child: Text( + 'Nothing Found!', + style: TextStyle(color: accent, fontSize: 18), + ), + ); } return Wrap( children: [ @@ -171,7 +173,7 @@ class CubeContainer extends StatelessWidget { @override Widget build(BuildContext context) { - final Size size = MediaQuery.of(context).size; + final size = MediaQuery.of(context).size; return DelayedDisplay( delay: const Duration(milliseconds: 200), fadingDuration: const Duration(milliseconds: 400), diff --git a/lib/ui/localSongsPage.dart b/lib/ui/localSongsPage.dart index 089f93e8e..55249c224 100644 --- a/lib/ui/localSongsPage.dart +++ b/lib/ui/localSongsPage.dart @@ -56,10 +56,10 @@ class _LocalSongsPageState extends State { Future fetch() async { final list = []; - final int _count = localSongs.length; + final _count = localSongs.length; final n = min(_itemsPerPage, _count - _currentPage * _itemsPerPage); await Future.delayed(const Duration(seconds: 1), () { - for (int i = 0; i < n; i++) { + for (var i = 0; i < n; i++) { list.add(localSongs[_currentLastLoadedId]); _currentLastLoadedId++; } @@ -165,9 +165,10 @@ class _LocalSongsPageState extends State { child: Text( AppLocalizations.of(context)!.playAll.toUpperCase(), style: TextStyle( - color: accent != const Color(0xFFFFFFFF) - ? Colors.white - : Colors.black), + color: accent != const Color(0xFFFFFFFF) + ? Colors.white + : Colors.black, + ), ), ), ], @@ -177,111 +178,115 @@ class _LocalSongsPageState extends State { ), const Padding(padding: EdgeInsets.only(top: 40)), FutureBuilder( - future: getLocalSongs(), - builder: (context, data) { - return data.hasData - ? ListView.builder( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - addAutomaticKeepAlives: - false, // may be problem with lazyload if it implemented - addRepaintBoundaries: false, - // Need to display a loading tile if more items are coming - itemCount: _hasMore - ? _songsList.length + 1 - : _songsList.length, - itemBuilder: (BuildContext context, int index) { - if (index >= _songsList.length) { - if (!_isLoading) { - _loadMore(); - } - return const Spinner(); + future: getLocalSongs(), + builder: (context, data) { + return data.hasData + ? ListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + addAutomaticKeepAlives: + false, // may be problem with lazyload if it implemented + addRepaintBoundaries: false, + // Need to display a loading tile if more items are coming + itemCount: _hasMore + ? _songsList.length + 1 + : _songsList.length, + itemBuilder: (BuildContext context, int index) { + if (index >= _songsList.length) { + if (!_isLoading) { + _loadMore(); } + return const Spinner(); + } - final lsong = { - 'id': index, - 'ytid': '', - 'title': localSongs[index].displayName, - 'image': '', - 'lowResImage': '', - 'highResImage': '', - 'songUrl': localSongs[index].data, - 'album': '', - 'type': 'song', - 'localSongId': localSongs[index].id, - 'more_info': { - 'primary_artists': '', - 'singers': '', - } - }; + final lsong = { + 'id': index, + 'ytid': '', + 'title': localSongs[index].displayName, + 'image': '', + 'lowResImage': '', + 'highResImage': '', + 'songUrl': localSongs[index].data, + 'album': '', + 'type': 'song', + 'localSongId': localSongs[index].id, + 'more_info': { + 'primary_artists': '', + 'singers': '', + } + }; - return Container( - padding: const EdgeInsets.only( - left: 12, right: 12, bottom: 15), - child: InkWell( - borderRadius: BorderRadius.circular(20), - onTap: () { - playSong(lsong); - }, - splashColor: accent, - hoverColor: accent, - focusColor: accent, - highlightColor: accent, - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - QueryArtworkWidget( - id: lsong['localSongId'] as int, - type: ArtworkType.AUDIO, - artworkWidth: 70, - artworkHeight: 70, - artworkFit: BoxFit.cover, - artworkBorder: - BorderRadius.circular(8), - nullArtworkWidget: DecoratedBox( - decoration: BoxDecoration( - color: accent, - borderRadius: - BorderRadius.circular(8)), - child: Icon( - MdiIcons.musicNoteOutline, - size: 70, - color: accent != - const Color(0xFFFFFFFF) - ? Colors.white - : Colors.black, - ), - ), - keepOldArtwork: true, + return Container( + padding: const EdgeInsets.only( + left: 12, + right: 12, + bottom: 15, + ), + child: InkWell( + borderRadius: BorderRadius.circular(20), + onTap: () { + playSong(lsong); + }, + splashColor: accent, + hoverColor: accent, + focusColor: accent, + highlightColor: accent, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + QueryArtworkWidget( + id: lsong['localSongId'] as int, + type: ArtworkType.AUDIO, + artworkWidth: 70, + artworkHeight: 70, + artworkFit: BoxFit.cover, + artworkBorder: BorderRadius.circular(8), + nullArtworkWidget: DecoratedBox( + decoration: BoxDecoration( + color: accent, + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + MdiIcons.musicNoteOutline, + size: 70, + color: accent != const Color(0xFFFFFFFF) + ? Colors.white + : Colors.black, + ), + ), + keepOldArtwork: true, + ), + Flexible( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only( + left: 15, ), - Flexible( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Container( - alignment: - Alignment.centerLeft, - padding: - const EdgeInsets.only( - left: 15), - child: Text( - overflow: - TextOverflow.ellipsis, - lsong['title'].toString(), - style: TextStyle( - color: accent), - ), - ), - ], + child: Text( + overflow: TextOverflow.ellipsis, + lsong['title'].toString(), + style: TextStyle( + color: accent, ), ), - ]))); - }, - ) - : const Spinner(); - }) + ), + ], + ), + ), + ], + ), + ), + ); + }, + ) + : const Spinner(); + }, + ) ], ), ), diff --git a/lib/ui/player.dart b/lib/ui/player.dart index d319be99b..83a47409c 100644 --- a/lib/ui/player.dart +++ b/lib/ui/player.dart @@ -193,7 +193,9 @@ class AudioAppState extends State { ), Padding( padding: EdgeInsets.only( - top: size.height * 0.04, bottom: size.height * 0.01), + top: size.height * 0.04, + bottom: size.height * 0.01, + ), child: Column( children: [ Text( @@ -306,17 +308,18 @@ class AudioAppState extends State { }, ), IconButton( - padding: EdgeInsets.zero, - icon: Icon( - sponsorBlockSupport.value - ? MdiIcons.playCircle - : MdiIcons.playCircleOutline, - color: Colors.white, - ), - iconSize: size.width * 0.056, - splashColor: Colors.transparent, - onPressed: () => - setState(changeSponsorBlockStatus)), + padding: EdgeInsets.zero, + icon: Icon( + sponsorBlockSupport.value + ? MdiIcons.playCircle + : MdiIcons.playCircleOutline, + color: Colors.white, + ), + iconSize: size.width * 0.056, + splashColor: Colors.transparent, + onPressed: () => + setState(changeSponsorBlockStatus), + ), ], ), IconButton( @@ -347,47 +350,49 @@ class AudioAppState extends State { borderRadius: BorderRadius.circular(100), ), child: ValueListenableBuilder( - valueListenable: playerState, - builder: (_, value, __) { - if (value.processingState == - ProcessingState.loading || - value.processingState == - ProcessingState.buffering) { - return Container( - margin: const EdgeInsets.all(8), - width: size.width * 0.08, - height: size.width * 0.08, - child: const CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Color.fromARGB(255, 0, 0, 0)), + valueListenable: playerState, + builder: (_, value, __) { + if (value.processingState == + ProcessingState.loading || + value.processingState == + ProcessingState.buffering) { + return Container( + margin: const EdgeInsets.all(8), + width: size.width * 0.08, + height: size.width * 0.08, + child: const CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + Color.fromARGB(255, 0, 0, 0), ), - ); - } else if (value.playing != true) { - return IconButton( - icon: const Icon(MdiIcons.play), - iconSize: size.width * 0.1, - onPressed: play, - splashColor: Colors.transparent, - ); - } else if (value.processingState != - ProcessingState.completed) { - return IconButton( - icon: const Icon(MdiIcons.pause), - iconSize: size.width * 0.1, - onPressed: pause, - splashColor: Colors.transparent, - ); - } else { - return IconButton( - icon: const Icon(MdiIcons.replay), - iconSize: size.width * 0.056, - onPressed: () => audioPlayer.seek( - Duration.zero, - index: audioPlayer - .effectiveIndices!.first), - ); - } - }), + ), + ); + } else if (value.playing != true) { + return IconButton( + icon: const Icon(MdiIcons.play), + iconSize: size.width * 0.1, + onPressed: play, + splashColor: Colors.transparent, + ); + } else if (value.processingState != + ProcessingState.completed) { + return IconButton( + icon: const Icon(MdiIcons.pause), + iconSize: size.width * 0.1, + onPressed: pause, + splashColor: Colors.transparent, + ); + } else { + return IconButton( + icon: const Icon(MdiIcons.replay), + iconSize: size.width * 0.056, + onPressed: () => audioPlayer.seek( + Duration.zero, + index: audioPlayer.effectiveIndices!.first, + ), + ); + } + }, + ), ), IconButton( padding: EdgeInsets.zero, @@ -553,7 +558,8 @@ class AudioAppState extends State { ); } else if (value == 'null') { return const SizedBox( - child: Spinner()); + child: Spinner(), + ); } else { return Padding( padding: const EdgeInsets.only( diff --git a/lib/ui/playlistPage.dart b/lib/ui/playlistPage.dart index ce4b415a2..ddd7700b3 100644 --- a/lib/ui/playlistPage.dart +++ b/lib/ui/playlistPage.dart @@ -11,7 +11,7 @@ import 'package:musify/customWidgets/spinner.dart'; import 'package:musify/style/appColors.dart'; class PlaylistPage extends StatefulWidget { - const PlaylistPage({Key? key, required this.playlist}) : super(key: key); + const PlaylistPage({super.key, required this.playlist}); final dynamic playlist; @override @@ -60,10 +60,10 @@ class _PlaylistPageState extends State { Future fetch() async { final list = []; - final int _count = widget.playlist['list'].length as int; + final _count = widget.playlist['list'].length as int; final n = min(_itemsPerPage, _count - _currentPage * _itemsPerPage); await Future.delayed(const Duration(seconds: 1), () { - for (int i = 0; i < n; i++) { + for (var i = 0; i < n; i++) { list.add(widget.playlist['list'][_currentLastLoadedId]); _currentLastLoadedId++; } @@ -198,9 +198,10 @@ class _PlaylistPageState extends State { child: Text( AppLocalizations.of(context)!.playAll.toUpperCase(), style: TextStyle( - color: accent != const Color(0xFFFFFFFF) - ? Colors.white - : Colors.black), + color: accent != const Color(0xFFFFFFFF) + ? Colors.white + : Colors.black, + ), ), ), ], diff --git a/lib/ui/playlistsPage.dart b/lib/ui/playlistsPage.dart index 79e0eeac8..a02770efa 100644 --- a/lib/ui/playlistsPage.dart +++ b/lib/ui/playlistsPage.dart @@ -48,7 +48,11 @@ class _PlaylistsPageState extends State { children: [ Padding( padding: const EdgeInsets.only( - top: 12, bottom: 20, left: 12, right: 12), + top: 12, + bottom: 20, + left: 12, + right: 12, + ), child: TextField( onSubmitted: (String value) { search(); @@ -190,12 +194,12 @@ class _PlaylistsPageState extends State { class GetPlaylist extends StatelessWidget { const GetPlaylist({ - Key? key, + super.key, required this.index, required this.image, required this.title, required this.id, - }) : super(key: key); + }); final int index; final dynamic image; final String title; @@ -203,7 +207,7 @@ class GetPlaylist extends StatelessWidget { @override Widget build(BuildContext context) { - final Size size = MediaQuery.of(context).size; + final size = MediaQuery.of(context).size; return DelayedDisplay( delay: const Duration(milliseconds: 200), fadingDuration: const Duration(milliseconds: 400), diff --git a/lib/ui/rootPage.dart b/lib/ui/rootPage.dart index 5382dc5a8..c9146995a 100644 --- a/lib/ui/rootPage.dart +++ b/lib/ui/rootPage.dart @@ -69,7 +69,7 @@ class AppState extends State { } Widget getFooter() { - final List items = [ + final items = [ BottomNavBarItem( icon: const Icon(MdiIcons.homeOutline), activeIcon: const Icon(MdiIcons.home), @@ -266,8 +266,10 @@ class AppState extends State { return IconButton( icon: Icon(MdiIcons.replay, color: accent), iconSize: 45, - onPressed: () => audioPlayer.seek(Duration.zero, - index: audioPlayer.effectiveIndices!.first), + onPressed: () => audioPlayer.seek( + Duration.zero, + index: audioPlayer.effectiveIndices!.first, + ), splashColor: Colors.transparent, ); } diff --git a/lib/ui/searchPage.dart b/lib/ui/searchPage.dart index 9395dcdb1..2285fc65b 100644 --- a/lib/ui/searchPage.dart +++ b/lib/ui/searchPage.dart @@ -20,7 +20,7 @@ class _SearchPageState extends State { final FocusNode _inputNode = FocusNode(); Future search() async { - final String searchQuery = _searchBar.text; + final searchQuery = _searchBar.text; if (searchQuery.isEmpty) { setState(() { searchedList = []; @@ -88,30 +88,36 @@ class _SearchPageState extends State { borderSide: BorderSide(color: accent), ), suffixIcon: ValueListenableBuilder( - valueListenable: _fetchingSongs, - builder: (_, value, __) { - if (value == true) { - return IconButton( - icon: const SizedBox( - height: 18, width: 18, child: Spinner()), - color: accent, - onPressed: () { - search(); - FocusManager.instance.primaryFocus?.unfocus(); - }); - } else { - return IconButton( - icon: Icon( - Icons.search, - color: accent, - ), - color: accent, - onPressed: () { - search(); - FocusManager.instance.primaryFocus?.unfocus(); - }); - } - }), + valueListenable: _fetchingSongs, + builder: (_, value, __) { + if (value == true) { + return IconButton( + icon: const SizedBox( + height: 18, + width: 18, + child: Spinner(), + ), + color: accent, + onPressed: () { + search(); + FocusManager.instance.primaryFocus?.unfocus(); + }, + ); + } else { + return IconButton( + icon: Icon( + Icons.search, + color: accent, + ), + color: accent, + onPressed: () { + search(); + FocusManager.instance.primaryFocus?.unfocus(); + }, + ); + } + }, + ), border: InputBorder.none, hintText: '${AppLocalizations.of(context)!.search}...', hintStyle: TextStyle( diff --git a/lib/ui/settingsPage.dart b/lib/ui/settingsPage.dart index 80c7fd95b..ec26dd368 100644 --- a/lib/ui/settingsPage.dart +++ b/lib/ui/settingsPage.dart @@ -53,7 +53,7 @@ class SettingsCards extends StatelessWidget { backgroundColor: Colors.transparent, context: context, builder: (BuildContext context) { - final List colors = [ + final colors = [ 0xFFFFFFFF, 0xFFFFCDD2, 0xFFF8BBD0, @@ -124,7 +124,9 @@ class SettingsCards extends StatelessWidget { colors[index], ); MyApp.setAccentColor( - context, Color(colors[index])); + context, + Color(colors[index]), + ); Fluttertoast.showToast( backgroundColor: accent, textColor: @@ -172,7 +174,7 @@ class SettingsCards extends StatelessWidget { backgroundColor: Colors.transparent, context: context, builder: (BuildContext context) { - final Map codes = { + final codes = { 'English': 'en', 'Georgian': 'ka', 'Chinese': 'zh', @@ -187,7 +189,7 @@ class SettingsCards extends StatelessWidget { 'Ukrainian': 'uk', }; - final List availableLanguages = [ + final availableLanguages = [ 'English', 'Georgian', 'Chinese', diff --git a/lib/ui/userLikedSongsPage.dart b/lib/ui/userLikedSongsPage.dart index 0bd80b1f6..935e056e0 100644 --- a/lib/ui/userLikedSongsPage.dart +++ b/lib/ui/userLikedSongsPage.dart @@ -6,7 +6,7 @@ import 'package:musify/customWidgets/song_bar.dart'; import 'package:musify/style/appColors.dart'; class UserLikedSongs extends StatefulWidget { - const UserLikedSongs({Key? key}) : super(key: key); + const UserLikedSongs({super.key}); @override State createState() => _UserLikedSongsState(); @@ -119,9 +119,10 @@ class _UserLikedSongsState extends State { child: Text( AppLocalizations.of(context)!.playAll.toUpperCase(), style: TextStyle( - color: accent != const Color(0xFFFFFFFF) - ? Colors.white - : Colors.black), + color: accent != const Color(0xFFFFFFFF) + ? Colors.white + : Colors.black, + ), ), ), ], diff --git a/lib/ui/userPlaylistsPage.dart b/lib/ui/userPlaylistsPage.dart index 2be83876a..6f5da1c4b 100644 --- a/lib/ui/userPlaylistsPage.dart +++ b/lib/ui/userPlaylistsPage.dart @@ -6,7 +6,7 @@ import 'package:musify/style/appColors.dart'; import 'package:musify/ui/playlistsPage.dart'; class UserPlaylistsPage extends StatefulWidget { - const UserPlaylistsPage({Key? key}) : super(key: key); + const UserPlaylistsPage({super.key}); @override State createState() => _UserPlaylistsPageState(); @@ -40,7 +40,7 @@ class _UserPlaylistsPageState extends State { showDialog( context: context, builder: (BuildContext context) { - String id = ''; + var id = ''; return AlertDialog( backgroundColor: accent, content: Stack(