From af841de27b0d7eccf707f01d997700fa6969ebd5 Mon Sep 17 00:00:00 2001 From: MSOB7YY Date: Thu, 21 Mar 2024 12:39:23 +0200 Subject: [PATCH] chore: refactor & tweaks --- lib/base/audio_handler.dart | 22 ++-- lib/base/ports_provider.dart | 8 +- lib/controller/search_sort_controller.dart | 7 +- lib/controller/video_controller.dart | 7 +- lib/ui/pages/albums_page.dart | 2 +- lib/ui/pages/artists_page.dart | 2 +- lib/ui/pages/genres_page.dart | 2 +- lib/ui/pages/playlists_page.dart | 2 +- lib/ui/pages/tracks_page.dart | 2 +- lib/ui/widgets/expandable_box.dart | 4 +- lib/ui/widgets/video_widget.dart | 124 +++++++++--------- .../youtube_local_search_controller.dart | 2 +- .../controller/yt_generators_controller.dart | 2 +- lib/youtube/seek_ready_widget.dart | 8 +- pubspec.yaml | 2 +- 15 files changed, 99 insertions(+), 97 deletions(-) diff --git a/lib/base/audio_handler.dart b/lib/base/audio_handler.dart index 3b8303ec..5338fa0d 100644 --- a/lib/base/audio_handler.dart +++ b/lib/base/audio_handler.dart @@ -857,11 +857,12 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { Duration? duration = playedFromCacheDetails.duration; // race avoidance when playing multiple videos - bool checkInterrupted() { + bool checkInterrupted([Duration? dur]) { if (item != currentVideo) { return true; } else { - if (duration != null) _currentItemDuration.value = duration; + dur ??= duration ?? playedFromCacheDetails.duration; + if (dur != null) _currentItemDuration.value = dur; return false; } } @@ -871,6 +872,8 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { currentCachedAudio.value = playedFromCacheDetails.audio; currentCachedVideo.value = playedFromCacheDetails.video; + if (checkInterrupted(playedFromCacheDetails.duration)) return; + generateWaveform(); bool heyIhandledAudioPlaying = false; @@ -881,7 +884,7 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { heyIhandledAudioPlaying = false; } - if (checkInterrupted()) return; + if (checkInterrupted(playedFromCacheDetails.duration)) return; if (ConnectivityController.inst.hasConnection) { try { @@ -898,6 +901,7 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { YoutubeController.inst.currentYTQualities.value = streams.videoOnlyStreams ?? []; YoutubeController.inst.currentYTAudioStreams.value = streams.audioOnlyStreams ?? []; currentVideoInfo.value = streams.videoInfo; + if (checkInterrupted(streams.videoInfo.duration)) return; final vos = streams.videoOnlyStreams; final allVideoStream = isAudioOnlyPlayback || vos == null || vos.isEmpty ? null : YoutubeController.inst.getPreferredStreamQuality(vos, preferIncludeWebm: false); final prefferedVideoStream = allVideoStream; @@ -924,7 +928,7 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { final cachedAudio = prefferedAudioStream?.getCachedFile(item.id); final mediaItem = item.toMediaItem(currentVideoInfo.value, currentVideoThumbnail.value, index, currentQueue.length); _isCurrentAudioFromCache = cachedAudio != null; - if (checkInterrupted()) return; + if (checkInterrupted(streams.videoInfo.duration)) return; final isVideoCacheSameAsPrevSet = cachedVideo != null && playedFromCacheDetails.video != null && playedFromCacheDetails.video?.path == cachedVideo.path; // only if not the same cache path (i.e. diff resolution) @@ -949,7 +953,7 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { ); } await playerStoppingSeikoo.future; - if (checkInterrupted()) return; + if (checkInterrupted(streams.videoInfo.duration)) return; if (cachedVideo?.path != null) { File(cachedVideo!.path).setLastAccessedTry(DateTime.now()); @@ -1386,9 +1390,6 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { ); } - @override - Future skipToNext([bool? andPlay]) async => await onSkipToNext(andPlay); - @override Future skipToPrevious() async { if (previousButtonReplays) { @@ -1406,12 +1407,9 @@ class NamidaAudioVideoHandler extends BasicAudioHandler { } } - await onSkipToPrevious(); + await skipToPrevious(); } - @override - Future skipToQueueItem(int index, [bool? andPlay]) async => await onSkipToQueueItem(index, andPlay); - @override Future onDispose() async { await [ diff --git a/lib/base/ports_provider.dart b/lib/base/ports_provider.dart index f7ee5108..046fb5f4 100644 --- a/lib/base/ports_provider.dart +++ b/lib/base/ports_provider.dart @@ -5,16 +5,20 @@ import 'package:namida/core/extensions.dart'; typedef PortsComm = ({ReceivePort items, Completer search}); +abstract class _PortsProviderDisposeMessage {} + mixin PortsProvider { PortsComm? port; StreamSubscription? _streamSub; + static bool isDisposeMessage(dynamic message) => message == _PortsProviderDisposeMessage; + Future disposePort() async { final port = this.port; if (port != null) { port.items.close(); _streamSub?.cancel(); - (await port.search.future).send('dispose'); + (await port.search.future).send(_PortsProviderDisposeMessage); this.port = null; } } @@ -48,7 +52,7 @@ mixin PortsProviderBase { Future disposePort(PortsComm port) async { port.items.close(); _streamSub?.cancel(); - (await port.search.future).send('dispose'); + (await port.search.future).send(_PortsProviderDisposeMessage); } Future preparePortBase({ diff --git a/lib/controller/search_sort_controller.dart b/lib/controller/search_sort_controller.dart index 1ad30ef1..9e53cd3b 100644 --- a/lib/controller/search_sort_controller.dart +++ b/lib/controller/search_sort_controller.dart @@ -6,6 +6,7 @@ import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:playlist_manager/playlist_manager.dart'; +import 'package:namida/base/ports_provider.dart'; import 'package:namida/class/split_config.dart'; import 'package:namida/class/track.dart'; import 'package:namida/controller/history_controller.dart'; @@ -346,7 +347,7 @@ class SearchSortController { StreamSubscription? streamSub; streamSub = receivePort.listen((p) { - if (p is String && p == 'dispose') { + if (PortsProvider.isDisposeMessage(p)) { receivePort.close(); streamSub?.cancel(); return; @@ -488,7 +489,7 @@ class SearchSortController { StreamSubscription? streamSub; streamSub = receivePort.listen((p) { - if (p is String && p == 'dispose') { + if (PortsProvider.isDisposeMessage(p)) { receivePort.close(); streamSub?.cancel(); return; @@ -892,7 +893,7 @@ class SearchSortController { final cleanupFunction = _functionOfCleanup(cleanup); StreamSubscription? streamSub; streamSub = receivePort.listen((p) { - if (p is String && p == 'dispose') { + if (PortsProvider.isDisposeMessage(p)) { receivePort.close(); streamSub?.cancel(); return; diff --git a/lib/controller/video_controller.dart b/lib/controller/video_controller.dart index 8afe85bb..8559ffda 100644 --- a/lib/controller/video_controller.dart +++ b/lib/controller/video_controller.dart @@ -134,19 +134,18 @@ class VideoController { Future toggleFullScreenVideoView({ required bool isLocal, + bool? setOrientations, }) async { final aspect = Player.inst.videoPlayerInfo?.aspectRatio; await NamidaNavigator.inst.toggleFullScreen( NamidaVideoControls( key: VideoController.inst.videoControlsKeyFullScreen, isLocal: isLocal, - onMinimizeTap: () { - NamidaNavigator.inst.exitFullScreen(); - }, + onMinimizeTap: NamidaNavigator.inst.exitFullScreen, showControls: true, isFullScreen: true, ), - setOrientations: aspect == null ? true : aspect > 1, + setOrientations: setOrientations ?? (aspect == null ? true : aspect > 1), ); } diff --git a/lib/ui/pages/albums_page.dart b/lib/ui/pages/albums_page.dart index 09335ee4..fc1e7aef 100644 --- a/lib/ui/pages/albums_page.dart +++ b/lib/ui/pages/albums_page.dart @@ -64,7 +64,7 @@ class AlbumsPage extends StatelessWidget { onCloseButtonPressed: () => ScrollSearchController.inst.clearSearchTextField(LibraryTab.albums), sortByMenuWidget: SortByMenu( title: settings.albumSort.value.toText(), - popupMenuChild: const SortByMenuAlbums(), + popupMenuChild: () => const SortByMenuAlbums(), isCurrentlyReversed: settings.albumSortReversed.value, onReverseIconTap: () => SearchSortController.inst.sortMedia(MediaType.album, reverse: !settings.albumSortReversed.value), ), diff --git a/lib/ui/pages/artists_page.dart b/lib/ui/pages/artists_page.dart index 77778fa5..15dbb5b4 100644 --- a/lib/ui/pages/artists_page.dart +++ b/lib/ui/pages/artists_page.dart @@ -62,7 +62,7 @@ class ArtistsPage extends StatelessWidget { onCloseButtonPressed: () => ScrollSearchController.inst.clearSearchTextField(LibraryTab.artists), sortByMenuWidget: SortByMenu( title: settings.artistSort.value.toText(), - popupMenuChild: const SortByMenuArtists(), + popupMenuChild: () => const SortByMenuArtists(), isCurrentlyReversed: settings.artistSortReversed.value, onReverseIconTap: () => SearchSortController.inst.sortMedia(MediaType.artist, reverse: !settings.artistSortReversed.value), ), diff --git a/lib/ui/pages/genres_page.dart b/lib/ui/pages/genres_page.dart index ae4da993..8956ff0f 100644 --- a/lib/ui/pages/genres_page.dart +++ b/lib/ui/pages/genres_page.dart @@ -60,7 +60,7 @@ class GenresPage extends StatelessWidget { onCloseButtonPressed: () => ScrollSearchController.inst.clearSearchTextField(LibraryTab.genres), sortByMenuWidget: SortByMenu( title: settings.genreSort.value.toText(), - popupMenuChild: const SortByMenuGenres(), + popupMenuChild: () => const SortByMenuGenres(), isCurrentlyReversed: settings.genreSortReversed.value, onReverseIconTap: () => SearchSortController.inst.sortMedia(MediaType.genre, reverse: !settings.genreSortReversed.value), ), diff --git a/lib/ui/pages/playlists_page.dart b/lib/ui/pages/playlists_page.dart index df478185..30574b81 100644 --- a/lib/ui/pages/playlists_page.dart +++ b/lib/ui/pages/playlists_page.dart @@ -99,7 +99,7 @@ class _PlaylistsPageState extends State with TickerProviderStateM onCloseButtonPressed: () => ScrollSearchController.inst.clearSearchTextField(LibraryTab.playlists), sortByMenuWidget: SortByMenu( title: settings.playlistSort.value.toText(), - popupMenuChild: const SortByMenuPlaylist(), + popupMenuChild: () => const SortByMenuPlaylist(), isCurrentlyReversed: settings.playlistSortReversed.value, onReverseIconTap: () => SearchSortController.inst.sortMedia(MediaType.playlist, reverse: !settings.playlistSortReversed.value), ), diff --git a/lib/ui/pages/tracks_page.dart b/lib/ui/pages/tracks_page.dart index 183b79a9..467ba1a3 100644 --- a/lib/ui/pages/tracks_page.dart +++ b/lib/ui/pages/tracks_page.dart @@ -92,7 +92,7 @@ class _TracksPageState extends State with TickerProviderStateMixin, }, sortByMenuWidget: SortByMenu( title: settings.tracksSort.value.toText(), - popupMenuChild: const SortByMenuTracks(), + popupMenuChild: () => const SortByMenuTracks(), isCurrentlyReversed: settings.tracksSortReversed.value, onReverseIconTap: () { SearchSortController.inst.sortMedia(MediaType.track, reverse: !settings.tracksSortReversed.value); diff --git a/lib/ui/widgets/expandable_box.dart b/lib/ui/widgets/expandable_box.dart index 10662bf8..f07277a8 100644 --- a/lib/ui/widgets/expandable_box.dart +++ b/lib/ui/widgets/expandable_box.dart @@ -148,7 +148,7 @@ class CustomTextFiled extends StatelessWidget { } class SortByMenu extends StatelessWidget { - final Widget popupMenuChild; + final Widget Function() popupMenuChild; final String title; final bool isCurrentlyReversed; final void Function()? onReverseIconTap; @@ -177,7 +177,7 @@ class SortByMenu extends StatelessWidget { items: [ PopupMenuItem( padding: const EdgeInsets.symmetric(vertical: 0.0), - child: popupMenuChild, + child: popupMenuChild(), ), ], ), diff --git a/lib/ui/widgets/video_widget.dart b/lib/ui/widgets/video_widget.dart index 390c2321..24304ed7 100644 --- a/lib/ui/widgets/video_widget.dart +++ b/lib/ui/widgets/video_widget.dart @@ -515,49 +515,69 @@ class NamidaVideoControlsState extends State with TickerPro @override Widget build(BuildContext context) { - final fallbackChild = widget.isLocal && !widget.isFullScreen - ? Container( - key: const Key('dummy_container'), - color: Colors.transparent, - ) - : Obx( - () { - if (widget.isLocal) { - final track = Player.inst.nowPlayingTrack; - if (File(track.pathToImage).existsSync()) { - return ArtworkWidget( - key: Key(track.path), - track: track, - path: track.pathToImage, - thumbnailSize: context.width, - width: context.width, - height: context.width * 9 / 16, - borderRadius: 0, - blur: 0, - compressed: false, - ); - } - } - final vidId = Player.inst.nowPlayingVideoID?.id ?? (YoutubeController.inst.currentYoutubeMetadataVideo.value ?? Player.inst.currentVideoInfo)?.id; - return YoutubeThumbnail( - key: Key(vidId ?? ''), - isImportantInCache: true, - width: context.width, - height: context.width * 9 / 16, - borderRadius: 0, - blur: 0, - videoId: vidId, - displayFallbackIcon: false, - compressed: false, - preferLowerRes: false, - ); - }, - ); + final maxWidth = context.width; + final maxHeight = context.height; final inLandscape = NamidaNavigator.inst.isInLanscape; + + // -- in landscape, the size is calculated based on height, to fit in correctly. + final fallbackHeight = inLandscape ? maxHeight : maxWidth * 9 / 16; + final fallbackWidth = inLandscape ? maxHeight * 16 / 9 : maxWidth; + + final finalVideoWidget = Obx(() { + final info = Player.inst.videoPlayerInfo; + if (info != null && info.isInitialized) { + return NamidaAspectRatio( + aspectRatio: info.aspectRatio, + child: Obx( + () => AnimatedScale( + duration: const Duration(milliseconds: 200), + scale: 1.0 + VideoController.inst.videoZoomAdditionalScale.value * 0.02, + child: Texture(textureId: info.textureId), + ), + ), + ); + } + if (widget.isLocal && !widget.isFullScreen) { + return Container( + key: const Key('dummy_container'), + color: Colors.transparent, + ); + } + // -- fallback images + if (widget.isLocal) { + final track = Player.inst.nowPlayingTrack; + if (File(track.pathToImage).existsSync()) { + return ArtworkWidget( + key: Key(track.path), + track: track, + path: track.pathToImage, + thumbnailSize: fallbackWidth, + width: fallbackWidth, + height: fallbackHeight, + borderRadius: 0, + blur: 0, + compressed: false, + ); + } + } + final vidId = Player.inst.nowPlayingVideoID?.id ?? (YoutubeController.inst.currentYoutubeMetadataVideo.value ?? Player.inst.currentVideoInfo)?.id; + return YoutubeThumbnail( + key: Key(vidId ?? ''), + isImportantInCache: true, + width: fallbackWidth, + height: fallbackHeight, + borderRadius: 0, + blur: 0, + videoId: vidId, + displayFallbackIcon: false, + compressed: false, + preferLowerRes: false, + ); + }); final horizontalControlsPadding = widget.isFullScreen ? inLandscape - ? const EdgeInsets.symmetric(horizontal: 32.0, vertical: 12.0) // lanscape videos - : const EdgeInsets.symmetric(horizontal: 12.0, vertical: 24.0) // vertical videos + ? const EdgeInsets.symmetric(horizontal: 32.0, vertical: 0.0) // lanscape videos + : const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0) // vertical videos : const EdgeInsets.symmetric(horizontal: 2.0, vertical: 2.0); final itemsColor = Colors.white.withAlpha(200); final shouldShowSliders = _canShowControls && widget.isFullScreen; @@ -644,29 +664,9 @@ class NamidaVideoControlsState extends State with TickerPro fit: StackFit.passthrough, alignment: Alignment.center, children: [ - Stack( + Align( alignment: Alignment.center, - children: [ - Obx(() { - final info = Player.inst.videoPlayerInfo; - return info != null && info.isInitialized - ? NamidaAspectRatio( - aspectRatio: info.aspectRatio, - child: Obx( - () => AnimatedScale( - duration: const Duration(milliseconds: 200), - scale: 1.0 + VideoController.inst.videoZoomAdditionalScale.value * 0.02, - child: Texture(textureId: info.textureId), - ), - ), - ) - : SizedBox( - height: context.height, - width: context.height * 16 / 9, - child: fallbackChild, - ); - }) - ], + child: finalVideoWidget, ), // ---- Brightness Mask ----- Positioned.fill( diff --git a/lib/youtube/controller/youtube_local_search_controller.dart b/lib/youtube/controller/youtube_local_search_controller.dart index ca6ce35e..c9a89bc0 100644 --- a/lib/youtube/controller/youtube_local_search_controller.dart +++ b/lib/youtube/controller/youtube_local_search_controller.dart @@ -117,7 +117,7 @@ class YTLocalSearchController with PortsProvider { // -- start listening StreamSubscription? streamSub; streamSub = recievePort.listen((p) { - if (p is String && p == 'dispose') { + if (PortsProvider.isDisposeMessage(p)) { recievePort.close(); lookupListStreamInfo.clear(); lookupListYTVH.clear(); diff --git a/lib/youtube/controller/yt_generators_controller.dart b/lib/youtube/controller/yt_generators_controller.dart index b83fac3c..bb2e2107 100644 --- a/lib/youtube/controller/yt_generators_controller.dart +++ b/lib/youtube/controller/yt_generators_controller.dart @@ -142,7 +142,7 @@ class NamidaYTGenerator extends NamidaGeneratorBase with Port // -- start listening StreamSubscription? streamSub; streamSub = recievePort.listen((p) async { - if (p is String && p == 'dispose') { + if (PortsProvider.isDisposeMessage(p)) { recievePort.close(); releaseDateMap.clear(); allIds.clear(); diff --git a/lib/youtube/seek_ready_widget.dart b/lib/youtube/seek_ready_widget.dart index fdcda76c..677c3c8a 100644 --- a/lib/youtube/seek_ready_widget.dart +++ b/lib/youtube/seek_ready_widget.dart @@ -74,10 +74,11 @@ class _SeekReadyWidgetState extends State with SingleTickerProv _seekPercentage.value = percentageSwiped; } + Duration get _currentDuration => Player.inst.getCurrentVideoDuration; + void _onSeekEnd() async { widget.onDraggingChange?.call(false); - final plDur = Player.inst.currentItemDuration ?? Duration.zero; - final newSeek = _seekPercentage.value * (plDur.inMilliseconds); + final newSeek = _seekPercentage.value * (_currentDuration.inMilliseconds); await Player.inst.seek(Duration(milliseconds: newSeek.round())); } @@ -221,9 +222,8 @@ class _SeekReadyWidgetState extends State with SingleTickerProv // -- current seek Obx( () { - final playerDuration = Player.inst.currentItemDuration ?? Duration.zero; final currentPositionMS = Player.inst.nowPlayingPosition; - final seekTo = _seekPercentage.value * playerDuration.inMilliseconds; + final seekTo = _seekPercentage.value * _currentDuration.inMilliseconds; final seekToDiff = seekTo - currentPositionMS; final plusOrMinus = seekToDiff < 0 ? ' ' : '+'; final finalText = _currentSeekStuckWord != '' ? _currentSeekStuckWord : "$plusOrMinus${seekToDiff.round().milliSecondsLabel} "; diff --git a/pubspec.yaml b/pubspec.yaml index 745a24a1..c874bbf1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -92,7 +92,7 @@ dependencies: url: https://github.com/MSOB7YY/audio_service path: audio_service/ ref: e576b78b5b67f9ac750d8223096fbd5ed5503d17 - waveform_extractor: ^1.0.1 + waveform_extractor: ^1.0.3 basic_audio_handler: git: url: https://github.com/namidaco/basic_audio_handler