new: add adjustable subtitle text size in player and preferences UI
This commit is contained in:
+4
@@ -27,6 +27,10 @@ internal class InMemoryPreferencesRepository : PreferencesRepository {
|
|||||||
subtitleState.update { it.copy(showTranslation = enabled) }
|
subtitleState.update { it.copy(showTranslation = enabled) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun setSubtitleTextScale(scale: Float) {
|
||||||
|
subtitleState.update { it.copy(textScale = scale) }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun setPlaybackSpeed(speed: Float) {
|
override suspend fun setPlaybackSpeed(speed: Float) {
|
||||||
playbackState.update { it.copy(speed = speed) }
|
playbackState.update { it.copy(speed = speed) }
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -13,5 +13,7 @@ interface PreferencesRepository {
|
|||||||
|
|
||||||
suspend fun setShowTranslation(enabled: Boolean)
|
suspend fun setShowTranslation(enabled: Boolean)
|
||||||
|
|
||||||
|
suspend fun setSubtitleTextScale(scale: Float)
|
||||||
|
|
||||||
suspend fun setPlaybackSpeed(speed: Float)
|
suspend fun setPlaybackSpeed(speed: Float)
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-2
@@ -1,12 +1,30 @@
|
|||||||
package fr.ajaury.gwenedeg.preferences.model
|
package fr.ajaury.gwenedeg.preferences.model
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User preferences controlling which subtitle lines are displayed on the player.
|
* User preferences controlling the subtitle display on the player.
|
||||||
*
|
*
|
||||||
* @property showTranscription whether the Breton (BZH) transcription line is shown.
|
* @property showTranscription whether the Breton (BZH) transcription line is shown.
|
||||||
* @property showTranslation whether the French (FR) translation line is shown.
|
* @property showTranslation whether the French (FR) translation line is shown.
|
||||||
|
* @property textScale multiplier applied to the subtitle font size (see [TEXT_SCALE_STEPS]).
|
||||||
*/
|
*/
|
||||||
data class SubtitlePreferences(
|
data class SubtitlePreferences(
|
||||||
val showTranscription: Boolean = true,
|
val showTranscription: Boolean = true,
|
||||||
val showTranslation: Boolean = true,
|
val showTranslation: Boolean = true,
|
||||||
)
|
val textScale: Float = DEFAULT_TEXT_SCALE,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
const val DEFAULT_TEXT_SCALE = 1f
|
||||||
|
|
||||||
|
/** Allowed text-scale steps: 0.1 increments up to x1, then 0.2 increments up to x2. */
|
||||||
|
val TEXT_SCALE_STEPS: List<Float> =
|
||||||
|
listOf(0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.2f, 1.4f, 1.6f, 1.8f, 2.0f)
|
||||||
|
|
||||||
|
/** The next allowed step above [scale], or the maximum when already at the top. */
|
||||||
|
fun nextTextScale(scale: Float): Float =
|
||||||
|
TEXT_SCALE_STEPS.firstOrNull { it > scale } ?: TEXT_SCALE_STEPS.last()
|
||||||
|
|
||||||
|
/** The previous allowed step below [scale], or the minimum when already at the bottom. */
|
||||||
|
fun previousTextScale(scale: Float): Float =
|
||||||
|
TEXT_SCALE_STEPS.lastOrNull { it < scale } ?: TEXT_SCALE_STEPS.first()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+4
@@ -32,6 +32,8 @@ internal class DataStorePreferencesRepository(
|
|||||||
|
|
||||||
override suspend fun setShowTranslation(enabled: Boolean) = edit { it[ShowTranslationKey] = enabled }
|
override suspend fun setShowTranslation(enabled: Boolean) = edit { it[ShowTranslationKey] = enabled }
|
||||||
|
|
||||||
|
override suspend fun setSubtitleTextScale(scale: Float) = edit { it[SubtitleTextScaleKey] = scale }
|
||||||
|
|
||||||
override suspend fun setPlaybackSpeed(speed: Float) = edit { it[PlaybackSpeedKey] = speed }
|
override suspend fun setPlaybackSpeed(speed: Float) = edit { it[PlaybackSpeedKey] = speed }
|
||||||
|
|
||||||
private suspend fun edit(transform: (MutablePreferences) -> Unit) {
|
private suspend fun edit(transform: (MutablePreferences) -> Unit) {
|
||||||
@@ -43,6 +45,7 @@ internal class DataStorePreferencesRepository(
|
|||||||
return SubtitlePreferences(
|
return SubtitlePreferences(
|
||||||
showTranscription = this[ShowTranscriptionKey] ?: defaults.showTranscription,
|
showTranscription = this[ShowTranscriptionKey] ?: defaults.showTranscription,
|
||||||
showTranslation = this[ShowTranslationKey] ?: defaults.showTranslation,
|
showTranslation = this[ShowTranslationKey] ?: defaults.showTranslation,
|
||||||
|
textScale = this[SubtitleTextScaleKey] ?: defaults.textScale,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +57,7 @@ internal class DataStorePreferencesRepository(
|
|||||||
private companion object {
|
private companion object {
|
||||||
val ShowTranscriptionKey = booleanPreferencesKey("show_transcription")
|
val ShowTranscriptionKey = booleanPreferencesKey("show_transcription")
|
||||||
val ShowTranslationKey = booleanPreferencesKey("show_translation")
|
val ShowTranslationKey = booleanPreferencesKey("show_translation")
|
||||||
|
val SubtitleTextScaleKey = floatPreferencesKey("subtitle_text_scale")
|
||||||
val PlaybackSpeedKey = floatPreferencesKey("playback_speed")
|
val PlaybackSpeedKey = floatPreferencesKey("playback_speed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
<string name="subtitle_transcription_description">Diskouez an treuzskrivadur brezhonek</string>
|
<string name="subtitle_transcription_description">Diskouez an treuzskrivadur brezhonek</string>
|
||||||
<string name="subtitle_translation_label">Troidigezh (FR)</string>
|
<string name="subtitle_translation_label">Troidigezh (FR)</string>
|
||||||
<string name="subtitle_translation_description">Diskouez an droidigezh c\'hallek</string>
|
<string name="subtitle_translation_description">Diskouez an droidigezh c\'hallek</string>
|
||||||
|
<string name="subtitle_text_size_label">Ment an destenn</string>
|
||||||
|
<string name="subtitle_text_size_decrease">Bihanaat ment an destenn</string>
|
||||||
|
<string name="subtitle_text_size_increase">Brasaat ment an destenn</string>
|
||||||
|
|
||||||
<string name="playback_speed_title">Tizh al lenn</string>
|
<string name="playback_speed_title">Tizh al lenn</string>
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
<string name="subtitle_transcription_description">Afficher la transcription bretonne</string>
|
<string name="subtitle_transcription_description">Afficher la transcription bretonne</string>
|
||||||
<string name="subtitle_translation_label">Traduction (FR)</string>
|
<string name="subtitle_translation_label">Traduction (FR)</string>
|
||||||
<string name="subtitle_translation_description">Afficher la traduction française</string>
|
<string name="subtitle_translation_description">Afficher la traduction française</string>
|
||||||
|
<string name="subtitle_text_size_label">Taille du texte</string>
|
||||||
|
<string name="subtitle_text_size_decrease">Réduire la taille du texte</string>
|
||||||
|
<string name="subtitle_text_size_increase">Augmenter la taille du texte</string>
|
||||||
|
|
||||||
<string name="playback_speed_title">Vitesse de lecture</string>
|
<string name="playback_speed_title">Vitesse de lecture</string>
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ fun PlayerScreen(
|
|||||||
onNextSentenceClicked = viewModel::goToNextSentence,
|
onNextSentenceClicked = viewModel::goToNextSentence,
|
||||||
onShowTranscriptionChange = viewModel::setShowTranscription,
|
onShowTranscriptionChange = viewModel::setShowTranscription,
|
||||||
onShowTranslationChange = viewModel::setShowTranslation,
|
onShowTranslationChange = viewModel::setShowTranslation,
|
||||||
|
onTextSizeDecrease = viewModel::decreaseSubtitleTextSize,
|
||||||
|
onTextSizeIncrease = viewModel::increaseSubtitleTextSize,
|
||||||
onSpeedChange = viewModel::setPlaybackSpeed,
|
onSpeedChange = viewModel::setPlaybackSpeed,
|
||||||
onBackClicked = onBackClicked,
|
onBackClicked = onBackClicked,
|
||||||
)
|
)
|
||||||
@@ -88,6 +90,8 @@ fun PlayerScreen(
|
|||||||
onNextSentenceClicked: () -> Unit = {},
|
onNextSentenceClicked: () -> Unit = {},
|
||||||
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
||||||
onShowTranslationChange: (Boolean) -> Unit = {},
|
onShowTranslationChange: (Boolean) -> Unit = {},
|
||||||
|
onTextSizeDecrease: () -> Unit = {},
|
||||||
|
onTextSizeIncrease: () -> Unit = {},
|
||||||
onSpeedChange: (Float) -> Unit = {},
|
onSpeedChange: (Float) -> Unit = {},
|
||||||
onBackClicked: () -> Unit = {},
|
onBackClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
@@ -184,6 +188,8 @@ fun PlayerScreen(
|
|||||||
subtitlePreferences = uiState.subtitlePreferences,
|
subtitlePreferences = uiState.subtitlePreferences,
|
||||||
onShowTranscriptionChange = onShowTranscriptionChange,
|
onShowTranscriptionChange = onShowTranscriptionChange,
|
||||||
onShowTranslationChange = onShowTranslationChange,
|
onShowTranslationChange = onShowTranslationChange,
|
||||||
|
onTextSizeDecrease = onTextSizeDecrease,
|
||||||
|
onTextSizeIncrease = onTextSizeIncrease,
|
||||||
onDismiss = { showPreferences = false },
|
onDismiss = { showPreferences = false },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -27,9 +28,11 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.Density
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import fr.ajaury.gwenedeg.core.model.Phrase
|
import fr.ajaury.gwenedeg.core.model.Phrase
|
||||||
@@ -90,14 +93,24 @@ fun SubtitleList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val density = LocalDensity.current
|
||||||
BoxWithConstraints(modifier = modifier) {
|
BoxWithConstraints(modifier = modifier) {
|
||||||
|
// Half-height padding so the first and last lines can reach the vertical center. Captured here
|
||||||
|
// because `maxHeight` (BoxWithConstraintsScope) is not in scope inside the provider lambda.
|
||||||
|
val verticalPadding = maxHeight / 2
|
||||||
|
// Scale only the subtitle fonts by overriding the density's fontScale (dp layout is untouched).
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalDensity provides Density(
|
||||||
|
density = density.density,
|
||||||
|
fontScale = density.fontScale * subtitlePreferences.textScale,
|
||||||
|
),
|
||||||
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
// Half-height padding so the first and last lines can reach the vertical center.
|
contentPadding = PaddingValues(vertical = verticalPadding),
|
||||||
contentPadding = PaddingValues(vertical = maxHeight / 2),
|
|
||||||
) {
|
) {
|
||||||
itemsIndexed(lines) { index, line ->
|
itemsIndexed(lines) { index, line ->
|
||||||
val isCurrent = index == centeredIndex
|
val isCurrent = index == centeredIndex
|
||||||
@@ -110,6 +123,7 @@ fun SubtitleList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun LazyListState.getCenteredIndex(): Int {
|
private fun LazyListState.getCenteredIndex(): Int {
|
||||||
|
|||||||
+17
@@ -9,6 +9,7 @@ import fr.ajaury.gwenedeg.player.domain.PlaybackRepository
|
|||||||
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
||||||
import fr.ajaury.gwenedeg.preferences.domain.PreferencesRepository
|
import fr.ajaury.gwenedeg.preferences.domain.PreferencesRepository
|
||||||
import fr.ajaury.gwenedeg.preferences.model.PlaybackPreferences
|
import fr.ajaury.gwenedeg.preferences.model.PlaybackPreferences
|
||||||
|
import fr.ajaury.gwenedeg.preferences.model.SubtitlePreferences
|
||||||
import fr.ajaury.gwenedeg.records.domain.RecordRepository
|
import fr.ajaury.gwenedeg.records.domain.RecordRepository
|
||||||
import fr.ajaury.gwenedeg.records.model.Record
|
import fr.ajaury.gwenedeg.records.model.Record
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -125,6 +126,22 @@ class PlayerViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun increaseSubtitleTextSize() {
|
||||||
|
val current = uiState.value.subtitlePreferences.textScale
|
||||||
|
setSubtitleTextScale(SubtitlePreferences.nextTextScale(current))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decreaseSubtitleTextSize() {
|
||||||
|
val current = uiState.value.subtitlePreferences.textScale
|
||||||
|
setSubtitleTextScale(SubtitlePreferences.previousTextScale(current))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSubtitleTextScale(scale: Float) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
preferencesRepository.setSubtitleTextScale(scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
playbackRepository.stop()
|
playbackRepository.stop()
|
||||||
}
|
}
|
||||||
|
|||||||
+71
@@ -2,27 +2,38 @@ package fr.ajaury.gwenedeg.preferences.ui
|
|||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.Remove
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
import androidx.compose.material3.SheetState
|
import androidx.compose.material3.SheetState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import fr.ajaury.gwenedeg.preferences.model.SubtitlePreferences
|
import fr.ajaury.gwenedeg.preferences.model.SubtitlePreferences
|
||||||
import fr.ajaury.gwenedeg.resources.generated.resources.Res
|
import fr.ajaury.gwenedeg.resources.generated.resources.Res
|
||||||
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_preferences_title
|
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_preferences_title
|
||||||
|
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_text_size_decrease
|
||||||
|
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_text_size_increase
|
||||||
|
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_text_size_label
|
||||||
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_transcription_description
|
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_transcription_description
|
||||||
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_transcription_label
|
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_transcription_label
|
||||||
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_translation_description
|
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_translation_description
|
||||||
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_translation_label
|
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_translation_label
|
||||||
import fr.ajaury.gwenedeg.theme.ChomBevTheme
|
import fr.ajaury.gwenedeg.theme.ChomBevTheme
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bottom sheet letting the user toggle the display of the Breton transcription (BZH) and the
|
* Bottom sheet letting the user toggle the display of the Breton transcription (BZH) and the
|
||||||
@@ -34,6 +45,8 @@ fun SubtitlePreferencesBottomSheet(
|
|||||||
subtitlePreferences: SubtitlePreferences,
|
subtitlePreferences: SubtitlePreferences,
|
||||||
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
||||||
onShowTranslationChange: (Boolean) -> Unit = {},
|
onShowTranslationChange: (Boolean) -> Unit = {},
|
||||||
|
onTextSizeDecrease: () -> Unit = {},
|
||||||
|
onTextSizeIncrease: () -> Unit = {},
|
||||||
onDismiss: () -> Unit = {},
|
onDismiss: () -> Unit = {},
|
||||||
sheetState: SheetState = rememberModalBottomSheetState(),
|
sheetState: SheetState = rememberModalBottomSheetState(),
|
||||||
) {
|
) {
|
||||||
@@ -45,6 +58,8 @@ fun SubtitlePreferencesBottomSheet(
|
|||||||
subtitlePreferences = subtitlePreferences,
|
subtitlePreferences = subtitlePreferences,
|
||||||
onShowTranscriptionChange = onShowTranscriptionChange,
|
onShowTranscriptionChange = onShowTranscriptionChange,
|
||||||
onShowTranslationChange = onShowTranslationChange,
|
onShowTranslationChange = onShowTranslationChange,
|
||||||
|
onTextSizeDecrease = onTextSizeDecrease,
|
||||||
|
onTextSizeIncrease = onTextSizeIncrease,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,6 +69,8 @@ private fun SubtitlePreferencesContent(
|
|||||||
subtitlePreferences: SubtitlePreferences,
|
subtitlePreferences: SubtitlePreferences,
|
||||||
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
||||||
onShowTranslationChange: (Boolean) -> Unit = {},
|
onShowTranslationChange: (Boolean) -> Unit = {},
|
||||||
|
onTextSizeDecrease: () -> Unit = {},
|
||||||
|
onTextSizeIncrease: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -78,9 +95,63 @@ private fun SubtitlePreferencesContent(
|
|||||||
checked = subtitlePreferences.showTranslation,
|
checked = subtitlePreferences.showTranslation,
|
||||||
onCheckedChange = onShowTranslationChange,
|
onCheckedChange = onShowTranslationChange,
|
||||||
)
|
)
|
||||||
|
SubtitleTextSizeControl(
|
||||||
|
textScale = subtitlePreferences.textScale,
|
||||||
|
onDecrease = onTextSizeDecrease,
|
||||||
|
onIncrease = onTextSizeIncrease,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SubtitleTextSizeControl(
|
||||||
|
textScale: Float,
|
||||||
|
onDecrease: () -> Unit = {},
|
||||||
|
onIncrease: () -> Unit = {},
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 8.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(Res.string.subtitle_text_size_label),
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
)
|
||||||
|
IconButton(
|
||||||
|
onClick = onDecrease,
|
||||||
|
enabled = textScale > SubtitlePreferences.TEXT_SCALE_STEPS.first(),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Remove,
|
||||||
|
contentDescription = stringResource(Res.string.subtitle_text_size_decrease),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = formatTextScale(textScale),
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
IconButton(
|
||||||
|
onClick = onIncrease,
|
||||||
|
enabled = textScale < SubtitlePreferences.TEXT_SCALE_STEPS.last(),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Add,
|
||||||
|
contentDescription = stringResource(Res.string.subtitle_text_size_increase),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Formats a text-scale multiplier as a short label, e.g. 1.0 -> "x1", 1.2 -> "x1.2". */
|
||||||
|
private fun formatTextScale(scale: Float): String {
|
||||||
|
val tenths = (scale * 10).roundToInt()
|
||||||
|
return if (tenths % 10 == 0) "x${tenths / 10}" else "x${tenths / 10}.${tenths % 10}"
|
||||||
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun SubtitlePreferencesContentPreview() {
|
private fun SubtitlePreferencesContentPreview() {
|
||||||
|
|||||||
Reference in New Issue
Block a user