mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-13 22:00:30 +05:30
Merge pull request #5925 from Bnyro/master
refactor: simplify notification/player actions logic
This commit is contained in:
commit
221a33c623
@ -6,5 +6,6 @@ enum class PlayerEvent {
|
||||
Rewind,
|
||||
Next,
|
||||
Prev,
|
||||
Background
|
||||
Background,
|
||||
Stop
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
@ -38,6 +39,8 @@ import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.db.obj.WatchPosition
|
||||
import com.github.libretube.enums.PlayerEvent
|
||||
import com.github.libretube.enums.SbSkipOptions
|
||||
import com.github.libretube.extensions.seekBy
|
||||
import com.github.libretube.extensions.togglePlayPauseState
|
||||
import com.github.libretube.extensions.updateParameters
|
||||
import com.github.libretube.obj.VideoStats
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
@ -800,4 +803,25 @@ object PlayerHelper {
|
||||
DatabaseHolder.Database.watchPositionDao().insert(watchPosition)
|
||||
}
|
||||
}
|
||||
|
||||
fun handlePlayerAction(player: Player, playerEvent: PlayerEvent): Boolean {
|
||||
return when (playerEvent) {
|
||||
PlayerEvent.PlayPause -> {
|
||||
player.togglePlayPauseState()
|
||||
true
|
||||
}
|
||||
|
||||
PlayerEvent.Forward -> {
|
||||
player.seekBy(PlayerHelper.seekIncrement)
|
||||
true
|
||||
}
|
||||
|
||||
PlayerEvent.Rewind -> {
|
||||
player.seekBy(-PlayerHelper.seekIncrement)
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
package com.github.libretube.services
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Handler
|
||||
import android.os.IBinder
|
||||
import android.os.Looper
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.ServiceCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.LifecycleService
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.C
|
||||
@ -22,6 +26,8 @@ import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.db.obj.DownloadWithItems
|
||||
import com.github.libretube.enums.FileType
|
||||
import com.github.libretube.enums.NotificationId
|
||||
import com.github.libretube.enums.PlayerEvent
|
||||
import com.github.libretube.extensions.serializableExtra
|
||||
import com.github.libretube.extensions.toAndroidUri
|
||||
import com.github.libretube.extensions.updateParameters
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
@ -75,6 +81,20 @@ class OfflinePlayerService : LifecycleService() {
|
||||
}
|
||||
}
|
||||
|
||||
private val playerActionReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val event = intent.serializableExtra<PlayerEvent>(PlayerHelper.CONTROL_TYPE) ?: return
|
||||
val player = player ?: return
|
||||
|
||||
if (PlayerHelper.handlePlayerAction(player, event)) return
|
||||
|
||||
when (event) {
|
||||
PlayerEvent.Stop -> onDestroy()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
@ -85,6 +105,13 @@ class OfflinePlayerService : LifecycleService() {
|
||||
.build()
|
||||
|
||||
startForeground(NotificationId.PLAYER_PLAYBACK.id, notification)
|
||||
|
||||
ContextCompat.registerReceiver(
|
||||
this,
|
||||
playerActionReceiver,
|
||||
IntentFilter(PlayerHelper.getIntentActionName(this)),
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
@ -189,6 +216,7 @@ class OfflinePlayerService : LifecycleService() {
|
||||
nowPlayingNotification = null
|
||||
|
||||
watchPositionTimer.destroy()
|
||||
unregisterReceiver(playerActionReceiver)
|
||||
|
||||
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
|
||||
stopSelf()
|
||||
|
@ -1,7 +1,10 @@
|
||||
package com.github.libretube.services
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Binder
|
||||
import android.os.Handler
|
||||
import android.os.IBinder
|
||||
@ -9,6 +12,7 @@ import android.os.Looper
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.ServiceCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.LifecycleService
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@ -30,7 +34,9 @@ import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.db.DatabaseHelper
|
||||
import com.github.libretube.enums.NotificationId
|
||||
import com.github.libretube.enums.PlayerEvent
|
||||
import com.github.libretube.extensions.parcelableExtra
|
||||
import com.github.libretube.extensions.serializableExtra
|
||||
import com.github.libretube.extensions.setMetadata
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.extensions.updateParameters
|
||||
@ -159,6 +165,28 @@ class OnlinePlayerService : LifecycleService() {
|
||||
}
|
||||
}
|
||||
|
||||
private val playerActionReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val event = intent.serializableExtra<PlayerEvent>(PlayerHelper.CONTROL_TYPE) ?: return
|
||||
val player = player ?: return
|
||||
|
||||
if (PlayerHelper.handlePlayerAction(player, event)) return
|
||||
|
||||
when (event) {
|
||||
PlayerEvent.Next -> {
|
||||
PlayingQueue.navigateNext()
|
||||
}
|
||||
PlayerEvent.Prev -> {
|
||||
PlayingQueue.navigatePrev()
|
||||
}
|
||||
PlayerEvent.Stop -> {
|
||||
onDestroy()
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting the required [Notification] for running as a foreground service
|
||||
*/
|
||||
@ -172,6 +200,13 @@ class OnlinePlayerService : LifecycleService() {
|
||||
.build()
|
||||
|
||||
startForeground(NotificationId.PLAYER_PLAYBACK.id, notification)
|
||||
|
||||
ContextCompat.registerReceiver(
|
||||
this,
|
||||
playerActionReceiver,
|
||||
IntentFilter(PlayerHelper.getIntentActionName(this)),
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -338,7 +373,8 @@ class OnlinePlayerService : LifecycleService() {
|
||||
this,
|
||||
) to MimeTypes.APPLICATION_MPD
|
||||
} else {
|
||||
ProxyHelper.unwrapStreamUrl(streams.hls.orEmpty()).toUri() to MimeTypes.APPLICATION_M3U8
|
||||
ProxyHelper.unwrapStreamUrl(streams.hls.orEmpty())
|
||||
.toUri() to MimeTypes.APPLICATION_M3U8
|
||||
}
|
||||
|
||||
val mediaItem = MediaItem.Builder()
|
||||
@ -395,6 +431,7 @@ class OnlinePlayerService : LifecycleService() {
|
||||
player?.release()
|
||||
|
||||
watchPositionTimer.destroy()
|
||||
unregisterReceiver(playerActionReceiver)
|
||||
|
||||
// called when the user pressed stop in the notification
|
||||
// stop the service from being in the foreground and remove the notification
|
||||
|
@ -36,10 +36,8 @@ import com.github.libretube.db.DatabaseHolder.Database
|
||||
import com.github.libretube.db.obj.DownloadChapter
|
||||
import com.github.libretube.enums.FileType
|
||||
import com.github.libretube.enums.PlayerEvent
|
||||
import com.github.libretube.extensions.seekBy
|
||||
import com.github.libretube.extensions.serializableExtra
|
||||
import com.github.libretube.extensions.toAndroidUri
|
||||
import com.github.libretube.extensions.togglePlayPauseState
|
||||
import com.github.libretube.extensions.updateParameters
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.helpers.WindowHelper
|
||||
@ -115,21 +113,8 @@ class OfflinePlayerActivity : BaseActivity() {
|
||||
|
||||
private val playerActionReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.serializableExtra<PlayerEvent>(PlayerHelper.CONTROL_TYPE) ?: return) {
|
||||
PlayerEvent.PlayPause -> {
|
||||
player.togglePlayPauseState()
|
||||
}
|
||||
|
||||
PlayerEvent.Forward -> {
|
||||
player.seekBy(PlayerHelper.seekIncrement)
|
||||
}
|
||||
|
||||
PlayerEvent.Rewind -> {
|
||||
player.seekBy(-PlayerHelper.seekIncrement)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
val event = intent.serializableExtra<PlayerEvent>(PlayerHelper.CONTROL_TYPE) ?: return
|
||||
PlayerHelper.handlePlayerAction(player, event)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,6 @@ import com.github.libretube.enums.PlayerEvent
|
||||
import com.github.libretube.enums.ShareObjectType
|
||||
import com.github.libretube.extensions.formatShort
|
||||
import com.github.libretube.extensions.parcelable
|
||||
import com.github.libretube.extensions.seekBy
|
||||
import com.github.libretube.extensions.serializableExtra
|
||||
import com.github.libretube.extensions.setMetadata
|
||||
import com.github.libretube.extensions.toID
|
||||
@ -204,23 +203,19 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
*/
|
||||
private val playerActionReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.serializableExtra<PlayerEvent>(PlayerHelper.CONTROL_TYPE) ?: return) {
|
||||
PlayerEvent.PlayPause -> {
|
||||
exoPlayer.togglePlayPauseState()
|
||||
}
|
||||
val event = intent.serializableExtra<PlayerEvent>(PlayerHelper.CONTROL_TYPE) ?: return
|
||||
|
||||
PlayerEvent.Forward -> {
|
||||
exoPlayer.seekBy(PlayerHelper.seekIncrement)
|
||||
}
|
||||
|
||||
PlayerEvent.Rewind -> {
|
||||
exoPlayer.seekBy(-PlayerHelper.seekIncrement)
|
||||
}
|
||||
if (PlayerHelper.handlePlayerAction(exoPlayer, event)) return
|
||||
|
||||
when (event) {
|
||||
PlayerEvent.Next -> {
|
||||
playNextVideo(PlayingQueue.getNext())
|
||||
}
|
||||
|
||||
PlayerEvent.Prev -> {
|
||||
playNextVideo(PlayingQueue.getPrev())
|
||||
}
|
||||
|
||||
PlayerEvent.Background -> {
|
||||
playOnBackground()
|
||||
// wait some time in order for the service to get started properly
|
||||
|
@ -2,10 +2,8 @@ package com.github.libretube.util
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -14,7 +12,6 @@ import android.support.v4.media.session.PlaybackStateCompat
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.media.app.NotificationCompat.MediaStyle
|
||||
@ -26,14 +23,11 @@ import com.github.libretube.LibreTubeApp.Companion.PLAYER_CHANNEL_NAME
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.enums.NotificationId
|
||||
import com.github.libretube.extensions.seekBy
|
||||
import com.github.libretube.enums.PlayerEvent
|
||||
import com.github.libretube.extensions.toMediaMetadataCompat
|
||||
import com.github.libretube.extensions.togglePlayPauseState
|
||||
import com.github.libretube.helpers.BackgroundHelper
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.obj.PlayerNotificationData
|
||||
import com.github.libretube.services.OfflinePlayerService
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import java.util.UUID
|
||||
|
||||
@ -133,14 +127,14 @@ class NowPlayingNotification(
|
||||
|
||||
private val legacyNotificationButtons
|
||||
get() = listOf(
|
||||
createNotificationAction(R.drawable.ic_prev_outlined, PREV),
|
||||
createNotificationAction(R.drawable.ic_prev_outlined, PlayerEvent.Prev.name),
|
||||
createNotificationAction(
|
||||
if (player.isPlaying) R.drawable.ic_pause else R.drawable.ic_play,
|
||||
PLAY_PAUSE
|
||||
PlayerEvent.PlayPause.name
|
||||
),
|
||||
createNotificationAction(R.drawable.ic_next_outlined, NEXT),
|
||||
createNotificationAction(R.drawable.ic_rewind_md, REWIND),
|
||||
createNotificationAction(R.drawable.ic_forward_md, FORWARD)
|
||||
createNotificationAction(R.drawable.ic_next_outlined, PlayerEvent.Next.name),
|
||||
createNotificationAction(R.drawable.ic_rewind_md, PlayerEvent.Rewind.name),
|
||||
createNotificationAction(R.drawable.ic_forward_md, PlayerEvent.Forward.name)
|
||||
)
|
||||
|
||||
private fun createNotificationAction(
|
||||
@ -165,38 +159,38 @@ class NowPlayingNotification(
|
||||
if (this::mediaSession.isInitialized) return
|
||||
|
||||
val sessionCallback = object : MediaSessionCompat.Callback() {
|
||||
override fun onSkipToNext() {
|
||||
handlePlayerAction(NEXT)
|
||||
super.onSkipToNext()
|
||||
}
|
||||
|
||||
override fun onSkipToPrevious() {
|
||||
handlePlayerAction(PREV)
|
||||
super.onSkipToPrevious()
|
||||
}
|
||||
|
||||
override fun onRewind() {
|
||||
handlePlayerAction(REWIND)
|
||||
handlePlayerAction(PlayerEvent.Rewind)
|
||||
super.onRewind()
|
||||
}
|
||||
|
||||
override fun onFastForward() {
|
||||
handlePlayerAction(FORWARD)
|
||||
handlePlayerAction(PlayerEvent.Forward)
|
||||
super.onFastForward()
|
||||
}
|
||||
|
||||
override fun onPlay() {
|
||||
handlePlayerAction(PLAY_PAUSE)
|
||||
handlePlayerAction(PlayerEvent.PlayPause)
|
||||
super.onPlay()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
handlePlayerAction(PLAY_PAUSE)
|
||||
handlePlayerAction(PlayerEvent.PlayPause)
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onSkipToNext() {
|
||||
handlePlayerAction(PlayerEvent.Next)
|
||||
super.onSkipToNext()
|
||||
}
|
||||
|
||||
override fun onSkipToPrevious() {
|
||||
handlePlayerAction(PlayerEvent.Prev)
|
||||
super.onSkipToPrevious()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
handlePlayerAction(STOP)
|
||||
handlePlayerAction(PlayerEvent.Stop)
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
@ -206,7 +200,7 @@ class NowPlayingNotification(
|
||||
}
|
||||
|
||||
override fun onCustomAction(action: String, extras: Bundle?) {
|
||||
handlePlayerAction(action)
|
||||
runCatching { handlePlayerAction(PlayerEvent.valueOf(action)) }
|
||||
super.onCustomAction(action, extras)
|
||||
}
|
||||
}
|
||||
@ -272,47 +266,20 @@ class NowPlayingNotification(
|
||||
|
||||
return PlaybackStateCompat.Builder()
|
||||
.setActions(stateActions)
|
||||
.addCustomAction(createMediaSessionAction(R.drawable.ic_rewind_md, REWIND))
|
||||
.addCustomAction(createMediaSessionAction(R.drawable.ic_forward_md, FORWARD))
|
||||
.addCustomAction(createMediaSessionAction(R.drawable.ic_rewind_md, PlayerEvent.Rewind.name))
|
||||
.addCustomAction(createMediaSessionAction(R.drawable.ic_forward_md, PlayerEvent.Forward.name))
|
||||
.setState(state, player.currentPosition, player.playbackParameters.speed)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun handlePlayerAction(action: String) {
|
||||
when (action) {
|
||||
NEXT -> {
|
||||
PlayingQueue.navigateNext()
|
||||
}
|
||||
|
||||
PREV -> {
|
||||
PlayingQueue.navigatePrev()
|
||||
}
|
||||
|
||||
REWIND -> {
|
||||
player.seekBy(-PlayerHelper.seekIncrement)
|
||||
}
|
||||
|
||||
FORWARD -> {
|
||||
player.seekBy(PlayerHelper.seekIncrement)
|
||||
}
|
||||
|
||||
PLAY_PAUSE -> {
|
||||
player.togglePlayPauseState()
|
||||
}
|
||||
|
||||
STOP -> {
|
||||
when (notificationType) {
|
||||
NowPlayingNotificationType.AUDIO_ONLINE -> BackgroundHelper.stopBackgroundPlay(
|
||||
context
|
||||
)
|
||||
NowPlayingNotificationType.AUDIO_OFFLINE -> BackgroundHelper.stopBackgroundPlay(
|
||||
context,
|
||||
OfflinePlayerService::class.java
|
||||
)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Forward the action to the responsible notification owner (e.g. PlayerFragment)
|
||||
*/
|
||||
private fun handlePlayerAction(action: PlayerEvent) {
|
||||
val intent = Intent(PlayerHelper.getIntentActionName(context))
|
||||
.setPackage(context.packageName)
|
||||
.putExtra(PlayerHelper.CONTROL_TYPE, action)
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -329,7 +296,6 @@ class NowPlayingNotification(
|
||||
if (notificationBuilder == null) {
|
||||
createMediaSession()
|
||||
createNotificationBuilder()
|
||||
createActionReceiver()
|
||||
// update the notification each time the player continues playing or pauses
|
||||
player.addListener(object : Player.Listener {
|
||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||
@ -349,7 +315,7 @@ class NowPlayingNotification(
|
||||
notificationBuilder = NotificationCompat.Builder(context, PLAYER_CHANNEL_NAME)
|
||||
.setSmallIcon(R.drawable.ic_launcher_lockscreen)
|
||||
.setContentIntent(createCurrentContentIntent())
|
||||
.setDeleteIntent(createIntent(STOP))
|
||||
.setDeleteIntent(createIntent(PlayerEvent.Stop.name))
|
||||
.setStyle(
|
||||
MediaStyle()
|
||||
.setMediaSession(mediaSession.sessionToken)
|
||||
@ -374,36 +340,12 @@ class NowPlayingNotification(
|
||||
nManager.notify(NotificationId.PLAYER_PLAYBACK.id, notification)
|
||||
}
|
||||
|
||||
private val notificationActionReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
handlePlayerAction(intent.action ?: return)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createActionReceiver() {
|
||||
val filter = IntentFilter().apply {
|
||||
listOf(PREV, NEXT, REWIND, FORWARD, PLAY_PAUSE, STOP).forEach {
|
||||
addAction(it)
|
||||
}
|
||||
}
|
||||
ContextCompat.registerReceiver(
|
||||
context,
|
||||
notificationActionReceiver,
|
||||
filter,
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the [NowPlayingNotification]
|
||||
*/
|
||||
fun destroySelf() {
|
||||
mediaSession.release()
|
||||
|
||||
runCatching {
|
||||
context.unregisterReceiver(notificationActionReceiver)
|
||||
}
|
||||
|
||||
nManager.cancel(NotificationId.PLAYER_PLAYBACK.id)
|
||||
}
|
||||
|
||||
@ -416,13 +358,6 @@ class NowPlayingNotification(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PREV = "prev"
|
||||
private const val NEXT = "next"
|
||||
private const val REWIND = "rewind"
|
||||
private const val FORWARD = "forward"
|
||||
private const val PLAY_PAUSE = "play_pause"
|
||||
private const val STOP = "stop"
|
||||
|
||||
enum class NowPlayingNotificationType {
|
||||
VIDEO_ONLINE,
|
||||
VIDEO_OFFLINE,
|
||||
|
Loading…
Reference in New Issue
Block a user