Tweak Lyrics code
This commit is contained in:
parent
0ac516b39b
commit
16b6e6505a
2 changed files with 203 additions and 215 deletions
|
@ -13,7 +13,6 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.gestures.detectTapGestures
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
@ -30,10 +29,10 @@ import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.saveable.autoSaver
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||||
|
@ -46,7 +45,6 @@ import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.MediaMetadata
|
import androidx.media3.common.MediaMetadata
|
||||||
import com.valentinilk.shimmer.shimmer
|
|
||||||
import it.vfsfitvnm.kugou.KuGou
|
import it.vfsfitvnm.kugou.KuGou
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
|
@ -55,6 +53,7 @@ import it.vfsfitvnm.vimusic.query
|
||||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.Menu
|
import it.vfsfitvnm.vimusic.ui.components.themed.Menu
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.MenuEntry
|
import it.vfsfitvnm.vimusic.ui.components.themed.MenuEntry
|
||||||
|
import it.vfsfitvnm.vimusic.ui.components.themed.ShimmerHost
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.DefaultDarkColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.DefaultDarkColorPalette
|
||||||
|
@ -66,7 +65,7 @@ import it.vfsfitvnm.vimusic.utils.center
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.vfsfitvnm.vimusic.utils.color
|
||||||
import it.vfsfitvnm.vimusic.utils.isShowingSynchronizedLyricsKey
|
import it.vfsfitvnm.vimusic.utils.isShowingSynchronizedLyricsKey
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.relaunchableEffect
|
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||||
import it.vfsfitvnm.vimusic.utils.verticalFadingEdge
|
import it.vfsfitvnm.vimusic.utils.verticalFadingEdge
|
||||||
import it.vfsfitvnm.youtubemusic.Innertube
|
import it.vfsfitvnm.youtubemusic.Innertube
|
||||||
|
@ -76,7 +75,6 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@ -103,59 +101,67 @@ fun Lyrics(
|
||||||
|
|
||||||
var isShowingSynchronizedLyrics by rememberPreference(isShowingSynchronizedLyricsKey, false)
|
var isShowingSynchronizedLyrics by rememberPreference(isShowingSynchronizedLyricsKey, false)
|
||||||
|
|
||||||
var state by remember(mediaId, isShowingSynchronizedLyrics) {
|
var isEditing by remember(mediaId, isShowingSynchronizedLyrics) {
|
||||||
mutableStateOf(LyricsState())
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val fetchLyrics = relaunchableEffect(mediaId, isShowingSynchronizedLyrics) {
|
val lyrics by produceSaveableState(
|
||||||
|
initialValue = ".",
|
||||||
|
stateSaver = autoSaver<String?>(),
|
||||||
|
mediaId, isShowingSynchronizedLyrics
|
||||||
|
) {
|
||||||
if (isShowingSynchronizedLyrics) {
|
if (isShowingSynchronizedLyrics) {
|
||||||
Database.synchronizedLyrics(mediaId)
|
Database.synchronizedLyrics(mediaId)
|
||||||
} else {
|
} else {
|
||||||
Database.lyrics(mediaId)
|
Database.lyrics(mediaId)
|
||||||
}.distinctUntilChanged().map flowMap@{ lyrics ->
|
}
|
||||||
if (lyrics != null) return@flowMap lyrics
|
.flowOn(Dispatchers.IO)
|
||||||
|
.distinctUntilChanged()
|
||||||
state = state.copy(isLoading = true)
|
.collect { value = it }
|
||||||
|
|
||||||
if (isShowingSynchronizedLyrics) {
|
|
||||||
val mediaMetadata = mediaMetadataProvider()
|
|
||||||
var duration = withContext(Dispatchers.Main) {
|
|
||||||
durationProvider()
|
|
||||||
}
|
|
||||||
|
|
||||||
while (duration == C.TIME_UNSET) {
|
|
||||||
delay(100)
|
|
||||||
duration = withContext(Dispatchers.Main) {
|
|
||||||
durationProvider()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KuGou.lyrics(
|
|
||||||
artist = mediaMetadata.artist?.toString() ?: "",
|
|
||||||
title = mediaMetadata.title?.toString() ?: "",
|
|
||||||
duration = duration / 1000
|
|
||||||
)?.map { it?.value }
|
|
||||||
} else {
|
|
||||||
Innertube.lyrics(NextBody(videoId = mediaId))
|
|
||||||
}?.map { newLyrics ->
|
|
||||||
onLyricsUpdate(isShowingSynchronizedLyrics, mediaId, newLyrics ?: "")
|
|
||||||
state = state.copy(isLoading = false)
|
|
||||||
return@flowMap newLyrics ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
state = state.copy(isLoading = false)
|
|
||||||
null
|
|
||||||
}.flowOn(Dispatchers.IO).collect { state = state.copy(lyrics = it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.isEditing) {
|
var isError by remember(lyrics) {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(lyrics == null) {
|
||||||
|
if (lyrics != null) return@LaunchedEffect
|
||||||
|
|
||||||
|
if (isShowingSynchronizedLyrics) {
|
||||||
|
val mediaMetadata = mediaMetadataProvider()
|
||||||
|
var duration = withContext(Dispatchers.Main) {
|
||||||
|
durationProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
while (duration == C.TIME_UNSET) {
|
||||||
|
delay(100)
|
||||||
|
duration = withContext(Dispatchers.Main) {
|
||||||
|
durationProvider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KuGou.lyrics(
|
||||||
|
artist = mediaMetadata.artist?.toString() ?: "",
|
||||||
|
title = mediaMetadata.title?.toString() ?: "",
|
||||||
|
duration = duration / 1000
|
||||||
|
)?.map { it?.value }
|
||||||
|
} else {
|
||||||
|
Innertube.lyrics(NextBody(videoId = mediaId))
|
||||||
|
}?.onSuccess { newLyrics ->
|
||||||
|
onLyricsUpdate(isShowingSynchronizedLyrics, mediaId, newLyrics ?: "")
|
||||||
|
}?.onFailure {
|
||||||
|
isError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEditing) {
|
||||||
TextFieldDialog(
|
TextFieldDialog(
|
||||||
hintText = "Enter the lyrics",
|
hintText = "Enter the lyrics",
|
||||||
initialTextInput = state.lyrics ?: "",
|
initialTextInput = lyrics ?: "",
|
||||||
singleLine = false,
|
singleLine = false,
|
||||||
maxLines = 10,
|
maxLines = 10,
|
||||||
isTextInputValid = { true },
|
isTextInputValid = { true },
|
||||||
onDismiss = { state = state.copy(isEditing = false) },
|
onDismiss = { isEditing = false },
|
||||||
onDone = {
|
onDone = {
|
||||||
query {
|
query {
|
||||||
if (isShowingSynchronizedLyrics) {
|
if (isShowingSynchronizedLyrics) {
|
||||||
|
@ -163,7 +169,6 @@ fun Lyrics(
|
||||||
} else {
|
} else {
|
||||||
Database.updateLyrics(mediaId, it)
|
Database.updateLyrics(mediaId, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -181,7 +186,7 @@ fun Lyrics(
|
||||||
.background(Color.Black.copy(0.8f))
|
.background(Color.Black.copy(0.8f))
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = !state.isLoading && state.lyrics == null,
|
visible = isError && lyrics == null,
|
||||||
enter = slideInVertically { -it },
|
enter = slideInVertically { -it },
|
||||||
exit = slideOutVertically { -it },
|
exit = slideOutVertically { -it },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -198,7 +203,7 @@ fun Lyrics(
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = state.lyrics?.let(String::isEmpty) ?: false,
|
visible = lyrics?.let(String::isEmpty) ?: false,
|
||||||
enter = slideInVertically { -it },
|
enter = slideInVertically { -it },
|
||||||
exit = slideOutVertically { -it },
|
exit = slideOutVertically { -it },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -214,177 +219,157 @@ fun Lyrics(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.isLoading) {
|
lyrics?.let { lyrics ->
|
||||||
Column(
|
if (lyrics.isNotEmpty() && lyrics != ".") {
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
if (isShowingSynchronizedLyrics) {
|
||||||
modifier = Modifier
|
val density = LocalDensity.current
|
||||||
.shimmer()
|
val player = LocalPlayerServiceBinder.current?.player
|
||||||
) {
|
?: return@AnimatedVisibility
|
||||||
repeat(4) { index ->
|
|
||||||
TextPlaceholder(
|
val synchronizedLyrics = remember(lyrics) {
|
||||||
color = colorPalette.onOverlayShimmer,
|
SynchronizedLyrics(KuGou.Lyrics(lyrics).sentences) {
|
||||||
|
player.currentPosition + 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val lazyListState = rememberLazyListState(
|
||||||
|
synchronizedLyrics.index,
|
||||||
|
with(density) { size.roundToPx() } / 6)
|
||||||
|
|
||||||
|
LaunchedEffect(synchronizedLyrics) {
|
||||||
|
val center = with(density) { size.roundToPx() } / 6
|
||||||
|
|
||||||
|
while (isActive) {
|
||||||
|
delay(50)
|
||||||
|
if (synchronizedLyrics.update()) {
|
||||||
|
lazyListState.animateScrollToItem(
|
||||||
|
synchronizedLyrics.index,
|
||||||
|
center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
state = lazyListState,
|
||||||
|
userScrollEnabled = false,
|
||||||
|
contentPadding = PaddingValues(vertical = size / 2),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.alpha(1f - index * 0.05f)
|
.verticalFadingEdge()
|
||||||
|
) {
|
||||||
|
itemsIndexed(items = synchronizedLyrics.sentences) { index, sentence ->
|
||||||
|
BasicText(
|
||||||
|
text = sentence.second,
|
||||||
|
style = typography.xs.center.medium.color(if (index == synchronizedLyrics.index) PureBlackColorPalette.text else PureBlackColorPalette.textDisabled),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 4.dp, horizontal = 32.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BasicText(
|
||||||
|
text = lyrics,
|
||||||
|
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
|
||||||
|
modifier = Modifier
|
||||||
|
.nestedScroll(remember { nestedScrollConnectionProvider() })
|
||||||
|
.verticalFadingEdge()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = size / 4, horizontal = 32.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
state.lyrics?.let { lyrics ->
|
|
||||||
if (lyrics.isNotEmpty() && lyrics != ".") {
|
|
||||||
if (isShowingSynchronizedLyrics) {
|
|
||||||
val density = LocalDensity.current
|
|
||||||
val player = LocalPlayerServiceBinder.current?.player
|
|
||||||
?: return@AnimatedVisibility
|
|
||||||
|
|
||||||
val synchronizedLyrics = remember(lyrics) {
|
if (lyrics == null && !isError) {
|
||||||
SynchronizedLyrics(KuGou.Lyrics(lyrics).sentences) {
|
ShimmerHost(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
player.currentPosition + 50
|
repeat(4) {
|
||||||
}
|
TextPlaceholder(color = colorPalette.onOverlayShimmer)
|
||||||
}
|
|
||||||
|
|
||||||
val lazyListState = rememberLazyListState(
|
|
||||||
synchronizedLyrics.index,
|
|
||||||
with(density) { size.roundToPx() } / 6)
|
|
||||||
|
|
||||||
LaunchedEffect(synchronizedLyrics) {
|
|
||||||
val center = with(density) { size.roundToPx() } / 6
|
|
||||||
|
|
||||||
while (isActive) {
|
|
||||||
delay(50)
|
|
||||||
if (synchronizedLyrics.update()) {
|
|
||||||
lazyListState.animateScrollToItem(
|
|
||||||
synchronizedLyrics.index,
|
|
||||||
center
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn(
|
|
||||||
state = lazyListState,
|
|
||||||
userScrollEnabled = false,
|
|
||||||
contentPadding = PaddingValues(vertical = size / 2),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier = Modifier
|
|
||||||
.verticalFadingEdge()
|
|
||||||
) {
|
|
||||||
itemsIndexed(items = synchronizedLyrics.sentences) { index, sentence ->
|
|
||||||
BasicText(
|
|
||||||
text = sentence.second,
|
|
||||||
style = typography.xs.center.medium.color(if (index == synchronizedLyrics.index) PureBlackColorPalette.text else PureBlackColorPalette.textDisabled),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(vertical = 4.dp, horizontal = 32.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BasicText(
|
|
||||||
text = lyrics,
|
|
||||||
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
|
|
||||||
modifier = Modifier
|
|
||||||
.nestedScroll(remember { nestedScrollConnectionProvider() })
|
|
||||||
.verticalFadingEdge()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = size / 4, horizontal = 32.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.ellipsis_horizontal),
|
painter = painterResource(R.drawable.ellipsis_horizontal),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(DefaultDarkColorPalette.text),
|
colorFilter = ColorFilter.tint(DefaultDarkColorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(all = 4.dp)
|
.padding(all = 4.dp)
|
||||||
.clickable {
|
.clickable {
|
||||||
menuState.display {
|
menuState.display {
|
||||||
Menu {
|
Menu {
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.time,
|
icon = R.drawable.time,
|
||||||
text = "Show ${if (isShowingSynchronizedLyrics) "un" else ""}synchronized lyrics",
|
text = "Show ${if (isShowingSynchronizedLyrics) "un" else ""}synchronized lyrics",
|
||||||
secondaryText = if (isShowingSynchronizedLyrics) null else "Provided by kugou.com",
|
secondaryText = if (isShowingSynchronizedLyrics) null else "Provided by kugou.com",
|
||||||
onClick = {
|
onClick = {
|
||||||
menuState.hide()
|
menuState.hide()
|
||||||
isShowingSynchronizedLyrics =
|
isShowingSynchronizedLyrics =
|
||||||
!isShowingSynchronizedLyrics
|
!isShowingSynchronizedLyrics
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
MenuEntry(
|
||||||
|
icon = R.drawable.pencil,
|
||||||
|
text = "Edit lyrics",
|
||||||
|
onClick = {
|
||||||
|
menuState.hide()
|
||||||
|
isEditing = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
MenuEntry(
|
||||||
|
icon = R.drawable.search,
|
||||||
|
text = "Search lyrics online",
|
||||||
|
onClick = {
|
||||||
|
menuState.hide()
|
||||||
|
val mediaMetadata = mediaMetadataProvider()
|
||||||
|
|
||||||
|
val intent =
|
||||||
|
Intent(Intent.ACTION_WEB_SEARCH).apply {
|
||||||
|
putExtra(
|
||||||
|
SearchManager.QUERY,
|
||||||
|
"${mediaMetadata.title} ${mediaMetadata.artist} lyrics"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intent.resolveActivity(context.packageManager) != null) {
|
||||||
|
context.startActivity(intent)
|
||||||
|
} else {
|
||||||
|
Toast
|
||||||
|
.makeText(
|
||||||
|
context,
|
||||||
|
"No browser app found!",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.pencil,
|
icon = R.drawable.download,
|
||||||
text = "Edit lyrics",
|
text = "Fetch lyrics again",
|
||||||
onClick = {
|
isEnabled = lyrics != null,
|
||||||
menuState.hide()
|
onClick = {
|
||||||
state = state.copy(isEditing = true)
|
menuState.hide()
|
||||||
}
|
query {
|
||||||
)
|
if (isShowingSynchronizedLyrics) {
|
||||||
|
Database.updateSynchronizedLyrics(mediaId, null)
|
||||||
MenuEntry(
|
|
||||||
icon = R.drawable.search,
|
|
||||||
text = "Search lyrics online",
|
|
||||||
onClick = {
|
|
||||||
menuState.hide()
|
|
||||||
val mediaMetadata = mediaMetadataProvider()
|
|
||||||
|
|
||||||
val intent =
|
|
||||||
Intent(Intent.ACTION_WEB_SEARCH).apply {
|
|
||||||
putExtra(
|
|
||||||
SearchManager.QUERY,
|
|
||||||
"${mediaMetadata.title} ${mediaMetadata.artist} lyrics"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intent.resolveActivity(context.packageManager) != null) {
|
|
||||||
context.startActivity(intent)
|
|
||||||
} else {
|
} else {
|
||||||
Toast
|
Database.updateLyrics(mediaId, null)
|
||||||
.makeText(
|
|
||||||
context,
|
|
||||||
"No browser app found!",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
)
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
)
|
||||||
MenuEntry(
|
|
||||||
icon = R.drawable.download,
|
|
||||||
text = "Fetch lyrics again",
|
|
||||||
onClick = {
|
|
||||||
menuState.hide()
|
|
||||||
if (state.lyrics == null) {
|
|
||||||
fetchLyrics()
|
|
||||||
} else {
|
|
||||||
query {
|
|
||||||
if (isShowingSynchronizedLyrics) {
|
|
||||||
Database.updateSynchronizedLyrics(
|
|
||||||
mediaId,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Database.updateLyrics(mediaId, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(all = 8.dp)
|
}
|
||||||
.size(20.dp)
|
.padding(all = 8.dp)
|
||||||
.align(Alignment.BottomEnd)
|
.size(20.dp)
|
||||||
)
|
.align(Alignment.BottomEnd)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class LyricsState(
|
|
||||||
val isLoading: Boolean = false,
|
|
||||||
val isEditing: Boolean = false,
|
|
||||||
val lyrics: String? = ".",
|
|
||||||
)
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
|
import it.vfsfitvnm.vimusic.query
|
||||||
import it.vfsfitvnm.vimusic.service.LoginRequiredException
|
import it.vfsfitvnm.vimusic.service.LoginRequiredException
|
||||||
import it.vfsfitvnm.vimusic.service.PlayableFormatNotFoundException
|
import it.vfsfitvnm.vimusic.service.PlayableFormatNotFoundException
|
||||||
import it.vfsfitvnm.vimusic.service.UnplayableException
|
import it.vfsfitvnm.vimusic.service.UnplayableException
|
||||||
|
@ -121,19 +122,21 @@ fun Thumbnail(
|
||||||
isDisplayed = isShowingLyrics && error == null,
|
isDisplayed = isShowingLyrics && error == null,
|
||||||
onDismiss = { onShowLyrics(false) },
|
onDismiss = { onShowLyrics(false) },
|
||||||
onLyricsUpdate = { areSynchronized, mediaId, lyrics ->
|
onLyricsUpdate = { areSynchronized, mediaId, lyrics ->
|
||||||
if (areSynchronized) {
|
query {
|
||||||
if (Database.updateSynchronizedLyrics(mediaId, lyrics) == 0) {
|
if (areSynchronized) {
|
||||||
if (mediaId == mediaItem.mediaId) {
|
if (Database.updateSynchronizedLyrics(mediaId, lyrics) == 0) {
|
||||||
Database.insert(mediaItem) { song ->
|
if (mediaId == mediaItem.mediaId) {
|
||||||
song.copy(synchronizedLyrics = lyrics)
|
Database.insert(mediaItem) { song ->
|
||||||
|
song.copy(synchronizedLyrics = lyrics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
if (Database.updateLyrics(mediaId, lyrics) == 0) {
|
||||||
if (Database.updateLyrics(mediaId, lyrics) == 0) {
|
if (mediaId == mediaItem.mediaId) {
|
||||||
if (mediaId == mediaItem.mediaId) {
|
Database.insert(mediaItem) { song ->
|
||||||
Database.insert(mediaItem) { song ->
|
song.copy(lyrics = lyrics)
|
||||||
song.copy(lyrics = lyrics)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue