From 554fe0c3bf9775eee812a66b0e11617208b445c7 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Sat, 21 Jan 2023 07:01:28 +0530 Subject: [PATCH 01/13] Use ViewCompat.getRootWindowInsets(). --- .../main/java/com/github/libretube/util/WindowHelper.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/github/libretube/util/WindowHelper.kt b/app/src/main/java/com/github/libretube/util/WindowHelper.kt index cb8259c80..3a36279d2 100644 --- a/app/src/main/java/com/github/libretube/util/WindowHelper.kt +++ b/app/src/main/java/com/github/libretube/util/WindowHelper.kt @@ -2,6 +2,7 @@ package com.github.libretube.util import android.os.Build import android.view.WindowManager +import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat @@ -48,10 +49,6 @@ class WindowHelper(private val activity: BaseActivity) { } fun hasCutout(): Boolean { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - activity.window.decorView.rootWindowInsets.displayCutout != null - } else { - return false - } + return ViewCompat.getRootWindowInsets(activity.window.decorView)?.displayCutout != null } } From 089e72b0c7483313aba5a501d5df292b7a5d6490 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 10:57:43 +0100 Subject: [PATCH 02/13] Apply top bar for vertical fullscreen too --- .../libretube/ui/views/CustomExoPlayerView.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index 9f35f5c5e..69ecd01a7 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -228,6 +228,7 @@ internal class CustomExoPlayerView( if (it.isFullscreen.value == true) { windowHelper?.setFullscreen() } + updateTopBarMargin() } } @@ -591,15 +592,7 @@ internal class CustomExoPlayerView( it.layoutParams = params } - // add padding to the top bar to not overlap the status bar - binding.topBar.let { - setPadding( - it.paddingLeft, - (if (newConfig?.orientation == Configuration.ORIENTATION_LANDSCAPE) 25 else 5).toPixel().toInt(), - it.paddingRight, - it.paddingBottom - ) - } + updateTopBarMargin() // don't add extra padding if there's no cutout if ((context as? MainActivity)?.windowHelper?.hasCutout() == false) return @@ -632,6 +625,19 @@ internal class CustomExoPlayerView( } } + /** + * Add extra margin to the top bar to not overlap the status bar + */ + private fun updateTopBarMargin() { + val isFullscreen = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || + playerViewModel?.isFullscreen?.value == true + binding.topBar.let { + it.layoutParams = (it.layoutParams as MarginLayoutParams).apply { + topMargin = (if (isFullscreen) 25 else 5).toPixel().toInt() + } + } + } + override fun onSingleTap() { toggleController() } From cf5ef1292fad170cf8622699d5ec32d83cdcb130 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:03:24 +0100 Subject: [PATCH 03/13] Use `isShort` to display the shorts label --- .../github/libretube/ui/adapters/PlaylistAdapter.kt | 2 +- .../github/libretube/ui/adapters/SearchAdapter.kt | 2 +- .../github/libretube/ui/adapters/VideosAdapter.kt | 2 +- .../libretube/ui/adapters/WatchHistoryAdapter.kt | 2 +- .../libretube/ui/extensions/SetFormattedDuration.kt | 13 +++++-------- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt index a39275984..5fba1f429 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt @@ -66,7 +66,7 @@ class PlaylistAdapter( videoInfo.text = streamItem.uploaderName channelImage.visibility = View.GONE - thumbnailDuration.setFormattedDuration(streamItem.duration!!) + thumbnailDuration.setFormattedDuration(streamItem.duration!!, streamItem.isShort) ImageHelper.loadImage(streamItem.thumbnail, thumbnail) root.setOnClickListener { NavigationHelper.navigateVideo(root.context, streamItem.url, playlistId) diff --git a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt index 30b0e44b9..6ffa9da7e 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt @@ -83,7 +83,7 @@ class SearchAdapter( private fun bindWatch(item: ContentItem, binding: VideoRowBinding) { binding.apply { ImageHelper.loadImage(item.thumbnail, thumbnail) - thumbnailDuration.setFormattedDuration(item.duration!!) + thumbnailDuration.setFormattedDuration(item.duration!!, item.isShort) ImageHelper.loadImage(item.uploaderAvatar, channelImage) videoTitle.text = item.title val viewsString = if (item.views?.toInt() != -1) item.views.formatShort() else "" diff --git a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt index 0e44dfd25..fccbcaa0a 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt @@ -133,7 +133,7 @@ class VideosAdapter( TextUtils.SEPARATOR + video.uploaded?.let { DateUtils.getRelativeTimeSpanString(it) } - video.duration?.let { thumbnailDuration.setFormattedDuration(it) } + video.duration?.let { thumbnailDuration.setFormattedDuration(it, video.isShort) } channelImage.setOnClickListener { NavigationHelper.navigateChannel(root.context, video.uploaderUrl) } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/WatchHistoryAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/WatchHistoryAdapter.kt index c329996a2..1a8930306 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/WatchHistoryAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/WatchHistoryAdapter.kt @@ -43,7 +43,7 @@ class WatchHistoryAdapter( videoTitle.text = video.title channelName.text = video.uploader videoInfo.text = video.uploadDate - thumbnailDuration.setFormattedDuration(video.duration!!) + thumbnailDuration.setFormattedDuration(video.duration!!, null) ImageHelper.loadImage(video.thumbnailUrl, thumbnail) ImageHelper.loadImage(video.uploaderAvatar, channelImage) diff --git a/app/src/main/java/com/github/libretube/ui/extensions/SetFormattedDuration.kt b/app/src/main/java/com/github/libretube/ui/extensions/SetFormattedDuration.kt index a57e70b68..6817f4a5c 100644 --- a/app/src/main/java/com/github/libretube/ui/extensions/SetFormattedDuration.kt +++ b/app/src/main/java/com/github/libretube/ui/extensions/SetFormattedDuration.kt @@ -4,13 +4,10 @@ import android.text.format.DateUtils import android.widget.TextView import com.github.libretube.R -fun TextView.setFormattedDuration(duration: Long) { - val text = if (duration < 0L) { - this.context.getString(R.string.live) - } else if (duration in 0L..60L) { - this.context.getString(R.string.yt_shorts) - } else { - DateUtils.formatElapsedTime(duration) +fun TextView.setFormattedDuration(duration: Long, isShort: Boolean?) { + this.text = when { + isShort == true -> context.getString(R.string.yt_shorts) + duration < 0L -> context.getString(R.string.live) + else -> DateUtils.formatElapsedTime(duration) } - this.text = text } From c01cee3f832b567d76df7d4aa5238f4597677c06 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:06:16 +0100 Subject: [PATCH 04/13] Use a lower elevation for the navigation bar --- .../java/com/github/libretube/ui/activities/MainActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt index 17dd44643..3e2069659 100644 --- a/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt +++ b/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt @@ -97,7 +97,7 @@ class MainActivity : BaseActivity() { // sets the navigation bar color to the previously calculated color window.navigationBarColor = if (binding.bottomNav.menu.size() > 0) { - SurfaceColors.getColorForElevation(this, 10F) + SurfaceColors.getColorForElevation(this, 9F) } else { ThemeHelper.getThemeColor(this, android.R.attr.colorBackground) } @@ -120,7 +120,7 @@ class MainActivity : BaseActivity() { val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment? // get the current fragment - val fragment = navHostFragment?.childFragmentManager?.fragments?.get(0) + val fragment = navHostFragment?.childFragmentManager?.fragments?.getOrNull(0) tryScrollToTop(fragment?.requireView() as? ViewGroup) } } From 87519742dac1f138e91aa35626a20da2f9cab54e Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:08:32 +0100 Subject: [PATCH 05/13] Use the same elevation for nav and bottom bar --- .../java/com/github/libretube/ui/activities/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt index 3e2069659..2f9cd70b2 100644 --- a/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt +++ b/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt @@ -97,7 +97,7 @@ class MainActivity : BaseActivity() { // sets the navigation bar color to the previously calculated color window.navigationBarColor = if (binding.bottomNav.menu.size() > 0) { - SurfaceColors.getColorForElevation(this, 9F) + SurfaceColors.getColorForElevation(this, binding.bottomNav.elevation) } else { ThemeHelper.getThemeColor(this, android.R.attr.colorBackground) } From 00c607db49cc97b0bf0e977280b2d6fc4fc8d5eb Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:13:41 +0100 Subject: [PATCH 06/13] Don't hide player controls when touching 'em --- .../libretube/ui/views/CustomExoPlayerView.kt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index 69ecd01a7..dea2a587c 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -236,7 +236,7 @@ internal class CustomExoPlayerView( // remove the previous callback from the queue to prevent a flashing behavior handler.removeCallbacks(hideControllerRunnable) // automatically hide the controller after 2 seconds - handler.postDelayed(hideControllerRunnable, 2000) + handler.postDelayed(hideControllerRunnable, AUTO_HIDE_CONTROLLER_DELAY) super.showController() } @@ -712,9 +712,22 @@ internal class CustomExoPlayerView( } } + /** + * Listen for all child touch events + */ + override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { + // when a control is clicked, restart the countdown to hide the controller + if (isControllerFullyVisible) { + handler.removeCallbacks(hideControllerRunnable) + handler.postDelayed(hideControllerRunnable, AUTO_HIDE_CONTROLLER_DELAY) + } + return super.onInterceptTouchEvent(ev) + } + companion object { private const val SUBTITLE_BOTTOM_PADDING_FRACTION = 0.158f private const val ANIMATION_DURATION = 100L + private const val AUTO_HIDE_CONTROLLER_DELAY = 2000L private val LANDSCAPE_MARGIN_HORIZONTAL = (20).toPixel().toInt() } } From c2f0d68ddf35a347054135eaaded421d8324e5b2 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:19:47 +0100 Subject: [PATCH 07/13] Fix queue starts wrong video after reordering --- .../libretube/ui/adapters/PlayingQueueAdapter.kt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt index 20ff28c2c..d0875c073 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt @@ -7,6 +7,7 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.github.libretube.databinding.QueueRowBinding +import com.github.libretube.extensions.toID import com.github.libretube.ui.viewholders.PlayingQueueViewHolder import com.github.libretube.util.ImageHelper import com.github.libretube.util.PlayingQueue @@ -46,10 +47,16 @@ class PlayingQueueAdapter : RecyclerView.Adapter() { ) root.setOnClickListener { - val oldIndex = PlayingQueue.currentIndex() - PlayingQueue.onQueueItemSelected(position) - notifyItemChanged(oldIndex) - notifyItemChanged(position) + val oldPosition = PlayingQueue.currentIndex() + // get the new position from the queue to work properly after reordering the queue + val newPosition = PlayingQueue.getStreams().indexOfFirst { + it.url?.toID() == streamItem.url?.toID() + }.takeIf { it >= 0 } ?: return@setOnClickListener + + // select the new item in the queue and update the selected item in the UI + PlayingQueue.onQueueItemSelected(newPosition) + notifyItemChanged(oldPosition) + notifyItemChanged(newPosition) } } } From a5c31329160ebb580f5079c7cc126a32ad6fcda9 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:24:25 +0100 Subject: [PATCH 08/13] Fix the notification thumbnail vanishing --- .../libretube/util/NowPlayingNotification.kt | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/github/libretube/util/NowPlayingNotification.kt b/app/src/main/java/com/github/libretube/util/NowPlayingNotification.kt index 286c3d084..ae00b2bfc 100644 --- a/app/src/main/java/com/github/libretube/util/NowPlayingNotification.kt +++ b/app/src/main/java/com/github/libretube/util/NowPlayingNotification.kt @@ -38,6 +38,7 @@ class NowPlayingNotification( ) { private var videoId: String? = null private var streams: Streams? = null + private var bitmap: Bitmap? = null /** * The [MediaSessionCompat] for the [streams]. @@ -105,24 +106,7 @@ class NowPlayingNotification( ): Bitmap? { if (DataSaverMode.isEnabled(context)) return null - var bitmap: Bitmap? = null - - val request = ImageRequest.Builder(context) - .data(streams?.thumbnailUrl) - .target { result -> - val bm = (result as BitmapDrawable).bitmap - // returns the bitmap on Android 13+, for everything below scaled down to a square - bitmap = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - ImageHelper.getSquareBitmap(bm) - } else { - bm - } - callback.onBitmap(bitmap!!) - } - .build() - - // enqueue the thumbnail loading request - ImageHelper.imageLoader.enqueue(request) + if (bitmap == null) enqueueThumbnailRequest(callback) return bitmap } @@ -132,6 +116,25 @@ class NowPlayingNotification( } } + private fun enqueueThumbnailRequest(callback: PlayerNotificationManager.BitmapCallback) { + val request = ImageRequest.Builder(context) + .data(streams?.thumbnailUrl) + .target { result -> + val bm = (result as BitmapDrawable).bitmap + // returns the bitmap on Android 13+, for everything below scaled down to a square + bitmap = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + ImageHelper.getSquareBitmap(bm) + } else { + bm + } + callback.onBitmap(bitmap!!) + } + .build() + + // enqueue the thumbnail loading request + ImageHelper.imageLoader.enqueue(request) + } + private val customActionReceiver = object : CustomActionReceiver { override fun createCustomActions( context: Context, @@ -257,6 +260,8 @@ class NowPlayingNotification( ) { this.videoId = videoId this.streams = streams + // reset the thumbnail bitmap in order to become reloaded for the new video + this.bitmap = null if (playerNotification == null) { createMediaSession() From 7ffe3a6ed9f7cd3dcd81ee3bc0201697bfe99e35 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:46:56 +0100 Subject: [PATCH 09/13] [Audio Mode] Share, playback and queue controls --- .../libretube/services/BackgroundMode.kt | 2 +- .../ui/fragments/AudioPlayerFragment.kt | 39 ++++++++++---- ...kSpeedSheet.kt => PlaybackOptionsSheet.kt} | 2 +- .../libretube/ui/views/CustomExoPlayerView.kt | 4 +- app/src/main/res/drawable/ic_video.xml | 5 ++ .../main/res/layout/fragment_audio_player.xml | 54 ++++++++++++++++--- app/src/main/res/values/style.xml | 8 +++ 7 files changed, 92 insertions(+), 22 deletions(-) rename app/src/main/java/com/github/libretube/ui/sheets/{PlaybackSpeedSheet.kt => PlaybackOptionsSheet.kt} (98%) create mode 100644 app/src/main/res/drawable/ic_video.xml diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index ac4251f65..ccaf5aa91 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -65,7 +65,7 @@ class BackgroundMode : Service() { /** * The [ExoPlayer] player. Followed tutorial [here](https://developer.android.com/codelabs/exoplayer-intro) */ - private var player: ExoPlayer? = null + var player: ExoPlayer? = null private var playWhenReadyPlayer = true /** diff --git a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt index b2b599952..a0ec7e3e9 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt @@ -15,10 +15,14 @@ import android.view.ViewGroup import com.github.libretube.R import com.github.libretube.api.obj.StreamItem import com.github.libretube.databinding.FragmentAudioPlayerBinding +import com.github.libretube.enums.ShareObjectType import com.github.libretube.extensions.toID +import com.github.libretube.obj.ShareData import com.github.libretube.services.BackgroundMode import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.base.BaseFragment +import com.github.libretube.ui.dialogs.ShareDialog +import com.github.libretube.ui.sheets.PlaybackOptionsSheet import com.github.libretube.ui.sheets.PlayingQueueSheet import com.github.libretube.util.ImageHelper import com.github.libretube.util.NavigationHelper @@ -32,7 +36,7 @@ class AudioPlayerFragment : BaseFragment() { private var handler = Handler(Looper.getMainLooper()) private var isPaused: Boolean = false - private lateinit var playerService: BackgroundMode + private var playerService: BackgroundMode? = null /** Defines callbacks for service binding, passed to bindService() */ private val connection = object : ServiceConnection { @@ -86,16 +90,31 @@ class AudioPlayerFragment : BaseFragment() { PlayingQueue.onQueueItemSelected(currentIndex + 1) } - binding.thumbnail.setOnClickListener { + binding.openQueue.setOnClickListener { PlayingQueueSheet().show(childFragmentManager) } + binding.playbackOptions.setOnClickListener { + playerService?.player?.let { + PlaybackOptionsSheet(it) + .show(childFragmentManager) + } + } + + binding.share.setOnClickListener { + val currentVideo = PlayingQueue.getCurrent() ?: return@setOnClickListener + ShareDialog( + id = currentVideo.url!!.toID(), + shareObjectType = ShareObjectType.VIDEO, + shareData = ShareData(currentVideo = currentVideo.title) + ).show(childFragmentManager, null) + } + // Listen for track changes due to autoplay or the notification PlayingQueue.addOnTrackChangedListener(onTrackChangeListener) binding.playPause.setOnClickListener { - if (!this::playerService.isInitialized) return@setOnClickListener - if (isPaused) playerService.play() else playerService.pause() + if (isPaused) playerService?.play() else playerService?.pause() } // load the stream info into the UI @@ -121,10 +140,8 @@ class AudioPlayerFragment : BaseFragment() { } private fun initializeSeekBar() { - if (!this::playerService.isInitialized) return - binding.timeBar.addOnChangeListener { _, value, fromUser -> - if (fromUser) playerService.seekToPosition(value.toLong() * 1000) + if (fromUser) playerService?.seekToPosition(value.toLong() * 1000) } updateSeekBar() } @@ -133,7 +150,7 @@ class AudioPlayerFragment : BaseFragment() { * Update the position, duration and text views belonging to the seek bar */ private fun updateSeekBar() { - val duration = playerService.getDuration()?.toFloat() ?: return + val duration = playerService?.getDuration()?.toFloat() ?: return // when the video is not loaded yet, retry in 100 ms if (duration <= 0) { @@ -142,7 +159,7 @@ class AudioPlayerFragment : BaseFragment() { } // get the current position from the player service - val currentPosition = playerService.getCurrentPosition()?.toFloat() ?: 0f + val currentPosition = playerService?.getCurrentPosition()?.toFloat() ?: 0f // set the text for the indicators binding.duration.text = DateUtils.formatElapsedTime((duration / 1000).toLong()) @@ -161,7 +178,7 @@ class AudioPlayerFragment : BaseFragment() { } private fun handleServiceConnection() { - playerService.onIsPlayingChanged = { isPlaying -> + playerService?.onIsPlayingChanged = { isPlaying -> binding.playPause.setIconResource( if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play ) @@ -172,7 +189,7 @@ class AudioPlayerFragment : BaseFragment() { override fun onDestroy() { // unregister all listeners and the connected [playerService] - playerService.onIsPlayingChanged = null + playerService?.onIsPlayingChanged = null activity?.unbindService(connection) PlayingQueue.removeOnTrackChangedListener(onTrackChangeListener) diff --git a/app/src/main/java/com/github/libretube/ui/sheets/PlaybackSpeedSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/PlaybackOptionsSheet.kt similarity index 98% rename from app/src/main/java/com/github/libretube/ui/sheets/PlaybackSpeedSheet.kt rename to app/src/main/java/com/github/libretube/ui/sheets/PlaybackOptionsSheet.kt index 4bf141c9e..caaa79898 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/PlaybackSpeedSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/PlaybackOptionsSheet.kt @@ -11,7 +11,7 @@ import com.github.libretube.util.PreferenceHelper import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.PlaybackParameters -class PlaybackSpeedSheet( +class PlaybackOptionsSheet( private val player: ExoPlayer ) : ExpandedBottomSheet() { private lateinit var binding: PlaybackBottomSheetBinding diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index dea2a587c..7784da8eb 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -30,7 +30,7 @@ import com.github.libretube.ui.interfaces.PlayerGestureOptions import com.github.libretube.ui.interfaces.PlayerOptions import com.github.libretube.ui.models.PlayerViewModel import com.github.libretube.ui.sheets.BaseBottomSheet -import com.github.libretube.ui.sheets.PlaybackSpeedSheet +import com.github.libretube.ui.sheets.PlaybackOptionsSheet import com.github.libretube.util.AudioHelper import com.github.libretube.util.BrightnessHelper import com.github.libretube.util.PlayerGestureController @@ -531,7 +531,7 @@ internal class CustomExoPlayerView( override fun onPlaybackSpeedClicked() { player?.let { - PlaybackSpeedSheet(it as ExoPlayer).show(supportFragmentManager) + PlaybackOptionsSheet(it as ExoPlayer).show(supportFragmentManager) } } diff --git a/app/src/main/res/drawable/ic_video.xml b/app/src/main/res/drawable/ic_video.xml new file mode 100644 index 000000000..154eca5b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_video.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/fragment_audio_player.xml b/app/src/main/res/layout/fragment_audio_player.xml index 67ec3bd23..1ee209686 100644 --- a/app/src/main/res/layout/fragment_audio_player.xml +++ b/app/src/main/res/layout/fragment_audio_player.xml @@ -47,8 +47,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:textSize="18sp" - android:layout_marginTop="10dp" /> + android:layout_marginTop="10dp" + android:textSize="18sp" /> @@ -56,8 +56,8 @@ android:id="@+id/time_bar" android:layout_width="match_parent" android:layout_height="wrap_content" - app:labelBehavior="gone" - android:layout_marginHorizontal="20dp" /> + android:layout_marginHorizontal="20dp" + app:labelBehavior="gone" /> + tools:text="00:00" /> + tools:text="10:15" /> @@ -84,7 +84,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_marginVertical="50dp"> + android:layout_marginVertical="36dp"> + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml index c12c90ca0..488986625 100644 --- a/app/src/main/res/values/style.xml +++ b/app/src/main/res/values/style.xml @@ -238,4 +238,12 @@ + + \ No newline at end of file From ee0607fb071cdc6e271106f49a0dd4a9cd07b92b Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:53:52 +0100 Subject: [PATCH 10/13] Add control to open the video from the audio player --- .../libretube/ui/fragments/AudioPlayerFragment.kt | 13 +++++++++++++ .../com/github/libretube/util/NavigationHelper.kt | 5 +++-- app/src/main/res/drawable/ic_video.xml | 13 +++++++++---- app/src/main/res/layout/fragment_audio_player.xml | 3 ++- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt index a0ec7e3e9..9190e8402 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt @@ -12,6 +12,7 @@ import android.text.format.DateUtils import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.navigation.fragment.findNavController import com.github.libretube.R import com.github.libretube.api.obj.StreamItem import com.github.libretube.databinding.FragmentAudioPlayerBinding @@ -24,6 +25,7 @@ import com.github.libretube.ui.base.BaseFragment import com.github.libretube.ui.dialogs.ShareDialog import com.github.libretube.ui.sheets.PlaybackOptionsSheet import com.github.libretube.ui.sheets.PlayingQueueSheet +import com.github.libretube.util.BackgroundHelper import com.github.libretube.util.ImageHelper import com.github.libretube.util.NavigationHelper import com.github.libretube.util.PlayingQueue @@ -101,6 +103,17 @@ class AudioPlayerFragment : BaseFragment() { } } + binding.openVideo.setOnClickListener { + NavigationHelper.navigateVideo( + context = requireContext(), + videoId = PlayingQueue.getCurrent()?.url?.toID(), + keepQueue = true, + forceVideo = true + ) + BackgroundHelper.stopBackgroundPlay(requireContext()) + findNavController().popBackStack() + } + binding.share.setOnClickListener { val currentVideo = PlayingQueue.getCurrent() ?: return@setOnClickListener ShareDialog( diff --git a/app/src/main/java/com/github/libretube/util/NavigationHelper.kt b/app/src/main/java/com/github/libretube/util/NavigationHelper.kt index ef8f30cd3..44e659d42 100644 --- a/app/src/main/java/com/github/libretube/util/NavigationHelper.kt +++ b/app/src/main/java/com/github/libretube/util/NavigationHelper.kt @@ -60,11 +60,12 @@ object NavigationHelper { playlistId: String? = null, channelId: String? = null, keepQueue: Boolean = false, - timeStamp: Long? = null + timeStamp: Long? = null, + forceVideo: Boolean = false ) { if (videoId == null) return - if (PreferenceHelper.getBoolean(PreferenceKeys.AUDIO_ONLY_MODE, false)) { + if (PreferenceHelper.getBoolean(PreferenceKeys.AUDIO_ONLY_MODE, false) && !forceVideo) { BackgroundHelper.stopBackgroundPlay(context) BackgroundHelper.playOnBackground( context, diff --git a/app/src/main/res/drawable/ic_video.xml b/app/src/main/res/drawable/ic_video.xml index 154eca5b5..d8424bad1 100644 --- a/app/src/main/res/drawable/ic_video.xml +++ b/app/src/main/res/drawable/ic_video.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/layout/fragment_audio_player.xml b/app/src/main/res/layout/fragment_audio_player.xml index 1ee209686..e88be5878 100644 --- a/app/src/main/res/layout/fragment_audio_player.xml +++ b/app/src/main/res/layout/fragment_audio_player.xml @@ -84,7 +84,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_marginVertical="36dp"> + android:layout_marginTop="24dp" + android:layout_marginBottom="36dp"> Date: Sat, 21 Jan 2023 11:57:43 +0100 Subject: [PATCH 11/13] Fix crash when removing callbacks --- .../libretube/ui/views/CustomExoPlayerView.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index 7784da8eb..5e06f40fb 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -218,9 +218,15 @@ internal class CustomExoPlayerView( } } + private fun cancelHideControllerTask() { + runCatching { + handler.removeCallbacks(hideControllerRunnable) + } + } + override fun hideController() { // remove the callback to hide the controller - handler.removeCallbacks(hideControllerRunnable) + cancelHideControllerTask() super.hideController() // hide system bars if in fullscreen @@ -234,7 +240,7 @@ internal class CustomExoPlayerView( override fun showController() { // remove the previous callback from the queue to prevent a flashing behavior - handler.removeCallbacks(hideControllerRunnable) + cancelHideControllerTask() // automatically hide the controller after 2 seconds handler.postDelayed(hideControllerRunnable, AUTO_HIDE_CONTROLLER_DELAY) super.showController() @@ -393,8 +399,8 @@ internal class CustomExoPlayerView( doubleTapOverlayBinding?.apply { animateSeeking(rewindBTN, rewindIV, rewindTV, true) - runnableHandler.removeCallbacks(hideRewindButtonRunnable) // start callback to hide the button + runnableHandler.removeCallbacks(hideRewindButtonRunnable) runnableHandler.postDelayed(hideRewindButtonRunnable, 700) } } @@ -718,7 +724,7 @@ internal class CustomExoPlayerView( override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { // when a control is clicked, restart the countdown to hide the controller if (isControllerFullyVisible) { - handler.removeCallbacks(hideControllerRunnable) + cancelHideControllerTask() handler.postDelayed(hideControllerRunnable, AUTO_HIDE_CONTROLLER_DELAY) } return super.onInterceptTouchEvent(ev) From b03d0803162acaef1f434af6a68a2be0c74699ba Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 11:59:44 +0100 Subject: [PATCH 12/13] Use the same playback speed for background and video mode --- .../github/libretube/constants/PreferenceKeys.kt | 1 - .../com/github/libretube/services/BackgroundMode.kt | 2 +- app/src/main/res/xml/audio_video_settings.xml | 13 ------------- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt index 486a858d7..7a1e06197 100644 --- a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt +++ b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt @@ -93,7 +93,6 @@ object PreferenceKeys { /** * Background mode */ - const val BACKGROUND_PLAYBACK_SPEED = "background_playback_speed" const val AUDIO_ONLY_MODE = "audio_only_mode" /** diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index ccaf5aa91..e0f622d63 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -225,7 +225,7 @@ class BackgroundMode : Service() { // set the playback speed val playbackSpeed = PreferenceHelper.getString( - PreferenceKeys.BACKGROUND_PLAYBACK_SPEED, + PreferenceKeys.PLAYBACK_SPEED, "1" ).toFloat() player?.setPlaybackSpeed(playbackSpeed) diff --git a/app/src/main/res/xml/audio_video_settings.xml b/app/src/main/res/xml/audio_video_settings.xml index 9ea6e0d77..217e00cb3 100644 --- a/app/src/main/res/xml/audio_video_settings.xml +++ b/app/src/main/res/xml/audio_video_settings.xml @@ -78,17 +78,4 @@ - - - - - - \ No newline at end of file From 79fab618df3b37431b723a2a982515d55d13bc2f Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 21 Jan 2023 12:07:28 +0100 Subject: [PATCH 13/13] Apply playback params for all players --- .../libretube/services/BackgroundMode.kt | 11 ++-------- .../ui/activities/OfflinePlayerActivity.kt | 2 ++ .../libretube/ui/fragments/PlayerFragment.kt | 2 ++ .../libretube/ui/views/CustomExoPlayerView.kt | 17 ---------------- .../com/github/libretube/util/PlayerHelper.kt | 20 +++++++++++++++++++ 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index e0f622d63..8378e9128 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -22,7 +22,6 @@ import com.github.libretube.api.obj.Streams import com.github.libretube.constants.BACKGROUND_CHANNEL_ID import com.github.libretube.constants.IntentData import com.github.libretube.constants.PLAYER_NOTIFICATION_ID -import com.github.libretube.constants.PreferenceKeys import com.github.libretube.db.DatabaseHolder.Companion.Database import com.github.libretube.db.obj.WatchPosition import com.github.libretube.extensions.TAG @@ -32,8 +31,8 @@ import com.github.libretube.extensions.toID import com.github.libretube.extensions.toStreamItem import com.github.libretube.util.NowPlayingNotification import com.github.libretube.util.PlayerHelper +import com.github.libretube.util.PlayerHelper.loadPlaybackParams import com.github.libretube.util.PlayingQueue -import com.github.libretube.util.PreferenceHelper import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.PlaybackException @@ -223,13 +222,6 @@ class BackgroundMode : Service() { } } - // set the playback speed - val playbackSpeed = PreferenceHelper.getString( - PreferenceKeys.PLAYBACK_SPEED, - "1" - ).toFloat() - player?.setPlaybackSpeed(playbackSpeed) - fetchSponsorBlockSegments() } @@ -244,6 +236,7 @@ class BackgroundMode : Service() { .setAudioAttributes(PlayerHelper.getAudioAttributes(), true) .setLoadControl(PlayerHelper.getLoadControl()) .build() + .loadPlaybackParams() /** * Listens for changed playbackStates (e.g. pause, end) diff --git a/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt index 5072bb5d6..d56276ea0 100644 --- a/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt +++ b/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt @@ -20,6 +20,7 @@ import com.github.libretube.ui.base.BaseActivity import com.github.libretube.ui.extensions.setAspectRatio import com.github.libretube.ui.models.PlayerViewModel import com.github.libretube.util.PlayerHelper +import com.github.libretube.util.PlayerHelper.loadPlaybackParams import com.github.libretube.util.WindowHelper import com.google.android.exoplayer2.C import com.google.android.exoplayer2.ExoPlayer @@ -81,6 +82,7 @@ class OfflinePlayerActivity : BaseActivity() { } }) } + .loadPlaybackParams() playerView = binding.player playerView.setShowSubtitleButton(true) diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index 17a16914e..3df84e776 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -94,6 +94,7 @@ import com.github.libretube.util.LinkHandler import com.github.libretube.util.NavigationHelper import com.github.libretube.util.NowPlayingNotification import com.github.libretube.util.PlayerHelper +import com.github.libretube.util.PlayerHelper.loadPlaybackParams import com.github.libretube.util.PlayingQueue import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.SeekbarPreviewListener @@ -1346,6 +1347,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { .setHandleAudioBecomingNoisy(true) .setAudioAttributes(PlayerHelper.getAudioAttributes(), true) .build() + .loadPlaybackParams() } /** diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index 5e06f40fb..c740b5d78 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -16,7 +16,6 @@ import android.widget.TextView import androidx.core.content.ContextCompat import androidx.lifecycle.LifecycleOwner import com.github.libretube.R -import com.github.libretube.constants.PreferenceKeys import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.PlayerGestureControlsViewBinding @@ -36,9 +35,7 @@ import com.github.libretube.util.BrightnessHelper import com.github.libretube.util.PlayerGestureController import com.github.libretube.util.PlayerHelper import com.github.libretube.util.PlayingQueue -import com.github.libretube.util.PreferenceHelper import com.google.android.exoplayer2.ExoPlayer -import com.google.android.exoplayer2.PlaybackParameters import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.text.Cue import com.google.android.exoplayer2.trackselection.TrackSelector @@ -92,9 +89,6 @@ internal class CustomExoPlayerView( if (isControllerFullyVisible) hideController() else showController() } - // saved to only load the playback speed once (for the first video) - private var playbackPrefSet = false - private val hideControllerRunnable = Runnable { hideController() } @@ -127,17 +121,6 @@ internal class CustomExoPlayerView( // don't let the player view hide its controls automatically controllerShowTimeoutMs = -1 - if (!playbackPrefSet) { - player?.playbackParameters = PlaybackParameters( - PlayerHelper.playbackSpeed.toFloat(), - 1.0f - ) - PreferenceHelper.getBoolean(PreferenceKeys.SKIP_SILENCE, false).let { - (player as ExoPlayer).skipSilenceEnabled = it - } - playbackPrefSet = true - } - // locking the player binding.lockPlayer.setOnClickListener { // change the locked/unlocked icon diff --git a/app/src/main/java/com/github/libretube/util/PlayerHelper.kt b/app/src/main/java/com/github/libretube/util/PlayerHelper.kt index 916ea78b2..06a8395ac 100644 --- a/app/src/main/java/com/github/libretube/util/PlayerHelper.kt +++ b/app/src/main/java/com/github/libretube/util/PlayerHelper.kt @@ -18,7 +18,9 @@ import com.github.libretube.enums.AudioQuality import com.github.libretube.enums.PlayerEvent import com.google.android.exoplayer2.C import com.google.android.exoplayer2.DefaultLoadControl +import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.LoadControl +import com.google.android.exoplayer2.PlaybackParameters import com.google.android.exoplayer2.audio.AudioAttributes import com.google.android.exoplayer2.ui.CaptionStyleCompat import com.google.android.exoplayer2.video.VideoSize @@ -342,6 +344,12 @@ object PlayerHelper { false ) + private val skipSilence: Boolean + get() = PreferenceHelper.getBoolean( + PreferenceKeys.SKIP_SILENCE, + false + ) + fun getDefaultResolution(context: Context): String { return if (NetworkHelper.isNetworkMobile(context)) { PreferenceHelper.getString( @@ -459,4 +467,16 @@ object PlayerHelper { ) .build() } + + /** + * Load playback parameters such as speed and skip silence + */ + fun ExoPlayer.loadPlaybackParams(): ExoPlayer { + skipSilenceEnabled = skipSilence + playbackParameters = PlaybackParameters( + playbackSpeed.toFloat(), + 1.0f + ) + return this + } }