new: add phonetic marker toggle to subtitles preferences
This commit is contained in:
@@ -72,6 +72,7 @@ fun PlayerScreen(
|
||||
onNextSentenceClicked = viewModel::goToNextSentence,
|
||||
onShowTranscriptionChange = viewModel::setShowTranscription,
|
||||
onShowTranslationChange = viewModel::setShowTranslation,
|
||||
onShowPhoneticMarkerChange = viewModel::setShowPhoneticMarkers,
|
||||
onTextSizeDecrease = viewModel::decreaseSubtitleTextSize,
|
||||
onTextSizeIncrease = viewModel::increaseSubtitleTextSize,
|
||||
onSpeedChange = viewModel::setPlaybackSpeed,
|
||||
@@ -91,6 +92,7 @@ fun PlayerScreen(
|
||||
onNextSentenceClicked: () -> Unit = {},
|
||||
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
||||
onShowTranslationChange: (Boolean) -> Unit = {},
|
||||
onShowPhoneticMarkerChange: (Boolean) -> Unit = {},
|
||||
onTextSizeDecrease: () -> Unit = {},
|
||||
onTextSizeIncrease: () -> Unit = {},
|
||||
onSpeedChange: (Float) -> Unit = {},
|
||||
@@ -190,6 +192,7 @@ fun PlayerScreen(
|
||||
subtitlePreferences = uiState.subtitlePreferences,
|
||||
onShowTranscriptionChange = onShowTranscriptionChange,
|
||||
onShowTranslationChange = onShowTranslationChange,
|
||||
onShowPhoneticMarkerChange = onShowPhoneticMarkerChange,
|
||||
onTextSizeDecrease = onTextSizeDecrease,
|
||||
onTextSizeIncrease = onTextSizeIncrease,
|
||||
onDismiss = { showPreferences = false },
|
||||
|
||||
@@ -177,6 +177,7 @@ private fun Subtitle(
|
||||
TranscriptionLine(
|
||||
text = line.phrase.transcription,
|
||||
contentColor = contentColor,
|
||||
showPhoneticMarkers = subtitlePreferences.showPhoneticMarkers,
|
||||
)
|
||||
}
|
||||
line.phrase.translation
|
||||
@@ -194,6 +195,7 @@ private fun Subtitle(
|
||||
private fun TranscriptionLine(
|
||||
text: String,
|
||||
contentColor: Color,
|
||||
showPhoneticMarkers: Boolean = true,
|
||||
) {
|
||||
TranscriptionText(
|
||||
text = text,
|
||||
@@ -203,6 +205,7 @@ private fun TranscriptionLine(
|
||||
lineHeight = 32.sp,
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
showPhoneticMarkers = showPhoneticMarkers,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+31
-4
@@ -38,7 +38,7 @@ import fr.ajaury.gwenedeg.theme.ChomBevTheme
|
||||
*
|
||||
* The captured group is the bare letter, without its surrounding delimiters.
|
||||
*/
|
||||
private val MARKED_LETTER_REGEX = Regex("""\(([A-Za-z])\)|\[([A-Za-z])\]""")
|
||||
private val MARKED_LETTER_REGEX = Regex("""\{([A-Za-z])\}|\[([A-Za-z])\]""")
|
||||
|
||||
/** Diacritic drawn above a parenthesised letter to mark that it is muted. */
|
||||
private const val MUTED_MARK = "ø"
|
||||
@@ -51,12 +51,15 @@ private const val WORD_JOINER = "\u2060"
|
||||
|
||||
/**
|
||||
* Renders a transcription, giving special treatment to single letters written between delimiters:
|
||||
* - `(x)` — a liaison consonant: the parentheses are dropped and the letter stays on the line, in
|
||||
* - `{x}` — a liaison consonant: the parentheses are dropped and the letter stays on the line, in
|
||||
* muted grey, topped with a small [MUTED_MARK].
|
||||
* - `[x]` — a linking consonant: the brackets are dropped and the letter is raised above the line,
|
||||
* in muted grey, with a small [LIAISON_MARK] underneath it.
|
||||
*
|
||||
* Marked letters are emitted as inline content so the line still wraps like normal text.
|
||||
*
|
||||
* When [showPhoneticMarkers] is `false` the pronunciation marks are dropped entirely: a muted
|
||||
* curved-bracketed letter reads as a normal letter, and a bracketed liaison letter becomes a space.
|
||||
*/
|
||||
@Composable
|
||||
fun TranscriptionText(
|
||||
@@ -65,12 +68,18 @@ fun TranscriptionText(
|
||||
style: TextStyle,
|
||||
modifier: Modifier = Modifier,
|
||||
textAlign: TextAlign = TextAlign.Center,
|
||||
showPhoneticMarkers: Boolean = true,
|
||||
) {
|
||||
val matches = remember(text) { MARKED_LETTER_REGEX.findAll(text).toList() }
|
||||
val matches = remember(text, showPhoneticMarkers) {
|
||||
if (showPhoneticMarkers) MARKED_LETTER_REGEX.findAll(text).toList() else emptyList()
|
||||
}
|
||||
|
||||
if (matches.isEmpty()) {
|
||||
val plainText = remember(text, showPhoneticMarkers) {
|
||||
if (showPhoneticMarkers) text else text.withoutMarkedLetters()
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
text = plainText,
|
||||
color = color,
|
||||
style = style,
|
||||
textAlign = textAlign,
|
||||
@@ -211,6 +220,24 @@ private val MatchResult.letter: String
|
||||
private val MatchResult.isBracketed: Boolean
|
||||
get() = groupValues[1].isEmpty()
|
||||
|
||||
/**
|
||||
* Strips pronunciation marks from a transcription: a muted parenthesised letter becomes a plain
|
||||
* letter, while a bracketed liaison letter is dropped and replaced by a space — except when it
|
||||
* directly follows an apostrophe (e.g. `d'[t]ober`), where it is removed without leaving a space.
|
||||
*/
|
||||
private fun String.withoutMarkedLetters(): String =
|
||||
replace(MARKED_LETTER_REGEX) { match ->
|
||||
val precedingChar = getOrNull(match.range.first - 1)
|
||||
when {
|
||||
!match.isBracketed -> match.letter
|
||||
precedingChar != null && precedingChar in APOSTROPHES -> ""
|
||||
else -> " "
|
||||
}
|
||||
}
|
||||
|
||||
/** Apostrophe characters after which a dropped liaison letter should not leave a space. */
|
||||
private val APOSTROPHES = setOf('\'', '’')
|
||||
|
||||
private fun inlineId(index: Int): String = "marked-letter-$index"
|
||||
|
||||
@Preview(backgroundColor = 0xFFFFFFFF)
|
||||
|
||||
+6
-1
@@ -17,7 +17,6 @@ import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.roundToInt
|
||||
@@ -147,6 +146,12 @@ class PlayerViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun setShowPhoneticMarkers(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
preferencesRepository.setShowPhoneticMarkers(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
fun increaseSubtitleTextSize() {
|
||||
val current = uiState.value.subtitlePreferences.textScale
|
||||
setSubtitleTextScale(SubtitlePreferences.nextTextScale(current))
|
||||
|
||||
+11
@@ -23,6 +23,8 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import fr.ajaury.gwenedeg.preferences.model.SubtitlePreferences
|
||||
import fr.ajaury.gwenedeg.resources.generated.resources.Res
|
||||
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_marked_letters_description
|
||||
import fr.ajaury.gwenedeg.resources.generated.resources.subtitle_marked_letters_label
|
||||
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
|
||||
@@ -45,6 +47,7 @@ fun SubtitlePreferencesBottomSheet(
|
||||
subtitlePreferences: SubtitlePreferences,
|
||||
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
||||
onShowTranslationChange: (Boolean) -> Unit = {},
|
||||
onShowPhoneticMarkerChange: (Boolean) -> Unit = {},
|
||||
onTextSizeDecrease: () -> Unit = {},
|
||||
onTextSizeIncrease: () -> Unit = {},
|
||||
onDismiss: () -> Unit = {},
|
||||
@@ -58,6 +61,7 @@ fun SubtitlePreferencesBottomSheet(
|
||||
subtitlePreferences = subtitlePreferences,
|
||||
onShowTranscriptionChange = onShowTranscriptionChange,
|
||||
onShowTranslationChange = onShowTranslationChange,
|
||||
onShowMarkedLettersChange = onShowPhoneticMarkerChange,
|
||||
onTextSizeDecrease = onTextSizeDecrease,
|
||||
onTextSizeIncrease = onTextSizeIncrease,
|
||||
)
|
||||
@@ -69,6 +73,7 @@ private fun SubtitlePreferencesContent(
|
||||
subtitlePreferences: SubtitlePreferences,
|
||||
onShowTranscriptionChange: (Boolean) -> Unit = {},
|
||||
onShowTranslationChange: (Boolean) -> Unit = {},
|
||||
onShowMarkedLettersChange: (Boolean) -> Unit = {},
|
||||
onTextSizeDecrease: () -> Unit = {},
|
||||
onTextSizeIncrease: () -> Unit = {},
|
||||
) {
|
||||
@@ -95,6 +100,12 @@ private fun SubtitlePreferencesContent(
|
||||
checked = subtitlePreferences.showTranslation,
|
||||
onCheckedChange = onShowTranslationChange,
|
||||
)
|
||||
PreferenceToggle(
|
||||
title = stringResource(Res.string.subtitle_marked_letters_label),
|
||||
subtitle = stringResource(Res.string.subtitle_marked_letters_description),
|
||||
checked = subtitlePreferences.showPhoneticMarkers,
|
||||
onCheckedChange = onShowMarkedLettersChange,
|
||||
)
|
||||
SubtitleTextSizeControl(
|
||||
textScale = subtitlePreferences.textScale,
|
||||
onDecrease = onTextSizeDecrease,
|
||||
|
||||
Reference in New Issue
Block a user