Save lyrics to the database
This commit is contained in:
@@ -7,7 +7,6 @@ import androidx.media3.common.MediaItem
|
||||
import androidx.room.*
|
||||
import it.vfsfitvnm.vimusic.models.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
|
||||
@Dao
|
||||
@@ -125,15 +124,22 @@ interface Database {
|
||||
|
||||
@androidx.room.Database(
|
||||
entities = [
|
||||
Song::class, SongInPlaylist::class, Playlist::class, Info::class, SongWithAuthors::class, SearchQuery::class, QueuedMediaItem::class
|
||||
Song::class,
|
||||
SongInPlaylist::class,
|
||||
Playlist::class,
|
||||
Info::class,
|
||||
SongWithAuthors::class,
|
||||
SearchQuery::class,
|
||||
QueuedMediaItem::class
|
||||
],
|
||||
views = [
|
||||
SortedSongInPlaylist::class
|
||||
],
|
||||
version = 2,
|
||||
version = 3,
|
||||
exportSchema = true,
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 1, to = 2)
|
||||
AutoMigration(from = 1, to = 2),
|
||||
AutoMigration(from = 2, to = 3),
|
||||
]
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
@@ -162,7 +168,7 @@ object Converters {
|
||||
return value?.let { byteArray ->
|
||||
val parcel = Parcel.obtain()
|
||||
parcel.unmarshall(byteArray, 0, byteArray.size)
|
||||
parcel.setDataPosition(0);
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val pb = parcel.readBundle(MediaItem::class.java.classLoader)
|
||||
parcel.recycle()
|
||||
|
||||
@@ -10,8 +10,9 @@ data class Song(
|
||||
val albumInfoId: Long?,
|
||||
val durationText: String,
|
||||
val thumbnailUrl: String?,
|
||||
val lyrics: String? = null,
|
||||
val likedAt: Long? = null,
|
||||
val totalPlayTimeMs: Long = 0
|
||||
val totalPlayTimeMs: Long = 0,
|
||||
) {
|
||||
val formattedTotalPlayTime: String
|
||||
get() {
|
||||
|
||||
@@ -26,7 +26,9 @@ import it.vfsfitvnm.route.Route
|
||||
import it.vfsfitvnm.route.RouteHandler
|
||||
import it.vfsfitvnm.route.empty
|
||||
import it.vfsfitvnm.route.rememberRoute
|
||||
import it.vfsfitvnm.vimusic.Database
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.models.Song
|
||||
import it.vfsfitvnm.vimusic.ui.components.BottomSheet
|
||||
import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
|
||||
import it.vfsfitvnm.vimusic.ui.components.Message
|
||||
@@ -35,10 +37,7 @@ import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
||||
import it.vfsfitvnm.vimusic.ui.screens.rememberLyricsRoute
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
||||
import it.vfsfitvnm.vimusic.utils.LocalYoutubePlayer
|
||||
import it.vfsfitvnm.vimusic.utils.center
|
||||
import it.vfsfitvnm.vimusic.utils.color
|
||||
import it.vfsfitvnm.vimusic.utils.medium
|
||||
import it.vfsfitvnm.vimusic.utils.*
|
||||
import it.vfsfitvnm.youtubemusic.Outcome
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.isEvaluable
|
||||
@@ -51,6 +50,7 @@ import kotlinx.coroutines.withContext
|
||||
@Composable
|
||||
fun PlayerBottomSheet(
|
||||
layoutState: BottomSheetState,
|
||||
song: Song?,
|
||||
onGlobalRouteEmitted: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -69,10 +69,6 @@ fun PlayerBottomSheet(
|
||||
mutableStateOf<Outcome<YouTube.NextResult>>(Outcome.Initial)
|
||||
}
|
||||
|
||||
var lyricsOutcome by remember(player.mediaItem!!.mediaId) {
|
||||
mutableStateOf<Outcome<String?>>(Outcome.Initial)
|
||||
}
|
||||
|
||||
BottomSheet(
|
||||
state = layoutState,
|
||||
peekHeight = 128.dp,
|
||||
@@ -91,7 +87,10 @@ fun PlayerBottomSheet(
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.background(color = colorPalette.textDisabled, shape = RoundedCornerShape(16.dp))
|
||||
.background(
|
||||
color = colorPalette.textDisabled,
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.width(36.dp)
|
||||
.height(4.dp)
|
||||
.padding(top = 8.dp)
|
||||
@@ -175,13 +174,18 @@ fun PlayerBottomSheet(
|
||||
.background(colorPalette.elevatedBackground)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
var lyricsOutcome by remember(song) {
|
||||
mutableStateOf(song?.lyrics?.let { Outcome.Success(it) } ?: Outcome.Initial)
|
||||
}
|
||||
|
||||
lyricsRoute {
|
||||
OutcomeItem(
|
||||
outcome = lyricsOutcome,
|
||||
onInitialize = {
|
||||
lyricsOutcome = Outcome.Loading
|
||||
|
||||
println("onInitialize!!")
|
||||
coroutineScope.launch(Dispatchers.Main) {
|
||||
lyricsOutcome = Outcome.Loading
|
||||
|
||||
if (nextOutcome.isEvaluable) {
|
||||
nextOutcome = Outcome.Loading
|
||||
nextOutcome = withContext(Dispatchers.IO) {
|
||||
@@ -195,6 +199,13 @@ fun PlayerBottomSheet(
|
||||
|
||||
lyricsOutcome = nextOutcome.flatMap {
|
||||
it.lyrics?.text().toNotNull()
|
||||
}.map {
|
||||
it ?: ""
|
||||
}.map {
|
||||
withContext(Dispatchers.IO) {
|
||||
Database.update((song ?: Database.insert(player.mediaItem!!)).copy(lyrics = it))
|
||||
}
|
||||
it
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -205,7 +216,14 @@ fun PlayerBottomSheet(
|
||||
)
|
||||
}
|
||||
) { lyrics ->
|
||||
if (lyrics != null) {
|
||||
if (lyrics.isEmpty()) {
|
||||
Message(
|
||||
text = "Lyrics not available",
|
||||
icon = R.drawable.text,
|
||||
modifier = Modifier
|
||||
.padding(top = 64.dp)
|
||||
)
|
||||
} else {
|
||||
BasicText(
|
||||
text = lyrics,
|
||||
style = typography.xs.center,
|
||||
@@ -217,13 +235,6 @@ fun PlayerBottomSheet(
|
||||
.padding(vertical = 16.dp)
|
||||
.padding(horizontal = 48.dp)
|
||||
)
|
||||
} else {
|
||||
Message(
|
||||
text = "Lyrics not available",
|
||||
icon = R.drawable.text,
|
||||
modifier = Modifier
|
||||
.padding(top = 64.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,11 +68,6 @@ fun PlayerView(
|
||||
size to density.run { size.minus(64.dp).roundToPx() }
|
||||
}
|
||||
|
||||
val song by remember(player.mediaItem?.mediaId) {
|
||||
player.mediaItem?.mediaId?.let(Database::songFlow)?.distinctUntilChanged() ?: flowOf(null)
|
||||
}.collectAsState(initial = null, context = Dispatchers.IO)
|
||||
|
||||
|
||||
BottomSheet(
|
||||
state = layoutState,
|
||||
modifier = modifier,
|
||||
@@ -169,6 +164,10 @@ fun PlayerView(
|
||||
}
|
||||
}
|
||||
) {
|
||||
val song by remember(player.mediaItem?.mediaId) {
|
||||
player.mediaItem?.mediaId?.let(Database::songFlow)?.distinctUntilChanged() ?: flowOf(null)
|
||||
}.collectAsState(initial = null, context = Dispatchers.IO)
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
@@ -440,6 +439,7 @@ fun PlayerView(
|
||||
PlayerBottomSheet(
|
||||
layoutState = rememberBottomSheetState(64.dp, layoutState.upperBound - 128.dp),
|
||||
onGlobalRouteEmitted = layoutState.collapse,
|
||||
song = song,
|
||||
modifier = Modifier
|
||||
.padding(bottom = 128.dp)
|
||||
.align(Alignment.BottomCenter)
|
||||
|
||||
Reference in New Issue
Block a user