Drop androidx.media3
This commit is contained in:
23
app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Context.kt
Normal file
23
app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Context.kt
Normal file
@@ -0,0 +1,23 @@
|
||||
package it.vfsfitvnm.vimusic.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
|
||||
inline fun <reified T> Context.intent(): Intent =
|
||||
Intent(this@Context, T::class.java)
|
||||
|
||||
inline fun <reified T: BroadcastReceiver> Context.broadCastPendingIntent(
|
||||
requestCode: Int = 0,
|
||||
flags: Int = if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 0,
|
||||
): PendingIntent =
|
||||
PendingIntent.getBroadcast(this, requestCode, intent<T>(), flags)
|
||||
|
||||
inline fun <reified T: Activity> Context.activityPendingIntent(
|
||||
requestCode: Int = 0,
|
||||
flags: Int = if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 0,
|
||||
): PendingIntent =
|
||||
PendingIntent.getActivity(this, requestCode, intent<T>(), flags)
|
||||
@@ -1,24 +0,0 @@
|
||||
package it.vfsfitvnm.vimusic.utils
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.media3.session.MediaController
|
||||
import androidx.media3.session.SessionCommand
|
||||
import androidx.media3.session.SessionResult
|
||||
import com.google.common.util.concurrent.MoreExecutors
|
||||
import kotlinx.coroutines.guava.await
|
||||
|
||||
|
||||
suspend fun MediaController.send(command: SessionCommand, args: Bundle = Bundle.EMPTY): SessionResult {
|
||||
return sendCustomCommand(command, args).await()
|
||||
}
|
||||
|
||||
fun MediaController.command(command: SessionCommand, args: Bundle = Bundle.EMPTY, listener: ((SessionResult) -> Unit)? = null) {
|
||||
val future = sendCustomCommand(command, args)
|
||||
listener?.let {
|
||||
future.addListener({ it(future.get()) }, MoreExecutors.directExecutor())
|
||||
}
|
||||
}
|
||||
|
||||
fun MediaController.syncCommand(command: SessionCommand, args: Bundle = Bundle.EMPTY): SessionResult {
|
||||
return sendCustomCommand(command, args).get()
|
||||
}
|
||||
@@ -6,10 +6,9 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.media3.common.*
|
||||
import androidx.media3.session.MediaController
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
open class PlayerState(val mediaController: MediaController) : Player.Listener {
|
||||
open class PlayerState(val mediaController: Player) : Player.Listener {
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
var currentPosition by mutableStateOf(mediaController.currentPosition)
|
||||
@@ -52,7 +51,6 @@ open class PlayerState(val mediaController: MediaController) : Player.Listener {
|
||||
init {
|
||||
handler.post(object : Runnable {
|
||||
override fun run() {
|
||||
duration = mediaController.duration
|
||||
currentPosition = mediaController.currentPosition
|
||||
handler.postDelayed(this, 500)
|
||||
}
|
||||
@@ -64,6 +62,7 @@ open class PlayerState(val mediaController: MediaController) : Player.Listener {
|
||||
}
|
||||
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
duration = mediaController.duration
|
||||
this.playbackState = playbackState
|
||||
}
|
||||
|
||||
|
||||
43
app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/TimerJob.kt
Normal file
43
app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/TimerJob.kt
Normal file
@@ -0,0 +1,43 @@
|
||||
package it.vfsfitvnm.vimusic.utils
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
interface TimerJob {
|
||||
val millisLeft: StateFlow<Long?>
|
||||
fun cancel()
|
||||
}
|
||||
|
||||
fun CoroutineScope.timer(delayMillis: Long, onCompletion: () -> Unit): TimerJob {
|
||||
val millisLeft = MutableStateFlow<Long?>(delayMillis)
|
||||
|
||||
val job = launch {
|
||||
while (isActive && millisLeft.value != null) {
|
||||
delay(1000)
|
||||
millisLeft.emit(millisLeft.value?.minus(1000)?.takeIf { it > 0 })
|
||||
}
|
||||
}
|
||||
|
||||
val disposableHandle = job.invokeOnCompletion {
|
||||
if (it == null) {
|
||||
onCompletion()
|
||||
}
|
||||
}
|
||||
|
||||
return object : TimerJob {
|
||||
override val millisLeft: StateFlow<Long?>
|
||||
get() = millisLeft.asStateFlow()
|
||||
|
||||
override fun cancel() {
|
||||
millisLeft.value = null
|
||||
disposableHandle.dispose()
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,13 @@ package it.vfsfitvnm.vimusic.utils
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.session.MediaController
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import androidx.media3.common.Player
|
||||
import it.vfsfitvnm.youtubemusic.Outcome
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.guava.await
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class YoutubePlayer(mediaController: MediaController) : PlayerState(mediaController) {
|
||||
class YoutubePlayer(mediaController: Player) : PlayerState(mediaController) {
|
||||
data class Radio(
|
||||
private val videoId: String? = null,
|
||||
private val playlistId: String? = null,
|
||||
@@ -45,22 +43,13 @@ class YoutubePlayer(mediaController: MediaController) : PlayerState(mediaControl
|
||||
}
|
||||
}
|
||||
|
||||
val LocalYoutubePlayer = compositionLocalOf<YoutubePlayer?> { null }
|
||||
|
||||
@Composable
|
||||
fun rememberYoutubePlayer(
|
||||
mediaControllerFuture: ListenableFuture<MediaController>
|
||||
player: Player?
|
||||
): YoutubePlayer? {
|
||||
val mediaController by produceState<MediaController?>(initialValue = null) {
|
||||
value = mediaControllerFuture.await()
|
||||
}
|
||||
|
||||
val playerState = remember(mediaController) {
|
||||
YoutubePlayer(mediaController ?: return@remember null).also {
|
||||
// TODO: should we remove the listener later on?
|
||||
mediaController?.addListener(it)
|
||||
return remember(player) {
|
||||
YoutubePlayer(player ?: return@remember null).also {
|
||||
player.addListener(it)
|
||||
}
|
||||
}
|
||||
|
||||
return playerState
|
||||
}
|
||||
|
||||
@@ -144,6 +144,8 @@ val SongWithInfo.asMediaItem: MediaItem
|
||||
.build()
|
||||
)
|
||||
.setMediaId(song.id)
|
||||
.setUri(song.id)
|
||||
.setCustomCacheKey(song.id)
|
||||
.build()
|
||||
|
||||
fun YouTube.PlaylistOrAlbum.Item.toMediaItem(
|
||||
@@ -172,6 +174,8 @@ fun YouTube.PlaylistOrAlbum.Item.toMediaItem(
|
||||
.build()
|
||||
)
|
||||
.setMediaId(info.endpoint?.videoId ?: return null)
|
||||
.setUri(info.endpoint?.videoId ?: return null)
|
||||
.setCustomCacheKey(info.endpoint?.videoId ?: return null)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user