Add the ability to import a YouTube playlist link as local playlist
This commit is contained in:
parent
c3b2435623
commit
0230624809
1 changed files with 105 additions and 9 deletions
|
@ -17,19 +17,30 @@ import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.media3.common.Player
|
||||||
import com.valentinilk.shimmer.ShimmerBounds
|
import com.valentinilk.shimmer.ShimmerBounds
|
||||||
import com.valentinilk.shimmer.rememberShimmer
|
import com.valentinilk.shimmer.rememberShimmer
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
|
import it.vfsfitvnm.vimusic.internal
|
||||||
|
import it.vfsfitvnm.vimusic.models.Playlist
|
||||||
|
import it.vfsfitvnm.vimusic.models.SongInPlaylist
|
||||||
import it.vfsfitvnm.vimusic.ui.components.Error
|
import it.vfsfitvnm.vimusic.ui.components.Error
|
||||||
|
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.Message
|
import it.vfsfitvnm.vimusic.ui.components.Message
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
|
import it.vfsfitvnm.vimusic.ui.components.themed.Menu
|
||||||
|
import it.vfsfitvnm.vimusic.ui.components.themed.MenuCloseButton
|
||||||
|
import it.vfsfitvnm.vimusic.ui.components.themed.MenuEntry
|
||||||
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
import it.vfsfitvnm.youtubemusic.Outcome
|
import it.vfsfitvnm.youtubemusic.Outcome
|
||||||
import it.vfsfitvnm.youtubemusic.YouTube
|
import it.vfsfitvnm.youtubemusic.YouTube
|
||||||
import it.vfsfitvnm.youtubemusic.toNullable
|
import it.vfsfitvnm.youtubemusic.toNullable
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
|
@ -54,10 +65,12 @@ fun IntentUriScreen(uri: Uri) {
|
||||||
}
|
}
|
||||||
|
|
||||||
host {
|
host {
|
||||||
|
val menuState = LocalMenuState.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val colorPalette = LocalColorPalette.current
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val player = LocalYoutubePlayer.current
|
val player = LocalYoutubePlayer.current
|
||||||
|
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val shimmer = rememberShimmer(shimmerBounds = ShimmerBounds.Window)
|
val shimmer = rememberShimmer(shimmerBounds = ShimmerBounds.Window)
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,6 +90,44 @@ fun IntentUriScreen(uri: Uri) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isImportingAsPlaylist by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isImportingAsPlaylist) {
|
||||||
|
TextFieldDialog(
|
||||||
|
hintText = "Enter the playlist name",
|
||||||
|
onDismiss = {
|
||||||
|
isImportingAsPlaylist = false
|
||||||
|
},
|
||||||
|
onDone = { text ->
|
||||||
|
menuState.hide()
|
||||||
|
|
||||||
|
coroutineScope.launch(Dispatchers.IO) {
|
||||||
|
Database.internal.runInTransaction {
|
||||||
|
val playlistId = Database.insert(Playlist(name = text))
|
||||||
|
|
||||||
|
items.valueOrNull
|
||||||
|
?.map(YouTube.Item.Song::asMediaItem)
|
||||||
|
?.forEachIndexed { index, mediaItem ->
|
||||||
|
if (Database.song(mediaItem.mediaId) == null) {
|
||||||
|
Database.insert(mediaItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
Database.insert(
|
||||||
|
SongInPlaylist(
|
||||||
|
songId = mediaItem.mediaId,
|
||||||
|
playlistId = playlistId,
|
||||||
|
position = index
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
@ -100,6 +151,47 @@ fun IntentUriScreen(uri: Uri) {
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.ellipsis_horizontal),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
menuState.display {
|
||||||
|
Menu {
|
||||||
|
MenuCloseButton(onClick = menuState::hide)
|
||||||
|
|
||||||
|
MenuEntry(
|
||||||
|
icon = R.drawable.time,
|
||||||
|
text = "Enqueue",
|
||||||
|
enabled = player?.playbackState == Player.STATE_READY,
|
||||||
|
onClick = {
|
||||||
|
menuState.hide()
|
||||||
|
|
||||||
|
items.valueOrNull
|
||||||
|
?.map(YouTube.Item.Song::asMediaItem)
|
||||||
|
?.let { mediaItems ->
|
||||||
|
player?.mediaController?.enqueue(
|
||||||
|
mediaItems
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
MenuEntry(
|
||||||
|
icon = R.drawable.list,
|
||||||
|
text = "Import as playlist",
|
||||||
|
onClick = {
|
||||||
|
isImportingAsPlaylist = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
.size(24.dp)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,16 +232,20 @@ fun IntentUriScreen(uri: Uri) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
itemsIndexed(currentItems.value) { index, item ->
|
itemsIndexed(currentItems.value) { index, item ->
|
||||||
SmallSongItem(
|
SmallSongItem(
|
||||||
song = item,
|
song = item,
|
||||||
thumbnailSizePx = density.run { 54.dp.roundToPx() },
|
thumbnailSizePx = density.run { 54.dp.roundToPx() },
|
||||||
onClick = {
|
onClick = {
|
||||||
YoutubePlayer.Radio.reset()
|
YoutubePlayer.Radio.reset()
|
||||||
|
|
||||||
player?.mediaController?.forcePlayAtIndex(currentItems.value.map(YouTube.Item.Song::asMediaItem), index)
|
player?.mediaController?.forcePlayAtIndex(
|
||||||
pop()
|
currentItems.value.map(
|
||||||
}
|
YouTube.Item.Song::asMediaItem
|
||||||
)
|
), index
|
||||||
|
)
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue