diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 81e445cd..f09a4686 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { minSdk = 24 targetSdk = 35 versionCode = 22 - versionName = "2.1-alpha17" + versionName = "2.1-alpha18" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/skyd/anivu/ui/mpv/controller/bar/BottomBar.kt b/app/src/main/java/com/skyd/anivu/ui/mpv/controller/bar/BottomBar.kt index ddf6b368..684490fe 100644 --- a/app/src/main/java/com/skyd/anivu/ui/mpv/controller/bar/BottomBar.kt +++ b/app/src/main/java/com/skyd/anivu/ui/mpv/controller/bar/BottomBar.kt @@ -52,6 +52,7 @@ import com.skyd.anivu.R import com.skyd.anivu.ui.mpv.controller.ControllerBarGray import com.skyd.anivu.ui.mpv.controller.state.PlayState import com.skyd.anivu.ui.mpv.controller.state.PlayStateCallback +import java.util.Locale import kotlin.math.abs @@ -175,7 +176,7 @@ fun BottomBar( .animateContentSize() // For vertical centering .wrapContentHeight(), - text = "${playStateValue.speed}x", + text = "${String.format(Locale.getDefault(), "%.2f", playStateValue.speed)}x", style = MaterialTheme.typography.labelLarge, fontSize = TextUnit(16f, TextUnitType.Sp), textAlign = TextAlign.Center, @@ -187,7 +188,7 @@ fun BottomBar( imageVector = Icons.Rounded.MusicNote, contentDescription = stringResource(R.string.player_audio_track), ) - // Audio track button + // Subtitle track button BarIconButton( onClick = bottomBarCallback.onSubtitleTrackClick, imageVector = Icons.Rounded.ClosedCaption, diff --git a/app/src/main/java/com/skyd/anivu/ui/mpv/controller/dialog/SpeedDialog.kt b/app/src/main/java/com/skyd/anivu/ui/mpv/controller/dialog/SpeedDialog.kt index b2f80607..2ee73fc0 100644 --- a/app/src/main/java/com/skyd/anivu/ui/mpv/controller/dialog/SpeedDialog.kt +++ b/app/src/main/java/com/skyd/anivu/ui/mpv/controller/dialog/SpeedDialog.kt @@ -2,26 +2,29 @@ package com.skyd.anivu.ui.mpv.controller.dialog import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.grid.GridCells -import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.Check +import androidx.compose.material.icons.rounded.RestartAlt import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Slider import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.skyd.anivu.R +import com.skyd.anivu.ui.component.AniVuIconButton import com.skyd.anivu.ui.mpv.controller.state.dialog.SpeedDialogCallback import com.skyd.anivu.ui.mpv.controller.state.dialog.SpeedDialogState +import java.util.Locale -val speeds = listOf( - 3f, 2f, 1.75f, 1.5f, 1.25f, 1f, 0.75f, 0.5f, 0.25f, -) - @Composable internal fun SpeedDialog( onDismissRequest: () -> Unit, @@ -30,32 +33,37 @@ internal fun SpeedDialog( ) { val state = speedDialogState() if (state.show) { + var value by rememberSaveable { mutableFloatStateOf(state.currentSpeed) } BasicPlayerDialog(onDismissRequest = onDismissRequest) { Column(modifier = Modifier.padding(PaddingValues(16.dp))) { - Text( - modifier = Modifier - .padding(horizontal = 16.dp) - .padding(bottom = 6.dp), - text = stringResource(id = R.string.player_speed), - style = MaterialTheme.typography.headlineSmall, - ) - LazyVerticalGrid( - columns = GridCells.Fixed(2), - ) { - items(speeds.size) { index -> - val speed = speeds[index] - TrackDialogListItem( - imageVector = if (state.currentSpeed == speed) - Icons.Rounded.Check else null, - iconContentDescription = stringResource(id = R.string.item_selected), - text = "${speed}x", - onClick = { - speedDialogCallback.onSpeedChanged(speed) - onDismissRequest() - } - ) - } + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(bottom = 6.dp), + text = stringResource(id = R.string.player_speed), + style = MaterialTheme.typography.headlineSmall, + ) + Text( + modifier = Modifier.weight(1f), + text = String.format(Locale.getDefault(), "%.2f", value), + ) + AniVuIconButton( + onClick = { + value = 1f + speedDialogCallback.onSpeedChanged(value) + }, + imageVector = Icons.Rounded.RestartAlt, + contentDescription = stringResource(id = R.string.reset), + ) } + Slider( + modifier = Modifier.padding(horizontal = 10.dp), + value = value, + onValueChange = { value = it }, + onValueChangeFinished = { speedDialogCallback.onSpeedChanged(value) }, + valueRange = 0.25f..3f, + ) } } } diff --git a/app/src/main/java/com/skyd/anivu/ui/screen/read/ReadScreen.kt b/app/src/main/java/com/skyd/anivu/ui/screen/read/ReadScreen.kt index 25ab7716..593a3732 100644 --- a/app/src/main/java/com/skyd/anivu/ui/screen/read/ReadScreen.kt +++ b/app/src/main/java/com/skyd/anivu/ui/screen/read/ReadScreen.kt @@ -1,5 +1,7 @@ package com.skyd.anivu.ui.screen.read +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -7,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -28,6 +31,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -162,53 +166,7 @@ fun ReadScreen(articleId: String, viewModel: ReadViewModel = hiltViewModel()) { ArticleState.Init, ArticleState.Loading -> Unit - is ArticleState.Success -> { - val article = articleState.article - SelectionContainer { - Column { - article.article.title?.let { title -> - Text( - text = title, - style = MaterialTheme.typography.titleLarge, - maxLines = 3, - overflow = TextOverflow.Ellipsis, - ) - } - val date = article.article.date - val author = article.article.author - if (date != null || !author.isNullOrBlank()) { - Row(modifier = Modifier.padding(vertical = 10.dp)) { - if (date != null) { - Text( - text = date.toDateTimeString(context = context), - style = MaterialTheme.typography.labelLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } - if (date != null && !author.isNullOrBlank()) { - Spacer(modifier = Modifier.width(12.dp)) - } - if (!author.isNullOrBlank()) { - Text( - text = author, - style = MaterialTheme.typography.labelLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } - } - } - } - } - HtmlText( - text = article.article.content.ifNullOfBlank { - article.article.description.orEmpty() - } - ) - } + is ArticleState.Success -> Content(articleState) } } @@ -229,4 +187,60 @@ fun ReadScreen(articleId: String, viewModel: ReadViewModel = hiltViewModel()) { ) } } +} + +@Composable +private fun Content(articleState: ArticleState.Success) { + val context = LocalContext.current + val article = articleState.article + + SelectionContainer { + Column { + var expandTitle by rememberSaveable { mutableStateOf(false) } + article.article.title?.let { title -> + Text( + modifier = Modifier + .clip(RoundedCornerShape(6.dp)) + .animateContentSize() + .clickable { expandTitle = !expandTitle }, + text = title, + style = MaterialTheme.typography.titleLarge, + maxLines = if (expandTitle) Int.MAX_VALUE else 3, + overflow = TextOverflow.Ellipsis, + ) + } + val date = article.article.date + val author = article.article.author + if (date != null || !author.isNullOrBlank()) { + Row(modifier = Modifier.padding(vertical = 10.dp)) { + if (date != null) { + Text( + text = date.toDateTimeString(context = context), + style = MaterialTheme.typography.labelLarge, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + if (date != null && !author.isNullOrBlank()) { + Spacer(modifier = Modifier.width(12.dp)) + } + if (!author.isNullOrBlank()) { + Text( + text = author, + style = MaterialTheme.typography.labelLarge, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } + } + } + } + HtmlText( + text = article.article.content.ifNullOfBlank { + article.article.description.orEmpty() + } + ) } \ No newline at end of file