feat: audio player UI for downloads

This commit is contained in:
Bnyro 2024-10-06 16:03:00 +02:00
parent f0fb359b5d
commit 9b68e4faea
12 changed files with 93 additions and 81 deletions

View File

@ -48,4 +48,5 @@ object IntentData {
const val videoList = "videoList" const val videoList = "videoList"
const val nextPage = "nextPage" const val nextPage = "nextPage"
const val videoInfo = "videoInfo" const val videoInfo = "videoInfo"
const val offlinePlayer = "offlinePlayer"
} }

View File

@ -50,13 +50,9 @@ object BackgroundHelper {
/** /**
* Stop the [OnlinePlayerService] service if it is running. * Stop the [OnlinePlayerService] service if it is running.
*/ */
fun stopBackgroundPlay( fun stopBackgroundPlay(context: Context) {
context: Context, arrayOf(OnlinePlayerService::class.java, OfflinePlayerService::class.java).forEach {
serviceClass: Class<*> = OnlinePlayerService::class.java val intent = Intent(context, it)
) {
if (isBackgroundServiceRunning(context, serviceClass)) {
// Intent to stop background mode service
val intent = Intent(context, serviceClass)
context.stopService(intent) context.stopService(intent)
} }
} }
@ -80,10 +76,11 @@ object BackgroundHelper {
* @param videoId the videoId of the video or null if all available downloads should be shuffled * @param videoId the videoId of the video or null if all available downloads should be shuffled
*/ */
fun playOnBackgroundOffline(context: Context, videoId: String?) { fun playOnBackgroundOffline(context: Context, videoId: String?) {
stopBackgroundPlay(context)
val playerIntent = Intent(context, OfflinePlayerService::class.java) val playerIntent = Intent(context, OfflinePlayerService::class.java)
.putExtra(IntentData.videoId, videoId) .putExtra(IntentData.videoId, videoId)
context.stopService(playerIntent)
ContextCompat.startForegroundService(context, playerIntent) ContextCompat.startForegroundService(context, playerIntent)
} }
} }

View File

@ -96,10 +96,13 @@ object NavigationHelper {
/** /**
* Start the audio player fragment * Start the audio player fragment
*/ */
fun startAudioPlayer(context: Context, minimizeByDefault: Boolean = false) { fun startAudioPlayer(context: Context, offlinePlayer: Boolean = false, minimizeByDefault: Boolean = false) {
val activity = ContextHelper.unwrapActivity(context) val activity = ContextHelper.unwrapActivity(context)
activity.supportFragmentManager.commitNow { activity.supportFragmentManager.commitNow {
val args = bundleOf(IntentData.minimizeByDefault to minimizeByDefault) val args = bundleOf(
IntentData.minimizeByDefault to minimizeByDefault,
IntentData.offlinePlayer to offlinePlayer
)
replace<AudioPlayerFragment>(R.id.container, args = args) replace<AudioPlayerFragment>(R.id.container, args = args)
} }
} }

View File

@ -4,9 +4,11 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.os.Binder
import android.os.Handler import android.os.Handler
import android.os.IBinder import android.os.IBinder
import android.os.Looper import android.os.Looper
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.annotation.OptIn import androidx.annotation.OptIn
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
@ -22,6 +24,8 @@ import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
import com.github.libretube.LibreTubeApp.Companion.PLAYER_CHANNEL_NAME import com.github.libretube.LibreTubeApp.Companion.PLAYER_CHANNEL_NAME
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.api.obj.ChapterSegment
import com.github.libretube.api.obj.StreamItem
import com.github.libretube.enums.NotificationId import com.github.libretube.enums.NotificationId
import com.github.libretube.enums.PlayerEvent import com.github.libretube.enums.PlayerEvent
import com.github.libretube.extensions.serializableExtra import com.github.libretube.extensions.serializableExtra
@ -43,6 +47,14 @@ abstract class AbstractPlayerService : LifecycleService() {
val handler = Handler(Looper.getMainLooper()) val handler = Handler(Looper.getMainLooper())
private val binder = LocalBinder()
/**
* Listener for passing playback state changes to the AudioPlayerFragment
*/
var onStateOrPlayingChanged: ((isPlaying: Boolean) -> Unit)? = null
var onNewVideoStarted: ((streamItem: StreamItem) -> Unit)? = null
private val watchPositionTimer = PauseableTimer( private val watchPositionTimer = PauseableTimer(
onTick = ::saveWatchPosition, onTick = ::saveWatchPosition,
delayMillis = PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS delayMillis = PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS
@ -58,11 +70,15 @@ abstract class AbstractPlayerService : LifecycleService() {
} else { } else {
watchPositionTimer.pause() watchPositionTimer.pause()
} }
onStateOrPlayingChanged?.let { it(isPlaying) }
} }
override fun onPlaybackStateChanged(playbackState: Int) { override fun onPlaybackStateChanged(playbackState: Int) {
super.onPlaybackStateChanged(playbackState) super.onPlaybackStateChanged(playbackState)
onStateOrPlayingChanged?.let { it(player?.isPlaying ?: false) }
this@AbstractPlayerService.onPlaybackStateChanged(playbackState) this@AbstractPlayerService.onPlaybackStateChanged(playbackState)
} }
@ -162,8 +178,7 @@ abstract class AbstractPlayerService : LifecycleService() {
nowPlayingNotification = NowPlayingNotification( nowPlayingNotification = NowPlayingNotification(
this, this,
player!!, player!!
NowPlayingNotification.Companion.NowPlayingNotificationType.AUDIO_OFFLINE
) )
} }
@ -202,11 +217,6 @@ abstract class AbstractPlayerService : LifecycleService() {
super.onDestroy() super.onDestroy()
} }
override fun onBind(intent: Intent): IBinder? {
super.onBind(intent)
return null
}
/** /**
* Stop the service when app is removed from the task manager. * Stop the service when app is removed from the task manager.
*/ */
@ -217,9 +227,21 @@ abstract class AbstractPlayerService : LifecycleService() {
abstract fun onPlaybackStateChanged(playbackState: Int) abstract fun onPlaybackStateChanged(playbackState: Int)
abstract fun getChapters(): List<ChapterSegment>
fun getCurrentPosition() = player?.currentPosition fun getCurrentPosition() = player?.currentPosition
fun getDuration() = player?.duration fun getDuration() = player?.duration
fun seekToPosition(position: Long) = player?.seekTo(position) fun seekToPosition(position: Long) = player?.seekTo(position)
inner class LocalBinder : Binder() {
// Return this instance of [AbstractPlayerService] so clients can call public methods
fun getService(): AbstractPlayerService = this@AbstractPlayerService
}
override fun onBind(intent: Intent): IBinder {
super.onBind(intent)
return binder
}
} }

View File

@ -1,13 +1,16 @@
package com.github.libretube.services package com.github.libretube.services
import android.content.Intent import android.content.Intent
import android.os.IBinder import android.util.Log
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import com.github.libretube.api.obj.ChapterSegment
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.db.DatabaseHolder.Database import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.DownloadChapter
import com.github.libretube.db.obj.DownloadWithItems
import com.github.libretube.enums.FileType import com.github.libretube.enums.FileType
import com.github.libretube.extensions.toAndroidUri import com.github.libretube.extensions.toAndroidUri
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
@ -24,6 +27,8 @@ import kotlin.io.path.exists
*/ */
@UnstableApi @UnstableApi
class OfflinePlayerService : AbstractPlayerService() { class OfflinePlayerService : AbstractPlayerService() {
private var downloadWithItems: DownloadWithItems? = null
override suspend fun onServiceCreated(intent: Intent) { override suspend fun onServiceCreated(intent: Intent) {
videoId = intent.getStringExtra(IntentData.videoId) ?: return videoId = intent.getStringExtra(IntentData.videoId) ?: return
@ -43,6 +48,8 @@ class OfflinePlayerService : AbstractPlayerService() {
val downloadWithItems = withContext(Dispatchers.IO) { val downloadWithItems = withContext(Dispatchers.IO) {
Database.downloadDao().findById(videoId) Database.downloadDao().findById(videoId)
} }
this.downloadWithItems = downloadWithItems
onNewVideoStarted?.let { it(downloadWithItems.download.toStreamItem()) }
PlayingQueue.updateCurrent(downloadWithItems.download.toStreamItem()) PlayingQueue.updateCurrent(downloadWithItems.download.toStreamItem())
@ -96,11 +103,6 @@ class OfflinePlayerService : AbstractPlayerService() {
} }
} }
override fun onBind(intent: Intent): IBinder? {
super.onBind(intent)
return null
}
/** /**
* Stop the service when app is removed from the task manager. * Stop the service when app is removed from the task manager.
*/ */
@ -115,4 +117,7 @@ class OfflinePlayerService : AbstractPlayerService() {
playNextVideo(PlayingQueue.getNext() ?: return) playNextVideo(PlayingQueue.getNext() ?: return)
} }
} }
override fun getChapters(): List<ChapterSegment> =
downloadWithItems?.downloadChapters.orEmpty().map(DownloadChapter::toChapterSegment)
} }

View File

@ -1,8 +1,6 @@
package com.github.libretube.services package com.github.libretube.services
import android.content.Intent import android.content.Intent
import android.os.Binder
import android.os.IBinder
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
@ -11,6 +9,7 @@ import androidx.media3.common.Player
import com.github.libretube.api.JsonHelper import com.github.libretube.api.JsonHelper
import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.RetrofitInstance
import com.github.libretube.api.StreamsExtractor import com.github.libretube.api.StreamsExtractor
import com.github.libretube.api.obj.ChapterSegment
import com.github.libretube.api.obj.Segment import com.github.libretube.api.obj.Segment
import com.github.libretube.api.obj.Streams import com.github.libretube.api.obj.Streams
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
@ -54,17 +53,6 @@ class OnlinePlayerService : AbstractPlayerService() {
private var segments = listOf<Segment>() private var segments = listOf<Segment>()
private var sponsorBlockConfig = PlayerHelper.getSponsorBlockCategories() private var sponsorBlockConfig = PlayerHelper.getSponsorBlockCategories()
/**
* Used for connecting to the AudioPlayerFragment
*/
private val binder = LocalBinder()
/**
* Listener for passing playback state changes to the AudioPlayerFragment
*/
var onStateOrPlayingChanged: ((isPlaying: Boolean) -> Unit)? = null
var onNewVideo: ((streams: Streams, videoId: String) -> Unit)? = null
override suspend fun onServiceCreated(intent: Intent) { override suspend fun onServiceCreated(intent: Intent) {
val playerData = intent.parcelableExtra<PlayerData>(IntentData.playerData) val playerData = intent.parcelableExtra<PlayerData>(IntentData.playerData)
if (playerData == null) { if (playerData == null) {
@ -143,7 +131,7 @@ class OnlinePlayerService : AbstractPlayerService() {
streams?.thumbnailUrl streams?.thumbnailUrl
) )
nowPlayingNotification?.updatePlayerNotification(videoId, playerNotificationData) nowPlayingNotification?.updatePlayerNotification(videoId, playerNotificationData)
streams?.let { onNewVideo?.invoke(it, videoId) } streams?.let { onNewVideoStarted?.invoke(it.toStreamItem(videoId)) }
player?.apply { player?.apply {
playWhenReady = PlayerHelper.playAutomatically playWhenReady = PlayerHelper.playAutomatically
@ -225,19 +213,7 @@ class OnlinePlayerService : AbstractPlayerService() {
player?.checkForSegments(this, segments, sponsorBlockConfig) player?.checkForSegments(this, segments, sponsorBlockConfig)
} }
inner class LocalBinder : Binder() {
// Return this instance of [BackgroundMode] so clients can call public methods
fun getService(): OnlinePlayerService = this@OnlinePlayerService
}
override fun onBind(intent: Intent): IBinder {
super.onBind(intent)
return binder
}
override fun onPlaybackStateChanged(playbackState: Int) { override fun onPlaybackStateChanged(playbackState: Int) {
onStateOrPlayingChanged?.invoke(player?.isPlaying ?: false)
when (playbackState) { when (playbackState) {
Player.STATE_ENDED -> { Player.STATE_ENDED -> {
if (!isTransitioning) playNextVideo() if (!isTransitioning) playNextVideo()
@ -260,4 +236,6 @@ class OnlinePlayerService : AbstractPlayerService() {
} }
} }
} }
override fun getChapters(): List<ChapterSegment> = streams?.chapters.orEmpty()
} }

View File

@ -217,8 +217,7 @@ class OfflinePlayerActivity : BaseActivity() {
nowPlayingNotification = NowPlayingNotification( nowPlayingNotification = NowPlayingNotification(
this, this,
viewModel.player, viewModel.player
NowPlayingNotification.Companion.NowPlayingNotificationType.VIDEO_OFFLINE
) )
} }

View File

@ -3,10 +3,13 @@ package com.github.libretube.ui.adapters
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Handler
import android.os.Looper
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.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.os.postDelayed
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -18,6 +21,7 @@ import com.github.libretube.db.obj.DownloadWithItems
import com.github.libretube.extensions.formatAsFileSize import com.github.libretube.extensions.formatAsFileSize
import com.github.libretube.helpers.BackgroundHelper import com.github.libretube.helpers.BackgroundHelper
import com.github.libretube.helpers.ImageHelper import com.github.libretube.helpers.ImageHelper
import com.github.libretube.helpers.NavigationHelper
import com.github.libretube.ui.activities.OfflinePlayerActivity import com.github.libretube.ui.activities.OfflinePlayerActivity
import com.github.libretube.ui.base.BaseActivity import com.github.libretube.ui.base.BaseActivity
import com.github.libretube.ui.fragments.DownloadTab import com.github.libretube.ui.fragments.DownloadTab
@ -38,6 +42,8 @@ class DownloadsAdapter(
private val downloads: MutableList<DownloadWithItems>, private val downloads: MutableList<DownloadWithItems>,
private val toggleDownload: (DownloadWithItems) -> Boolean private val toggleDownload: (DownloadWithItems) -> Boolean
) : RecyclerView.Adapter<DownloadsViewHolder>() { ) : RecyclerView.Adapter<DownloadsViewHolder>() {
private val handler = Handler(Looper.getMainLooper())
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsViewHolder {
val binding = DownloadedMediaRowBinding.inflate( val binding = DownloadedMediaRowBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
@ -107,6 +113,7 @@ class DownloadsAdapter(
root.context.startActivity(intent) root.context.startActivity(intent)
} else { } else {
BackgroundHelper.playOnBackgroundOffline(root.context, download.videoId) BackgroundHelper.playOnBackgroundOffline(root.context, download.videoId)
NavigationHelper.startAudioPlayer(root.context, offlinePlayer = true)
} }
} }

View File

@ -2,7 +2,6 @@ package com.github.libretube.ui.fragments
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.ComponentName import android.content.ComponentName
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.graphics.Color import android.graphics.Color
@ -11,6 +10,7 @@ import android.os.Handler
import android.os.IBinder import android.os.IBinder
import android.os.Looper import android.os.Looper
import android.text.format.DateUtils import android.text.format.DateUtils
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -23,6 +23,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.fragment.app.commit import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.media3.common.util.UnstableApi
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.api.obj.StreamItem import com.github.libretube.api.obj.StreamItem
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
@ -40,6 +41,8 @@ import com.github.libretube.helpers.NavBarHelper
import com.github.libretube.helpers.NavigationHelper import com.github.libretube.helpers.NavigationHelper
import com.github.libretube.helpers.PlayerHelper import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.ThemeHelper import com.github.libretube.helpers.ThemeHelper
import com.github.libretube.services.AbstractPlayerService
import com.github.libretube.services.OfflinePlayerService
import com.github.libretube.services.OnlinePlayerService import com.github.libretube.services.OnlinePlayerService
import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.interfaces.AudioPlayerOptions import com.github.libretube.ui.interfaces.AudioPlayerOptions
@ -56,6 +59,7 @@ import com.github.libretube.util.PlayingQueue
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.math.abs import kotlin.math.abs
@UnstableApi
class AudioPlayerFragment : Fragment(), AudioPlayerOptions { class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
private var _binding: FragmentAudioPlayerBinding? = null private var _binding: FragmentAudioPlayerBinding? = null
val binding get() = _binding!! val binding get() = _binding!!
@ -72,13 +76,13 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
private var handler = Handler(Looper.getMainLooper()) private var handler = Handler(Looper.getMainLooper())
private var isPaused = !PlayerHelper.playAutomatically private var isPaused = !PlayerHelper.playAutomatically
private var playerService: OnlinePlayerService? = null private var playerService: AbstractPlayerService? = null
/** Defines callbacks for service binding, passed to bindService() */ /** Defines callbacks for service binding, passed to bindService() */
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
// We've bound to LocalService, cast the IBinder and get LocalService instance // We've bound to LocalService, cast the IBinder and get LocalService instance
val binder = service as OnlinePlayerService.LocalBinder val binder = service as AbstractPlayerService.LocalBinder
playerService = binder.getService() playerService = binder.getService()
handleServiceConnection() handleServiceConnection()
} }
@ -90,8 +94,14 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
audioHelper = AudioHelper(requireContext()) audioHelper = AudioHelper(requireContext())
Intent(activity, OnlinePlayerService::class.java).also { intent ->
activity?.bindService(intent, connection, Context.BIND_AUTO_CREATE) val isOffline = requireArguments().getBoolean(IntentData.offlinePlayer)
val serviceClass =
if (isOffline) OfflinePlayerService::class.java else OnlinePlayerService::class.java
Log.e("class", serviceClass.name.toString())
Intent(activity, serviceClass).also { intent ->
activity?.bindService(intent, connection, 0)
} }
} }
@ -188,7 +198,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
binding.openChapters.setOnClickListener { binding.openChapters.setOnClickListener {
val playerService = playerService ?: return@setOnClickListener val playerService = playerService ?: return@setOnClickListener
chaptersModel.chaptersLiveData.value = playerService.streams?.chapters.orEmpty() chaptersModel.chaptersLiveData.value = playerService.getChapters()
ChaptersBottomSheet() ChaptersBottomSheet()
.apply { .apply {
@ -380,11 +390,15 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
updatePlayPauseButton() updatePlayPauseButton()
isPaused = !isPlaying isPaused = !isPlaying
} }
playerService?.onNewVideo = { streams, videoId -> playerService?.onNewVideoStarted = { streamItem ->
updateStreamInfo(streams.toStreamItem(videoId)) updateStreamInfo(streamItem)
_binding?.openChapters?.isVisible = streams.chapters.isNotEmpty() _binding?.openChapters?.isVisible = !playerService?.getChapters().isNullOrEmpty()
} }
initializeSeekBar() initializeSeekBar()
if (playerService is OfflinePlayerService) {
binding.openVideo.isGone = true
}
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -462,7 +476,8 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
val player = playerService?.player ?: return val player = playerService?.player ?: return
val currentIndex = PlayerHelper.getCurrentChapterIndex(player.currentPosition, chaptersModel.chapters) val currentIndex =
PlayerHelper.getCurrentChapterIndex(player.currentPosition, chaptersModel.chapters)
chaptersModel.currentChapterIndex.updateIfChanged(currentIndex ?: return) chaptersModel.currentChapterIndex.updateIfChanged(currentIndex ?: return)
} }
} }

View File

@ -1358,8 +1358,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
if (viewModel.nowPlayingNotification == null) { if (viewModel.nowPlayingNotification == null) {
viewModel.nowPlayingNotification = NowPlayingNotification( viewModel.nowPlayingNotification = NowPlayingNotification(
requireContext(), requireContext(),
viewModel.player, viewModel.player
NowPlayingNotification.Companion.NowPlayingNotificationType.VIDEO_ONLINE
) )
} }
val playerNotificationData = PlayerNotificationData( val playerNotificationData = PlayerNotificationData(

View File

@ -58,7 +58,7 @@ class VideoOptionsBottomSheet : BaseBottomSheet() {
// Start the background mode // Start the background mode
R.string.playOnBackground -> { R.string.playOnBackground -> {
BackgroundHelper.playOnBackground(requireContext(), videoId) BackgroundHelper.playOnBackground(requireContext(), videoId)
NavigationHelper.startAudioPlayer(requireContext(), true) NavigationHelper.startAudioPlayer(requireContext(), minimizeByDefault = true)
} }
// Add Video to Playlist Dialog // Add Video to Playlist Dialog
R.string.addToPlaylist -> { R.string.addToPlaylist -> {

View File

@ -13,12 +13,10 @@ 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.media.app.NotificationCompat.MediaStyle import androidx.media.app.NotificationCompat.MediaStyle
import androidx.media3.common.MediaMetadata import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import coil.request.ImageRequest
import com.github.libretube.LibreTubeApp.Companion.PLAYER_CHANNEL_NAME import com.github.libretube.LibreTubeApp.Companion.PLAYER_CHANNEL_NAME
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
@ -35,8 +33,7 @@ import java.util.UUID
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @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
private val notificationType: NowPlayingNotificationType
) { ) {
private var videoId: String? = null private var videoId: String? = null
private val nManager = context.getSystemService<NotificationManager>()!! private val nManager = context.getSystemService<NotificationManager>()!!
@ -77,10 +74,8 @@ class NowPlayingNotification(
// is set to "singleTop" in the AndroidManifest (important!!!) // is set to "singleTop" in the AndroidManifest (important!!!)
// that's the only way to launch back into the previous activity (e.g. the player view // that's the only way to launch back into the previous activity (e.g. the player view
val intent = Intent(context, MainActivity::class.java).apply { val intent = Intent(context, MainActivity::class.java).apply {
if (notificationType == NowPlayingNotificationType.AUDIO_ONLINE) { putExtra(IntentData.openAudioPlayer, true)
putExtra(IntentData.openAudioPlayer, true) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
} }
return PendingIntentCompat return PendingIntentCompat
@ -355,13 +350,4 @@ class NowPlayingNotification(
fun refreshNotification() { fun refreshNotification() {
createOrUpdateNotification() createOrUpdateNotification()
} }
companion object {
enum class NowPlayingNotificationType {
VIDEO_ONLINE,
VIDEO_OFFLINE,
AUDIO_ONLINE,
AUDIO_OFFLINE
}
}
} }