Further splitting the translation class into more methods to simplify recompositions

This commit is contained in:
Vitor Pamplona
2023-06-06 16:47:14 -04:00
parent c10db10430
commit b9654d164f
3 changed files with 242 additions and 180 deletions
@@ -49,33 +49,32 @@ fun TranslatableRichTextViewer(
accountViewModel: AccountViewModel,
nav: (String) -> Unit
) {
var translatedTextState by remember {
mutableStateOf(ResultOrError(content, null, null, null))
}
var showOriginal by remember { mutableStateOf(false) }
var langSettingsPopupExpanded by remember { mutableStateOf(false) }
TranslateAndWatchLanguageChanges(content, accountViewModel) { result, newShowOriginal ->
if (translatedTextState.result != result.result ||
translatedTextState.sourceLang != result.sourceLang ||
translatedTextState.targetLang != result.targetLang
) {
translatedTextState = result
}
if (showOriginal != newShowOriginal) {
showOriginal = newShowOriginal
}
}
val toBeViewed by remember(translatedTextState) {
derivedStateOf {
if (showOriginal) content else translatedTextState.result ?: content
}
}
Column {
var translatedTextState by remember {
mutableStateOf(ResultOrError(content, null, null, null))
}
var showOriginal by remember { mutableStateOf(false) }
TranslateAndWatchLanguageChanges(content, accountViewModel) { result, newShowOriginal ->
if (translatedTextState.result != result.result ||
translatedTextState.sourceLang != result.sourceLang ||
translatedTextState.targetLang != result.targetLang
) {
translatedTextState = result
}
if (showOriginal != newShowOriginal) {
showOriginal = newShowOriginal
}
}
val toBeViewed by remember(translatedTextState) {
derivedStateOf {
if (showOriginal) content else translatedTextState.result ?: content
}
}
ExpandableRichTextViewer(
toBeViewed,
canPreview,
@@ -86,69 +85,174 @@ fun TranslatableRichTextViewer(
nav
)
val target = translatedTextState.targetLang
val source = translatedTextState.sourceLang
if (source != null && target != null && source != target) {
val scope = rememberCoroutineScope()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 5.dp)
if (translatedTextState.sourceLang != null &&
translatedTextState.targetLang != null &&
translatedTextState.sourceLang != translatedTextState.targetLang
) {
TranslationMessage(
translatedTextState.sourceLang!!,
translatedTextState.targetLang!!,
accountViewModel
) {
val clickableTextStyle =
SpanStyle(color = MaterialTheme.colors.primary.copy(alpha = 0.52f))
showOriginal = it
}
}
}
}
val annotatedTranslationString = buildAnnotatedString {
withStyle(clickableTextStyle) {
pushStringAnnotation("langSettings", true.toString())
append(stringResource(R.string.translations_auto))
}
@Composable
private fun TranslationMessage(
source: String,
target: String,
accountViewModel: AccountViewModel,
onChangeWhatToShow: (Boolean) -> Unit
) {
var langSettingsPopupExpanded by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
append("-${stringResource(R.string.translations_translated_from)} ")
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 5.dp)
) {
val clickableTextStyle =
SpanStyle(color = MaterialTheme.colors.primary.copy(alpha = 0.52f))
withStyle(clickableTextStyle) {
pushStringAnnotation("showOriginal", true.toString())
append(Locale(source).displayName)
}
val annotatedTranslationString = buildAnnotatedString {
withStyle(clickableTextStyle) {
pushStringAnnotation("langSettings", true.toString())
append(stringResource(R.string.translations_auto))
}
append(" ${stringResource(R.string.translations_to)} ")
append("-${stringResource(R.string.translations_translated_from)} ")
withStyle(clickableTextStyle) {
pushStringAnnotation("showOriginal", false.toString())
append(Locale(target).displayName)
withStyle(clickableTextStyle) {
pushStringAnnotation("showOriginal", true.toString())
append(Locale(source).displayName)
}
append(" ${stringResource(R.string.translations_to)} ")
withStyle(clickableTextStyle) {
pushStringAnnotation("showOriginal", false.toString())
append(Locale(target).displayName)
}
}
ClickableText(
text = annotatedTranslationString,
style = LocalTextStyle.current.copy(
color = MaterialTheme.colors.onSurface.copy(
alpha = 0.32f
)
),
overflow = TextOverflow.Visible,
maxLines = 3
) { spanOffset ->
annotatedTranslationString.getStringAnnotations(spanOffset, spanOffset)
.firstOrNull()
?.also { span ->
if (span.tag == "showOriginal") {
onChangeWhatToShow(span.item.toBoolean())
} else {
langSettingsPopupExpanded = !langSettingsPopupExpanded
}
}
}
ClickableText(
text = annotatedTranslationString,
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)),
overflow = TextOverflow.Visible,
maxLines = 3
) { spanOffset ->
annotatedTranslationString.getStringAnnotations(spanOffset, spanOffset)
.firstOrNull()
?.also { span ->
if (span.tag == "showOriginal") {
showOriginal = span.item.toBoolean()
} else {
langSettingsPopupExpanded = !langSettingsPopupExpanded
}
}
DropdownMenu(
expanded = langSettingsPopupExpanded,
onDismissRequest = { langSettingsPopupExpanded = false }
) {
DropdownMenuItem(onClick = {
scope.launch(Dispatchers.IO) {
accountViewModel.dontTranslateFrom(source)
langSettingsPopupExpanded = false
}
}) {
if (source in accountViewModel.account.dontTranslateFrom) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
modifier = Modifier.size(24.dp)
)
} else {
Spacer(modifier = Modifier.size(24.dp))
}
DropdownMenu(
expanded = langSettingsPopupExpanded,
onDismissRequest = { langSettingsPopupExpanded = false }
) {
Spacer(modifier = Modifier.size(10.dp))
Text(
stringResource(
R.string.translations_never_translate_from_lang,
Locale(source).displayName
)
)
}
Divider()
DropdownMenuItem(onClick = {
scope.launch(Dispatchers.IO) {
accountViewModel.prefer(source, target, source)
langSettingsPopupExpanded = false
}
}) {
if (accountViewModel.account.preferenceBetween(source, target) == source) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
modifier = Modifier.size(24.dp)
)
} else {
Spacer(modifier = Modifier.size(24.dp))
}
Spacer(modifier = Modifier.size(10.dp))
Text(
stringResource(
R.string.translations_show_in_lang_first,
Locale(source).displayName
)
)
}
DropdownMenuItem(onClick = {
scope.launch(Dispatchers.IO) {
accountViewModel.prefer(source, target, target)
langSettingsPopupExpanded = false
}
}) {
if (accountViewModel.account.preferenceBetween(source, target) == target) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
modifier = Modifier.size(24.dp)
)
} else {
Spacer(modifier = Modifier.size(24.dp))
}
Spacer(modifier = Modifier.size(10.dp))
Text(
stringResource(
R.string.translations_show_in_lang_first,
Locale(target).displayName
)
)
}
Divider()
val languageList =
ConfigurationCompat.getLocales(Resources.getSystem().configuration)
for (i in 0 until languageList.size()) {
languageList.get(i)?.let { lang ->
DropdownMenuItem(onClick = {
scope.launch(Dispatchers.IO) {
accountViewModel.dontTranslateFrom(source)
accountViewModel.translateTo(lang)
langSettingsPopupExpanded = false
}
}) {
if (source in accountViewModel.account.dontTranslateFrom) {
if (lang.language in accountViewModel.account.translateTo) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
@@ -160,76 +264,12 @@ fun TranslatableRichTextViewer(
Spacer(modifier = Modifier.size(10.dp))
Text(stringResource(R.string.translations_never_translate_from_lang, Locale(source).displayName))
}
Divider()
DropdownMenuItem(onClick = {
scope.launch(Dispatchers.IO) {
accountViewModel.prefer(source, target, source)
langSettingsPopupExpanded = false
}
}) {
if (accountViewModel.account.preferenceBetween(source, target) == source) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
modifier = Modifier.size(24.dp)
Text(
stringResource(
R.string.translations_always_translate_to_lang,
lang.displayName
)
} else {
Spacer(modifier = Modifier.size(24.dp))
}
Spacer(modifier = Modifier.size(10.dp))
Text(stringResource(R.string.translations_show_in_lang_first, Locale(source).displayName))
}
DropdownMenuItem(onClick = {
scope.launch(Dispatchers.IO) {
accountViewModel.prefer(source, target, target)
langSettingsPopupExpanded = false
}
}) {
if (accountViewModel.account.preferenceBetween(source, target) == target) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
modifier = Modifier.size(24.dp)
)
} else {
Spacer(modifier = Modifier.size(24.dp))
}
Spacer(modifier = Modifier.size(10.dp))
Text(stringResource(R.string.translations_show_in_lang_first, Locale(target).displayName))
}
Divider()
val languageList =
ConfigurationCompat.getLocales(Resources.getSystem().configuration)
for (i in 0 until languageList.size()) {
languageList.get(i)?.let { lang ->
DropdownMenuItem(onClick = {
scope.launch(Dispatchers.IO) {
accountViewModel.translateTo(lang)
langSettingsPopupExpanded = false
}
}) {
if (lang.language in accountViewModel.account.translateTo) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
modifier = Modifier.size(24.dp)
)
} else {
Spacer(modifier = Modifier.size(24.dp))
}
Spacer(modifier = Modifier.size(10.dp))
Text(stringResource(R.string.translations_always_translate_to_lang, lang.displayName))
}
}
)
}
}
}