mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 00:10:32 +05:30
Migration to Media3
This commit is contained in:
parent
4a5dd6fc35
commit
95e65ae7e3
@ -103,10 +103,12 @@ dependencies {
|
|||||||
implementation libs.material
|
implementation libs.material
|
||||||
|
|
||||||
/* ExoPlayer */
|
/* ExoPlayer */
|
||||||
implementation libs.exoplayer
|
implementation libs.androidx.media3.exoplayer
|
||||||
implementation(libs.exoplayer.extension.cronet) { exclude group: 'com.google.android.gms' }
|
implementation libs.androidx.media3.ui
|
||||||
implementation libs.exoplayer.extension.mediasession
|
implementation libs.androidx.media3.exoplayer.hls
|
||||||
implementation libs.exoplayer.dash
|
implementation libs.androidx.media3.exoplayer.dash
|
||||||
|
implementation libs.androidx.media3.session
|
||||||
|
implementation(libs.androidx.media3.datasource.cronet) { exclude group: 'com.google.android.gms' }
|
||||||
|
|
||||||
/* Retrofit and Kotlinx Serialization */
|
/* Retrofit and Kotlinx Serialization */
|
||||||
implementation libs.square.retrofit
|
implementation libs.square.retrofit
|
||||||
|
@ -6,7 +6,7 @@ import android.os.Build
|
|||||||
import android.util.Rational
|
import android.util.Rational
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.app.RemoteActionCompat
|
import androidx.core.app.RemoteActionCompat
|
||||||
import com.google.android.exoplayer2.video.VideoSize
|
import androidx.media3.common.VideoSize
|
||||||
|
|
||||||
class PictureInPictureParamsCompat private constructor(
|
class PictureInPictureParamsCompat private constructor(
|
||||||
private val autoEnterEnabled: Boolean,
|
private val autoEnterEnabled: Boolean,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package com.github.libretube.extensions
|
package com.github.libretube.extensions
|
||||||
|
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||||
|
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
inline fun DefaultTrackSelector.updateParameters(
|
inline fun DefaultTrackSelector.updateParameters(
|
||||||
actions: DefaultTrackSelector.Parameters.Builder.() -> Unit,
|
actions: DefaultTrackSelector.Parameters.Builder.() -> Unit,
|
||||||
) = setParameters(buildUponParameters().apply(actions))
|
) = setParameters(buildUponParameters().apply(actions))
|
||||||
|
@ -12,19 +12,19 @@ import androidx.core.app.PendingIntentCompat
|
|||||||
import androidx.core.app.RemoteActionCompat
|
import androidx.core.app.RemoteActionCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
|
import androidx.media3.common.AudioAttributes
|
||||||
|
import androidx.media3.common.C
|
||||||
|
import androidx.media3.common.PlaybackParameters
|
||||||
|
import androidx.media3.exoplayer.DefaultLoadControl
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.exoplayer.LoadControl
|
||||||
|
import androidx.media3.ui.CaptionStyleCompat
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.obj.PipedStream
|
import com.github.libretube.api.obj.PipedStream
|
||||||
import com.github.libretube.api.obj.Segment
|
import com.github.libretube.api.obj.Segment
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.enums.AudioQuality
|
import com.github.libretube.enums.AudioQuality
|
||||||
import com.github.libretube.enums.PlayerEvent
|
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 kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -75,6 +75,7 @@ object PlayerHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the system default caption style
|
// get the system default caption style
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
fun getCaptionStyle(context: Context): CaptionStyleCompat {
|
fun getCaptionStyle(context: Context): CaptionStyleCompat {
|
||||||
val captioningManager = context.getSystemService<CaptioningManager>()!!
|
val captioningManager = context.getSystemService<CaptioningManager>()!!
|
||||||
return if (!captioningManager.isEnabled) {
|
return if (!captioningManager.isEnabled) {
|
||||||
@ -461,6 +462,7 @@ object PlayerHelper {
|
|||||||
/**
|
/**
|
||||||
* Get the load controls for the player (buffering, etc)
|
* Get the load controls for the player (buffering, etc)
|
||||||
*/
|
*/
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
fun getLoadControl(): LoadControl {
|
fun getLoadControl(): LoadControl {
|
||||||
return DefaultLoadControl.Builder()
|
return DefaultLoadControl.Builder()
|
||||||
// cache the last three minutes
|
// cache the last three minutes
|
||||||
@ -477,6 +479,7 @@ object PlayerHelper {
|
|||||||
/**
|
/**
|
||||||
* Load playback parameters such as speed and skip silence
|
* Load playback parameters such as speed and skip silence
|
||||||
*/
|
*/
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
fun ExoPlayer.loadPlaybackParams(isBackgroundMode: Boolean = false): ExoPlayer {
|
fun ExoPlayer.loadPlaybackParams(isBackgroundMode: Boolean = false): ExoPlayer {
|
||||||
skipSilenceEnabled = skipSilence
|
skipSilenceEnabled = skipSilence
|
||||||
val speed = if (isBackgroundMode) backgroundSpeed else playbackSpeed
|
val speed = if (isBackgroundMode) backgroundSpeed else playbackSpeed
|
||||||
|
@ -6,6 +6,8 @@ import androidx.core.app.NotificationCompat
|
|||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
import androidx.lifecycle.LifecycleService
|
import androidx.lifecycle.LifecycleService
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
||||||
import com.github.libretube.constants.IntentData
|
import com.github.libretube.constants.IntentData
|
||||||
@ -18,8 +20,6 @@ import com.github.libretube.helpers.PlayerHelper
|
|||||||
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
|
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
|
||||||
import com.github.libretube.obj.PlayerNotificationData
|
import com.github.libretube.obj.PlayerNotificationData
|
||||||
import com.github.libretube.util.NowPlayingNotification
|
import com.github.libretube.util.NowPlayingNotification
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.exoplayer2.MediaItem
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -75,6 +75,7 @@ class OfflinePlayerService : LifecycleService() {
|
|||||||
* @param downloadWithItem The database download to play from
|
* @param downloadWithItem The database download to play from
|
||||||
* @return whether starting the audio player succeeded
|
* @return whether starting the audio player succeeded
|
||||||
*/
|
*/
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
private fun startAudioPlayer(downloadWithItem: DownloadWithItems): Boolean {
|
private fun startAudioPlayer(downloadWithItem: DownloadWithItems): Boolean {
|
||||||
player = ExoPlayer.Builder(this)
|
player = ExoPlayer.Builder(this)
|
||||||
.setUsePlatformDiagnostics(false)
|
.setUsePlatformDiagnostics(false)
|
||||||
|
@ -12,6 +12,10 @@ import androidx.core.app.NotificationCompat
|
|||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
import androidx.lifecycle.LifecycleService
|
import androidx.lifecycle.LifecycleService
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.PlaybackException
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.JsonHelper
|
import com.github.libretube.api.JsonHelper
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
@ -31,10 +35,6 @@ import com.github.libretube.helpers.ProxyHelper
|
|||||||
import com.github.libretube.obj.PlayerNotificationData
|
import com.github.libretube.obj.PlayerNotificationData
|
||||||
import com.github.libretube.util.NowPlayingNotification
|
import com.github.libretube.util.NowPlayingNotification
|
||||||
import com.github.libretube.util.PlayingQueue
|
import com.github.libretube.util.PlayingQueue
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.exoplayer2.MediaItem
|
|
||||||
import com.google.android.exoplayer2.PlaybackException
|
|
||||||
import com.google.android.exoplayer2.Player
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -45,6 +45,7 @@ import kotlinx.serialization.encodeToString
|
|||||||
/**
|
/**
|
||||||
* Loads the selected videos audio in background mode with a notification area.
|
* Loads the selected videos audio in background mode with a notification area.
|
||||||
*/
|
*/
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
class OnlinePlayerService : LifecycleService() {
|
class OnlinePlayerService : LifecycleService() {
|
||||||
/**
|
/**
|
||||||
* VideoId of the video
|
* VideoId of the video
|
||||||
|
@ -8,6 +8,17 @@ import android.text.format.DateUtils
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.media3.common.C
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||||
|
import androidx.media3.common.MimeTypes
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.datasource.FileDataSource
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.exoplayer.source.MergingMediaSource
|
||||||
|
import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
||||||
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||||
|
import androidx.media3.ui.PlayerView
|
||||||
import com.github.libretube.compat.PictureInPictureCompat
|
import com.github.libretube.compat.PictureInPictureCompat
|
||||||
import com.github.libretube.compat.PictureInPictureParamsCompat
|
import com.github.libretube.compat.PictureInPictureParamsCompat
|
||||||
import com.github.libretube.constants.IntentData
|
import com.github.libretube.constants.IntentData
|
||||||
@ -22,26 +33,16 @@ import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
|
|||||||
import com.github.libretube.helpers.WindowHelper
|
import com.github.libretube.helpers.WindowHelper
|
||||||
import com.github.libretube.ui.base.BaseActivity
|
import com.github.libretube.ui.base.BaseActivity
|
||||||
import com.github.libretube.ui.models.PlayerViewModel
|
import com.github.libretube.ui.models.PlayerViewModel
|
||||||
import com.google.android.exoplayer2.C
|
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.exoplayer2.MediaItem
|
|
||||||
import com.google.android.exoplayer2.MediaItem.SubtitleConfiguration
|
|
||||||
import com.google.android.exoplayer2.Player
|
|
||||||
import com.google.android.exoplayer2.source.MergingMediaSource
|
|
||||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource
|
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
|
||||||
import com.google.android.exoplayer2.ui.StyledPlayerView
|
|
||||||
import com.google.android.exoplayer2.upstream.FileDataSource
|
|
||||||
import com.google.android.exoplayer2.util.MimeTypes
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
class OfflinePlayerActivity : BaseActivity() {
|
class OfflinePlayerActivity : BaseActivity() {
|
||||||
private lateinit var binding: ActivityOfflinePlayerBinding
|
private lateinit var binding: ActivityOfflinePlayerBinding
|
||||||
private lateinit var videoId: String
|
private lateinit var videoId: String
|
||||||
private lateinit var player: ExoPlayer
|
private lateinit var player: ExoPlayer
|
||||||
private lateinit var playerView: StyledPlayerView
|
private lateinit var playerView: PlayerView
|
||||||
private lateinit var trackSelector: DefaultTrackSelector
|
private lateinit var trackSelector: DefaultTrackSelector
|
||||||
|
|
||||||
private lateinit var playerBinding: ExoStyledPlayerControlViewBinding
|
private lateinit var playerBinding: ExoStyledPlayerControlViewBinding
|
||||||
|
@ -4,13 +4,13 @@ import android.graphics.Color
|
|||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.github.libretube.api.obj.ChapterSegment
|
import com.github.libretube.api.obj.ChapterSegment
|
||||||
import com.github.libretube.databinding.ChapterColumnBinding
|
import com.github.libretube.databinding.ChapterColumnBinding
|
||||||
import com.github.libretube.helpers.ImageHelper
|
import com.github.libretube.helpers.ImageHelper
|
||||||
import com.github.libretube.helpers.ThemeHelper
|
import com.github.libretube.helpers.ThemeHelper
|
||||||
import com.github.libretube.ui.viewholders.ChaptersViewHolder
|
import com.github.libretube.ui.viewholders.ChaptersViewHolder
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
|
|
||||||
class ChaptersAdapter(
|
class ChaptersAdapter(
|
||||||
private val chapters: List<ChapterSegment>,
|
private val chapters: List<ChapterSegment>,
|
||||||
|
@ -4,10 +4,10 @@ import android.annotation.SuppressLint
|
|||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.databinding.DialogStatsBinding
|
import com.github.libretube.databinding.DialogStatsBinding
|
||||||
import com.github.libretube.util.TextUtils
|
import com.github.libretube.util.TextUtils
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
|
||||||
class StatsDialog(
|
class StatsDialog(
|
||||||
|
@ -38,6 +38,17 @@ import androidx.fragment.app.activityViewModels
|
|||||||
import androidx.fragment.app.commit
|
import androidx.fragment.app.commit
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.media3.common.C
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||||
|
import androidx.media3.common.MimeTypes
|
||||||
|
import androidx.media3.common.PlaybackException
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.datasource.DefaultDataSource
|
||||||
|
import androidx.media3.datasource.cronet.CronetDataSource
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||||
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.CronetHelper
|
import com.github.libretube.api.CronetHelper
|
||||||
@ -99,24 +110,12 @@ import com.github.libretube.util.NowPlayingNotification
|
|||||||
import com.github.libretube.util.PlayingQueue
|
import com.github.libretube.util.PlayingQueue
|
||||||
import com.github.libretube.util.TextUtils
|
import com.github.libretube.util.TextUtils
|
||||||
import com.github.libretube.util.TextUtils.toTimeInSeconds
|
import com.github.libretube.util.TextUtils.toTimeInSeconds
|
||||||
import com.google.android.exoplayer2.C
|
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.exoplayer2.MediaItem
|
|
||||||
import com.google.android.exoplayer2.MediaItem.SubtitleConfiguration
|
|
||||||
import com.google.android.exoplayer2.PlaybackException
|
|
||||||
import com.google.android.exoplayer2.Player
|
|
||||||
import com.google.android.exoplayer2.ext.cronet.CronetDataSource
|
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSource
|
|
||||||
import com.google.android.exoplayer2.util.MimeTypes
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@ -124,6 +123,7 @@ import java.util.*
|
|||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||||
private var _binding: FragmentPlayerBinding? = null
|
private var _binding: FragmentPlayerBinding? = null
|
||||||
val binding get() = _binding!!
|
val binding get() = _binding!!
|
||||||
|
@ -7,13 +7,15 @@ import android.view.ViewGroup.MarginLayoutParams
|
|||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import androidx.core.math.MathUtils
|
import androidx.core.math.MathUtils
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.ui.TimeBar
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import com.github.libretube.api.obj.PreviewFrames
|
import com.github.libretube.api.obj.PreviewFrames
|
||||||
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
|
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
|
||||||
import com.github.libretube.helpers.ImageHelper
|
import com.github.libretube.helpers.ImageHelper
|
||||||
import com.github.libretube.obj.PreviewFrame
|
import com.github.libretube.obj.PreviewFrame
|
||||||
import com.google.android.exoplayer2.ui.TimeBar
|
|
||||||
|
|
||||||
|
@UnstableApi
|
||||||
class SeekbarPreviewListener(
|
class SeekbarPreviewListener(
|
||||||
private val previewFrames: List<PreviewFrames>,
|
private val previewFrames: List<PreviewFrames>,
|
||||||
private val playerBinding: ExoStyledPlayerControlViewBinding,
|
private val playerBinding: ExoStyledPlayerControlViewBinding,
|
||||||
@ -59,6 +61,8 @@ class SeekbarPreviewListener(
|
|||||||
playerBinding.seekbarPreview.alpha = 1f
|
playerBinding.seekbarPreview.alpha = 1f
|
||||||
}
|
}
|
||||||
.start()
|
.start()
|
||||||
|
|
||||||
|
onScrubEnd.invoke(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,12 +4,12 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.media3.common.PlaybackParameters
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.databinding.PlaybackBottomSheetBinding
|
import com.github.libretube.databinding.PlaybackBottomSheetBinding
|
||||||
import com.github.libretube.extensions.round
|
import com.github.libretube.extensions.round
|
||||||
import com.github.libretube.helpers.PreferenceHelper
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.exoplayer2.PlaybackParameters
|
|
||||||
|
|
||||||
class PlaybackOptionsSheet(
|
class PlaybackOptionsSheet(
|
||||||
private val player: ExoPlayer,
|
private val player: ExoPlayer,
|
||||||
|
@ -22,6 +22,16 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.core.view.marginStart
|
import androidx.core.view.marginStart
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.text.Cue
|
||||||
|
import androidx.media3.common.util.RepeatModeUtil
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.exoplayer.trackselection.TrackSelector
|
||||||
|
import androidx.media3.ui.AspectRatioFrameLayout
|
||||||
|
import androidx.media3.ui.CaptionStyleCompat
|
||||||
|
import androidx.media3.ui.PlayerView
|
||||||
|
import androidx.media3.ui.SubtitleView
|
||||||
|
import androidx.media3.ui.TimeBar
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.databinding.DoubleTapOverlayBinding
|
import com.github.libretube.databinding.DoubleTapOverlayBinding
|
||||||
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
|
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
|
||||||
@ -44,22 +54,13 @@ import com.github.libretube.ui.models.PlayerViewModel
|
|||||||
import com.github.libretube.ui.sheets.BaseBottomSheet
|
import com.github.libretube.ui.sheets.BaseBottomSheet
|
||||||
import com.github.libretube.ui.sheets.PlaybackOptionsSheet
|
import com.github.libretube.ui.sheets.PlaybackOptionsSheet
|
||||||
import com.github.libretube.util.PlayingQueue
|
import com.github.libretube.util.PlayingQueue
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.exoplayer2.Player
|
|
||||||
import com.google.android.exoplayer2.text.Cue
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelector
|
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
|
||||||
import com.google.android.exoplayer2.ui.CaptionStyleCompat
|
|
||||||
import com.google.android.exoplayer2.ui.StyledPlayerView
|
|
||||||
import com.google.android.exoplayer2.ui.SubtitleView
|
|
||||||
import com.google.android.exoplayer2.ui.TimeBar
|
|
||||||
import com.google.android.exoplayer2.util.RepeatModeUtil
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
internal class CustomExoPlayerView(
|
internal class CustomExoPlayerView(
|
||||||
context: Context,
|
context: Context,
|
||||||
attributeSet: AttributeSet? = null,
|
attributeSet: AttributeSet? = null,
|
||||||
) : StyledPlayerView(context, attributeSet), PlayerOptions, PlayerGestureOptions {
|
) : PlayerView(context, attributeSet), PlayerOptions, PlayerGestureOptions {
|
||||||
val binding: ExoStyledPlayerControlViewBinding = ExoStyledPlayerControlViewBinding.bind(this)
|
val binding: ExoStyledPlayerControlViewBinding = ExoStyledPlayerControlViewBinding.bind(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -405,7 +406,7 @@ internal class CustomExoPlayerView(
|
|||||||
if (isLocked) {
|
if (isLocked) {
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
context,
|
context,
|
||||||
com.google.android.exoplayer2.R.color.exo_black_opacity_60,
|
androidx.media3.ui.R.color.exo_black_opacity_60,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Color.TRANSPARENT
|
Color.TRANSPARENT
|
||||||
@ -600,12 +601,12 @@ internal class CustomExoPlayerView(
|
|||||||
.show(supportFragmentManager)
|
.show(supportFragmentManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration?) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
super.onConfigurationChanged(newConfig)
|
||||||
|
|
||||||
// add a larger bottom margin to the time bar in landscape mode
|
// add a larger bottom margin to the time bar in landscape mode
|
||||||
val offset = when {
|
val offset = when {
|
||||||
playerViewModel?.isFullscreen?.value ?: (newConfig?.orientation == Configuration.ORIENTATION_LANDSCAPE) -> 20.dpToPx()
|
playerViewModel?.isFullscreen?.value ?: (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) -> 20.dpToPx()
|
||||||
else -> 10.dpToPx()
|
else -> 10.dpToPx()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,7 +621,7 @@ internal class CustomExoPlayerView(
|
|||||||
if (!hasCutout && binding.topBar.marginStart == 0) return
|
if (!hasCutout && binding.topBar.marginStart == 0) return
|
||||||
|
|
||||||
// add a margin to the top and the bottom bar in landscape mode for notches
|
// add a margin to the top and the bottom bar in landscape mode for notches
|
||||||
val newMargin = when (newConfig?.orientation) {
|
val newMargin = when (newConfig.orientation) {
|
||||||
Configuration.ORIENTATION_LANDSCAPE -> LANDSCAPE_MARGIN_HORIZONTAL
|
Configuration.ORIENTATION_LANDSCAPE -> LANDSCAPE_MARGIN_HORIZONTAL
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,20 @@ import android.graphics.Rect
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.view.marginLeft
|
import androidx.core.view.marginLeft
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.ui.DefaultTimeBar
|
||||||
import com.github.libretube.api.obj.Segment
|
import com.github.libretube.api.obj.Segment
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.extensions.dpToPx
|
import com.github.libretube.extensions.dpToPx
|
||||||
import com.github.libretube.helpers.PreferenceHelper
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
import com.github.libretube.helpers.ThemeHelper
|
import com.github.libretube.helpers.ThemeHelper
|
||||||
import com.google.android.exoplayer2.Player
|
import com.google.android.material.R
|
||||||
import com.google.android.exoplayer2.ui.DefaultTimeBar
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TimeBar that can be marked with SponsorBlock Segments
|
* TimeBar that can be marked with SponsorBlock Segments
|
||||||
*/
|
*/
|
||||||
|
@UnstableApi
|
||||||
class MarkableTimeBar(
|
class MarkableTimeBar(
|
||||||
context: Context,
|
context: Context,
|
||||||
attributeSet: AttributeSet? = null,
|
attributeSet: AttributeSet? = null,
|
||||||
@ -57,7 +60,7 @@ class MarkableTimeBar(
|
|||||||
Paint().apply {
|
Paint().apply {
|
||||||
color = ThemeHelper.getThemeColor(
|
color = ThemeHelper.getThemeColor(
|
||||||
context,
|
context,
|
||||||
com.google.android.material.R.attr.colorOnSecondary,
|
R.attr.colorOnSecondary,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -12,13 +12,20 @@ import android.os.Bundle
|
|||||||
import android.support.v4.media.MediaDescriptionCompat
|
import android.support.v4.media.MediaDescriptionCompat
|
||||||
import android.support.v4.media.MediaMetadataCompat
|
import android.support.v4.media.MediaMetadataCompat
|
||||||
import android.support.v4.media.session.MediaSessionCompat
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
import android.support.v4.media.session.PlaybackStateCompat
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.PendingIntentCompat
|
import androidx.core.app.PendingIntentCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.session.CommandButton
|
||||||
|
import androidx.media3.session.DefaultMediaNotificationProvider
|
||||||
|
import androidx.media3.session.MediaSession
|
||||||
|
import androidx.media3.session.SessionCommand
|
||||||
|
import androidx.media3.session.SessionResult
|
||||||
|
import androidx.media3.ui.PlayerNotificationManager
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
||||||
@ -28,13 +35,10 @@ import com.github.libretube.helpers.ImageHelper
|
|||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.obj.PlayerNotificationData
|
import com.github.libretube.obj.PlayerNotificationData
|
||||||
import com.github.libretube.ui.activities.MainActivity
|
import com.github.libretube.ui.activities.MainActivity
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.android.exoplayer2.Player
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
|
|
||||||
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator
|
|
||||||
import com.google.android.exoplayer2.ui.PlayerNotificationManager
|
|
||||||
import com.google.android.exoplayer2.ui.PlayerNotificationManager.CustomActionReceiver
|
|
||||||
|
|
||||||
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
class NowPlayingNotification(
|
class NowPlayingNotification(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val player: ExoPlayer,
|
private val player: ExoPlayer,
|
||||||
@ -47,12 +51,7 @@ class NowPlayingNotification(
|
|||||||
/**
|
/**
|
||||||
* The [MediaSessionCompat] for the [notificationData].
|
* The [MediaSessionCompat] for the [notificationData].
|
||||||
*/
|
*/
|
||||||
private lateinit var mediaSession: MediaSessionCompat
|
private lateinit var mediaSession: MediaSession
|
||||||
|
|
||||||
/**
|
|
||||||
* The [MediaSessionConnector] to connect with the [mediaSession] and implement it with the [player].
|
|
||||||
*/
|
|
||||||
private lateinit var mediaSessionConnector: MediaSessionConnector
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [PlayerNotificationManager] to load the [mediaSession] content on it.
|
* The [PlayerNotificationManager] to load the [mediaSession] content on it.
|
||||||
@ -137,7 +136,7 @@ class NowPlayingNotification(
|
|||||||
ImageHelper.imageLoader.enqueue(request)
|
ImageHelper.imageLoader.enqueue(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val customActionReceiver = object : CustomActionReceiver {
|
private val customActionReceiver = object : PlayerNotificationManager.CustomActionReceiver {
|
||||||
override fun createCustomActions(
|
override fun createCustomActions(
|
||||||
context: Context,
|
context: Context,
|
||||||
instanceId: Int,
|
instanceId: Int,
|
||||||
@ -170,69 +169,89 @@ class NowPlayingNotification(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNotificationAction(drawableRes: Int, actionName: String, instanceId: Int): NotificationCompat.Action {
|
private fun createNotificationAction(
|
||||||
|
drawableRes: Int,
|
||||||
|
actionName: String,
|
||||||
|
instanceId: Int,
|
||||||
|
): NotificationCompat.Action {
|
||||||
val intent = Intent(actionName).setPackage(context.packageName)
|
val intent = Intent(actionName).setPackage(context.packageName)
|
||||||
val pendingIntent = PendingIntentCompat
|
val pendingIntent = PendingIntentCompat
|
||||||
.getBroadcast(context, instanceId, intent, PendingIntent.FLAG_CANCEL_CURRENT, false)
|
.getBroadcast(context, instanceId, intent, PendingIntent.FLAG_CANCEL_CURRENT, false)
|
||||||
return NotificationCompat.Action.Builder(drawableRes, actionName, pendingIntent).build()
|
return NotificationCompat.Action.Builder(drawableRes, actionName, pendingIntent).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createMediaSessionAction(@DrawableRes drawableRes: Int, actionName: String): MediaSessionConnector.CustomActionProvider {
|
private fun createMediaSessionAction(
|
||||||
return object : MediaSessionConnector.CustomActionProvider {
|
@DrawableRes drawableRes: Int,
|
||||||
override fun getCustomAction(player: Player): PlaybackStateCompat.CustomAction? {
|
actionName: String,
|
||||||
return PlaybackStateCompat.CustomAction.Builder(actionName, actionName, drawableRes).build()
|
): CommandButton {
|
||||||
}
|
return CommandButton.Builder()
|
||||||
|
.setDisplayName(actionName)
|
||||||
override fun onCustomAction(player: Player, action: String, extras: Bundle?) {
|
.setSessionCommand(SessionCommand(actionName, bundleOf()))
|
||||||
handlePlayerAction(action)
|
.setIconResId(drawableRes)
|
||||||
}
|
.build()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [MediaSessionCompat] amd a [MediaSessionConnector] for the player
|
* Creates a [MediaSessionCompat] for the player
|
||||||
*/
|
*/
|
||||||
private fun createMediaSession() {
|
private fun createMediaSession() {
|
||||||
if (this::mediaSession.isInitialized) return
|
if (this::mediaSession.isInitialized) return
|
||||||
mediaSession = MediaSessionCompat(context, this.javaClass.name).apply {
|
|
||||||
isActive = true
|
val sessionCallback = object : MediaSession.Callback {
|
||||||
|
override fun onConnect(
|
||||||
|
session: MediaSession,
|
||||||
|
controller: MediaSession.ControllerInfo,
|
||||||
|
): MediaSession.ConnectionResult {
|
||||||
|
val connectionResult = super.onConnect(session, controller)
|
||||||
|
val availablePlayerCommands = connectionResult.availablePlayerCommands.buildUpon()
|
||||||
|
.remove(Player.COMMAND_SEEK_TO_PREVIOUS)
|
||||||
|
.build()
|
||||||
|
return MediaSession.ConnectionResult.accept(
|
||||||
|
connectionResult.availableSessionCommands,
|
||||||
|
availablePlayerCommands,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCustomCommand(
|
||||||
|
session: MediaSession,
|
||||||
|
controller: MediaSession.ControllerInfo,
|
||||||
|
customCommand: SessionCommand,
|
||||||
|
args: Bundle,
|
||||||
|
): ListenableFuture<SessionResult> {
|
||||||
|
handlePlayerAction(customCommand.customAction)
|
||||||
|
return super.onCustomCommand(session, controller, customCommand, args)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaSessionConnector = MediaSessionConnector(mediaSession).apply {
|
mediaSession = MediaSession.Builder(context, player)
|
||||||
setPlayer(player)
|
.setCallback(sessionCallback)
|
||||||
setQueueNavigator(object : TimelineQueueNavigator(mediaSession) {
|
.build()
|
||||||
override fun getMediaDescription(
|
mediaSession.setCustomLayout(getCustomActions())
|
||||||
player: Player,
|
}
|
||||||
windowIndex: Int,
|
|
||||||
): MediaDescriptionCompat {
|
|
||||||
val appIcon = BitmapFactory.decodeResource(
|
|
||||||
context.resources,
|
|
||||||
R.drawable.ic_launcher_monochrome,
|
|
||||||
)
|
|
||||||
val extras = bundleOf(
|
|
||||||
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON to appIcon,
|
|
||||||
MediaMetadataCompat.METADATA_KEY_TITLE to notificationData?.title,
|
|
||||||
MediaMetadataCompat.METADATA_KEY_ARTIST to notificationData?.uploaderName,
|
|
||||||
)
|
|
||||||
return MediaDescriptionCompat.Builder()
|
|
||||||
.setTitle(notificationData?.title)
|
|
||||||
.setSubtitle(notificationData?.uploaderName)
|
|
||||||
.setIconBitmap(appIcon)
|
|
||||||
.setExtras(extras)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSupportedQueueNavigatorActions(player: Player): Long {
|
private fun getCustomActions() = mutableListOf(
|
||||||
return PlaybackStateCompat.ACTION_PLAY_PAUSE
|
createMediaSessionAction(R.drawable.ic_prev_outlined, PREV),
|
||||||
}
|
createMediaSessionAction(R.drawable.ic_next_outlined, NEXT),
|
||||||
})
|
createMediaSessionAction(R.drawable.ic_rewind_md, REWIND),
|
||||||
setCustomActionProviders(
|
createMediaSessionAction(R.drawable.ic_forward_md, FORWARD),
|
||||||
createMediaSessionAction(R.drawable.ic_prev_outlined, PREV),
|
)
|
||||||
createMediaSessionAction(R.drawable.ic_next_outlined, NEXT),
|
|
||||||
createMediaSessionAction(R.drawable.ic_rewind_md, REWIND),
|
private fun getMediaDescription(): MediaDescriptionCompat {
|
||||||
createMediaSessionAction(R.drawable.ic_forward_md, FORWARD),
|
val appIcon = BitmapFactory.decodeResource(
|
||||||
)
|
context.resources,
|
||||||
}
|
R.drawable.ic_launcher_monochrome,
|
||||||
|
)
|
||||||
|
val extras = bundleOf(
|
||||||
|
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON to appIcon,
|
||||||
|
MediaMetadataCompat.METADATA_KEY_TITLE to notificationData?.title,
|
||||||
|
MediaMetadataCompat.METADATA_KEY_ARTIST to notificationData?.uploaderName,
|
||||||
|
)
|
||||||
|
return MediaDescriptionCompat.Builder()
|
||||||
|
.setTitle(notificationData?.title)
|
||||||
|
.setSubtitle(notificationData?.uploaderName)
|
||||||
|
.setIconBitmap(appIcon)
|
||||||
|
.setExtras(extras)
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handlePlayerAction(action: String) {
|
private fun handlePlayerAction(action: String) {
|
||||||
@ -244,6 +263,7 @@ class NowPlayingNotification(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PREV -> {
|
PREV -> {
|
||||||
if (PlayingQueue.hasPrev()) {
|
if (PlayingQueue.hasPrev()) {
|
||||||
PlayingQueue.onQueueItemSelected(
|
PlayingQueue.onQueueItemSelected(
|
||||||
@ -251,9 +271,11 @@ class NowPlayingNotification(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
REWIND -> {
|
REWIND -> {
|
||||||
player.seekTo(player.currentPosition - PlayerHelper.seekIncrement)
|
player.seekTo(player.currentPosition - PlayerHelper.seekIncrement)
|
||||||
}
|
}
|
||||||
|
|
||||||
FORWARD -> {
|
FORWARD -> {
|
||||||
player.seekTo(player.currentPosition + PlayerHelper.seekIncrement)
|
player.seekTo(player.currentPosition + PlayerHelper.seekIncrement)
|
||||||
}
|
}
|
||||||
@ -278,6 +300,19 @@ class NowPlayingNotification(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NotificationProvider(val context: Context) : DefaultMediaNotificationProvider(context) {
|
||||||
|
override fun getMediaButtons(
|
||||||
|
session: MediaSession,
|
||||||
|
playerCommands: Player.Commands,
|
||||||
|
customLayout: ImmutableList<CommandButton>,
|
||||||
|
showPauseButton: Boolean,
|
||||||
|
): ImmutableList<CommandButton> {
|
||||||
|
val buttons = super.getMediaButtons(session, playerCommands, customLayout, showPauseButton)
|
||||||
|
buttons.removeFirst()
|
||||||
|
return buttons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the [playerNotification] attached to the [player] and shows it.
|
* Initializes the [playerNotification] attached to the [player] and shows it.
|
||||||
*/
|
*/
|
||||||
@ -291,7 +326,7 @@ class NowPlayingNotification(
|
|||||||
.build().apply {
|
.build().apply {
|
||||||
setPlayer(player)
|
setPlayer(player)
|
||||||
setColorized(true)
|
setColorized(true)
|
||||||
setMediaSessionToken(mediaSession.sessionToken)
|
setMediaSessionToken(mediaSession.sessionCompatToken)
|
||||||
setSmallIcon(R.drawable.ic_launcher_lockscreen)
|
setSmallIcon(R.drawable.ic_launcher_lockscreen)
|
||||||
setUseNextAction(false)
|
setUseNextAction(false)
|
||||||
setUsePreviousAction(false)
|
setUsePreviousAction(false)
|
||||||
@ -305,7 +340,6 @@ class NowPlayingNotification(
|
|||||||
fun destroySelfAndPlayer() {
|
fun destroySelfAndPlayer() {
|
||||||
playerNotification?.setPlayer(null)
|
playerNotification?.setPlayer(null)
|
||||||
|
|
||||||
mediaSession.isActive = false
|
|
||||||
mediaSession.release()
|
mediaSession.release()
|
||||||
|
|
||||||
player.stop()
|
player.stop()
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/black"
|
android:background="@android:color/black"
|
||||||
|
app:controller_layout_id="@layout/exo_styled_player_control_view"
|
||||||
app:show_buffering="when_playing">
|
app:show_buffering="when_playing">
|
||||||
|
|
||||||
<com.github.libretube.ui.views.DoubleTapOverlay
|
<com.github.libretube.ui.views.DoubleTapOverlay
|
||||||
|
@ -304,6 +304,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/black"
|
android:background="@android:color/black"
|
||||||
|
app:controller_layout_id="@layout/exo_styled_player_control_view"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/main_container"
|
app:layout_constraintBottom_toBottomOf="@id/main_container"
|
||||||
app:layout_constraintStart_toStartOf="@id/main_container"
|
app:layout_constraintStart_toStartOf="@id/main_container"
|
||||||
app:layout_constraintTop_toTopOf="@id/main_container"
|
app:layout_constraintTop_toTopOf="@id/main_container"
|
||||||
@ -349,7 +350,7 @@
|
|||||||
app:drawableTint="@android:color/white" />
|
app:drawableTint="@android:color/white" />
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.github.libretube.ui.views.AutoplayCountdownView
|
<com.github.libretube.ui.views.AutoplayCountdownView
|
||||||
android:id="@+id/autoplay_countdown"
|
android:id="@+id/autoplay_countdown"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<string name="app_name" translatable="false">LibreTube</string>
|
||||||
<string name="startpage">Home</string>
|
<string name="startpage">Home</string>
|
||||||
<string name="subscriptions">Subscriptions</string>
|
<string name="subscriptions">Subscriptions</string>
|
||||||
<string name="library">Library</string>
|
<string name="library">Library</string>
|
||||||
|
@ -10,7 +10,6 @@ preference = "1.2.0"
|
|||||||
extJunit = "1.1.5"
|
extJunit = "1.1.5"
|
||||||
espresso = "3.5.1"
|
espresso = "3.5.1"
|
||||||
workRuntime = "2.8.1"
|
workRuntime = "2.8.1"
|
||||||
exoplayer = "2.18.6"
|
|
||||||
retrofit = "2.9.0"
|
retrofit = "2.9.0"
|
||||||
desugaring = "2.0.3"
|
desugaring = "2.0.3"
|
||||||
cronetEmbedded = "108.5359.79"
|
cronetEmbedded = "108.5359.79"
|
||||||
@ -21,6 +20,7 @@ room = "2.5.1"
|
|||||||
kotlinxSerialization = "1.5.1"
|
kotlinxSerialization = "1.5.1"
|
||||||
kotlinxDatetime = "0.4.0"
|
kotlinxDatetime = "0.4.0"
|
||||||
kotlinxRetrofit = "1.0.0"
|
kotlinxRetrofit = "1.0.0"
|
||||||
|
media3 = "1.0.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||||
@ -34,12 +34,14 @@ androidx-preference = { group = "androidx.preference", name = "preference-ktx",
|
|||||||
androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "extJunit" }
|
androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "extJunit" }
|
||||||
androidx-test-espressoCore = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
|
androidx-test-espressoCore = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
|
||||||
androidx-work-runtime = { group = "androidx.work", name="work-runtime-ktx", version.ref="workRuntime" }
|
androidx-work-runtime = { group = "androidx.work", name="work-runtime-ktx", version.ref="workRuntime" }
|
||||||
exoplayer = { group = "com.google.android.exoplayer", name = "exoplayer", version.ref = "exoplayer" }
|
androidx-media3-exoplayer = { group = "androidx.media3", name="media3-exoplayer", version.ref="media3" }
|
||||||
exoplayer-extension-mediasession = { group = "com.google.android.exoplayer", name = "extension-mediasession", version.ref = "exoplayer" }
|
androidx-media3-exoplayer-hls = { group = "androidx.media3", name="media3-exoplayer-hls", version.ref="media3" }
|
||||||
|
androidx-media3-exoplayer-dash = { group = "androidx.media3", name="media3-exoplayer-dash", version.ref="media3" }
|
||||||
|
androidx-media3-datasource-cronet = { group = "androidx.media3", name = "media3-datasource-cronet", version.ref = "media3" }
|
||||||
|
androidx-media3-session = { group="androidx.media3", name="media3-session", version.ref="media3" }
|
||||||
|
androidx-media3-ui = { group="androidx.media3", name="media3-ui", version.ref="media3" }
|
||||||
square-retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
|
square-retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
|
||||||
desugaring = { group = "com.android.tools", name = "desugar_jdk_libs_nio", version.ref = "desugaring" }
|
desugaring = { group = "com.android.tools", name = "desugar_jdk_libs_nio", version.ref = "desugaring" }
|
||||||
exoplayer-extension-cronet = { group = "com.google.android.exoplayer", name = "extension-cronet", version.ref = "exoplayer" }
|
|
||||||
exoplayer-dash = { group = "com.google.android.exoplayer", name = "exoplayer-dash", version.ref = "exoplayer" }
|
|
||||||
cronet-embedded = { group = "org.chromium.net", name = "cronet-embedded", version.ref = "cronetEmbedded" }
|
cronet-embedded = { group = "org.chromium.net", name = "cronet-embedded", version.ref = "cronetEmbedded" }
|
||||||
cronet-okhttp = { group = "com.google.net.cronet", name = "cronet-okhttp", version.ref = "cronetOkHttp" }
|
cronet-okhttp = { group = "com.google.net.cronet", name = "cronet-okhttp", version.ref = "cronetOkHttp" }
|
||||||
coil = { group = "io.coil-kt", name = "coil", version.ref="coil" }
|
coil = { group = "io.coil-kt", name = "coil", version.ref="coil" }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user