Dispose PlayerState
This commit is contained in:
@@ -77,7 +77,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
|
|||||||
private var lastArtworkUri: Uri? = null
|
private var lastArtworkUri: Uri? = null
|
||||||
private var lastBitmap: Bitmap? = null
|
private var lastBitmap: Bitmap? = null
|
||||||
|
|
||||||
private var radio: YoutubePlayer.Radio? = null
|
private var radio: YouTubeRadio? = null
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(Dispatchers.IO) + Job()
|
private val coroutineScope = CoroutineScope(Dispatchers.IO) + Job()
|
||||||
|
|
||||||
@@ -549,7 +549,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
|
|||||||
private fun startRadio(endpoint: NavigationEndpoint.Endpoint.Watch?, justAdd: Boolean) {
|
private fun startRadio(endpoint: NavigationEndpoint.Endpoint.Watch?, justAdd: Boolean) {
|
||||||
radioJob?.cancel()
|
radioJob?.cancel()
|
||||||
radio = null
|
radio = null
|
||||||
YoutubePlayer.Radio(
|
YouTubeRadio(
|
||||||
endpoint?.videoId,
|
endpoint?.videoId,
|
||||||
endpoint?.playlistId,
|
endpoint?.playlistId,
|
||||||
endpoint?.playlistSetVideoId,
|
endpoint?.playlistSetVideoId,
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ fun PlayerView(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val player = binder?.player
|
val player = binder?.player
|
||||||
val playerState = rememberYoutubePlayer(player)
|
val playerState = rememberPlayerState(player)
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import androidx.media3.common.*
|
|||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
open class PlayerState(private val player: Player) : Player.Listener {
|
class PlayerState(private val player: Player) : Player.Listener, Runnable {
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
var currentPosition by mutableStateOf(player.currentPosition)
|
var currentPosition by mutableStateOf(player.currentPosition)
|
||||||
@@ -30,9 +30,6 @@ open class PlayerState(private val player: Player) : Player.Listener {
|
|||||||
var mediaMetadata by mutableStateOf(player.mediaMetadata)
|
var mediaMetadata by mutableStateOf(player.mediaMetadata)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var isPlaying by mutableStateOf(player.isPlaying)
|
|
||||||
private set
|
|
||||||
|
|
||||||
var playWhenReady by mutableStateOf(player.playWhenReady)
|
var playWhenReady by mutableStateOf(player.playWhenReady)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -47,16 +44,6 @@ open class PlayerState(private val player: Player) : Player.Listener {
|
|||||||
var volume by mutableStateOf(player.volume)
|
var volume by mutableStateOf(player.volume)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
|
||||||
handler.post(object : Runnable {
|
|
||||||
override fun run() {
|
|
||||||
duration = player.duration
|
|
||||||
currentPosition = player.currentPosition
|
|
||||||
handler.postDelayed(this, 500)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onVolumeChanged(volume: Float) {
|
override fun onVolumeChanged(volume: Float) {
|
||||||
this.volume = volume
|
this.volume = volume
|
||||||
}
|
}
|
||||||
@@ -69,10 +56,6 @@ open class PlayerState(private val player: Player) : Player.Listener {
|
|||||||
this.mediaMetadata = mediaMetadata
|
this.mediaMetadata = mediaMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
|
||||||
this.isPlaying = isPlaying
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
|
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
|
||||||
this.playWhenReady = playWhenReady
|
this.playWhenReady = playWhenReady
|
||||||
}
|
}
|
||||||
@@ -94,4 +77,38 @@ open class PlayerState(private val player: Player) : Player.Listener {
|
|||||||
mediaItems = timeline.mediaItems
|
mediaItems = timeline.mediaItems
|
||||||
mediaItemIndex = player.currentMediaItemIndex
|
mediaItemIndex = player.currentMediaItemIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
duration = player.duration
|
||||||
|
currentPosition = player.currentPosition
|
||||||
|
handler.postDelayed(this, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun init() {
|
||||||
|
player.addListener(this)
|
||||||
|
handler.post(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dispose() {
|
||||||
|
player.removeListener(this)
|
||||||
|
handler.removeCallbacks(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberPlayerState(
|
||||||
|
player: Player?
|
||||||
|
): PlayerState? {
|
||||||
|
val playerState = remember(player) {
|
||||||
|
player?.let(::PlayerState)
|
||||||
|
}
|
||||||
|
|
||||||
|
playerState?.let {
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
playerState.init()
|
||||||
|
onDispose(playerState::dispose)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerState
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,54 +2,40 @@ package it.vfsfitvnm.vimusic.utils
|
|||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.common.Player
|
|
||||||
import it.vfsfitvnm.youtubemusic.Outcome
|
import it.vfsfitvnm.youtubemusic.Outcome
|
||||||
import it.vfsfitvnm.youtubemusic.YouTube
|
import it.vfsfitvnm.youtubemusic.YouTube
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class YoutubePlayer(player: Player) : PlayerState(player) {
|
data class YouTubeRadio(
|
||||||
data class Radio(
|
private val videoId: String? = null,
|
||||||
private val videoId: String? = null,
|
private val playlistId: String? = null,
|
||||||
private val playlistId: String? = null,
|
private val playlistSetVideoId: String? = null,
|
||||||
private val playlistSetVideoId: String? = null,
|
private val parameters: String? = null
|
||||||
private val parameters: String? = null
|
) {
|
||||||
) {
|
var nextContinuation by mutableStateOf<Outcome<String?>>(Outcome.Initial)
|
||||||
var nextContinuation by mutableStateOf<Outcome<String?>>(Outcome.Initial)
|
|
||||||
|
|
||||||
suspend fun process(): List<MediaItem> {
|
suspend fun process(): List<MediaItem> {
|
||||||
val token = nextContinuation.valueOrNull
|
val token = nextContinuation.valueOrNull
|
||||||
|
|
||||||
nextContinuation = Outcome.Loading
|
nextContinuation = Outcome.Loading
|
||||||
|
|
||||||
var mediaItems: List<MediaItem>? = null
|
var mediaItems: List<MediaItem>? = null
|
||||||
|
|
||||||
nextContinuation = withContext(Dispatchers.IO) {
|
nextContinuation = withContext(Dispatchers.IO) {
|
||||||
YouTube.next(
|
YouTube.next(
|
||||||
videoId = videoId ?: error("This should not happen"),
|
videoId = videoId ?: error("This should not happen"),
|
||||||
playlistId = playlistId,
|
playlistId = playlistId,
|
||||||
params = parameters,
|
params = parameters,
|
||||||
playlistSetVideoId = playlistSetVideoId,
|
playlistSetVideoId = playlistSetVideoId,
|
||||||
continuation = token
|
continuation = token
|
||||||
)
|
)
|
||||||
}.map { nextResult ->
|
}.map { nextResult ->
|
||||||
mediaItems = nextResult.items?.map(YouTube.Item.Song::asMediaItem)
|
mediaItems = nextResult.items?.map(YouTube.Item.Song::asMediaItem)
|
||||||
|
|
||||||
nextResult.continuation?.takeUnless { token == nextResult.continuation }
|
nextResult.continuation?.takeUnless { token == nextResult.continuation }
|
||||||
}.recoverWith(token)
|
}.recoverWith(token)
|
||||||
|
|
||||||
return mediaItems ?: emptyList()
|
return mediaItems ?: emptyList()
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun rememberYoutubePlayer(
|
|
||||||
player: Player?
|
|
||||||
): YoutubePlayer? {
|
|
||||||
return remember(player) {
|
|
||||||
YoutubePlayer(player ?: return@remember null).also {
|
|
||||||
player.addListener(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user