Restructuring ViewModels

This commit is contained in:
Vitor Pamplona
2023-05-31 16:30:11 -04:00
parent 3744f90e87
commit d942c12627
49 changed files with 1399 additions and 1078 deletions
@@ -55,26 +55,16 @@ fun TranslatableRichTextViewer(
var showOriginal by remember { mutableStateOf(false) }
var langSettingsPopupExpanded by remember { mutableStateOf(false) }
val accountState by accountViewModel.accountLanguagesLiveData.observeAsState()
val account = remember(accountState) { accountState?.account } ?: return
WatchLanguageChanges(content, accountViewModel) { result, newShowOriginal ->
if (translatedTextState.result != result.result ||
translatedTextState.sourceLang != result.sourceLang ||
translatedTextState.targetLang != result.targetLang
) {
translatedTextState = result
}
val scope = rememberCoroutineScope()
LaunchedEffect(accountState) {
scope.launch(Dispatchers.IO) {
LanguageTranslatorService.autoTranslate(
content,
account.dontTranslateFrom,
account.translateTo
).addOnCompleteListener { task ->
if (task.isSuccessful && content != task.result.result) {
if (task.result.sourceLang != null && task.result.targetLang != null) {
val preference = account.preferenceBetween(task.result.sourceLang!!, task.result.targetLang!!)
showOriginal = preference == task.result.sourceLang
}
translatedTextState = task.result
}
}
if (showOriginal != newShowOriginal) {
showOriginal = newShowOriginal
}
}
@@ -98,137 +88,135 @@ fun TranslatableRichTextViewer(
val target = translatedTextState.targetLang
val source = translatedTextState.sourceLang
if (source != null && target != null) {
if (source != target) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 5.dp)
if (source != null && target != null && source != target) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 5.dp)
) {
val clickableTextStyle =
SpanStyle(color = MaterialTheme.colors.primary.copy(alpha = 0.52f))
val annotatedTranslationString = buildAnnotatedString {
withStyle(clickableTextStyle) {
pushStringAnnotation("langSettings", true.toString())
append(stringResource(R.string.translations_auto))
}
append("-${stringResource(R.string.translations_translated_from)} ")
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") {
showOriginal = span.item.toBoolean()
} else {
langSettingsPopupExpanded = !langSettingsPopupExpanded
}
}
}
DropdownMenu(
expanded = langSettingsPopupExpanded,
onDismissRequest = { langSettingsPopupExpanded = false }
) {
val clickableTextStyle =
SpanStyle(color = MaterialTheme.colors.primary.copy(alpha = 0.52f))
val annotatedTranslationString = buildAnnotatedString {
withStyle(clickableTextStyle) {
pushStringAnnotation("langSettings", true.toString())
append(stringResource(R.string.translations_auto))
DropdownMenuItem(onClick = {
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))
}
append("-${stringResource(R.string.translations_translated_from)} ")
Spacer(modifier = Modifier.size(10.dp))
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)
}
Text(stringResource(R.string.translations_never_translate_from_lang, Locale(source).displayName))
}
Divider()
DropdownMenuItem(onClick = {
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))
}
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()
Spacer(modifier = Modifier.size(10.dp))
Text(stringResource(R.string.translations_show_in_lang_first, Locale(source).displayName))
}
DropdownMenuItem(onClick = {
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 = {
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 {
langSettingsPopupExpanded = !langSettingsPopupExpanded
Spacer(modifier = Modifier.size(24.dp))
}
}
}
DropdownMenu(
expanded = langSettingsPopupExpanded,
onDismissRequest = { langSettingsPopupExpanded = false }
) {
DropdownMenuItem(onClick = {
accountViewModel.dontTranslateFrom(source)
langSettingsPopupExpanded = false
}) {
if (source in account.dontTranslateFrom) {
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))
Spacer(modifier = Modifier.size(10.dp))
Text(stringResource(R.string.translations_never_translate_from_lang, Locale(source).displayName))
}
Divider()
DropdownMenuItem(onClick = {
accountViewModel.prefer(source, target, source)
langSettingsPopupExpanded = false
}) {
if (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 = {
accountViewModel.prefer(source, target, target)
langSettingsPopupExpanded = false
}) {
if (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 = {
accountViewModel.translateTo(lang)
langSettingsPopupExpanded = false
}) {
if (lang.language in 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))
}
Text(stringResource(R.string.translations_always_translate_to_lang, lang.displayName))
}
}
}
@@ -237,3 +225,28 @@ fun TranslatableRichTextViewer(
}
}
}
@Composable
fun WatchLanguageChanges(content: String, accountViewModel: AccountViewModel, onTranslated: (ResultOrError, Boolean) -> Unit) {
val accountState by accountViewModel.accountLanguagesLiveData.observeAsState()
val account = remember(accountState) { accountState?.account } ?: return
val scope = rememberCoroutineScope()
LaunchedEffect(accountState) {
scope.launch(Dispatchers.IO) {
LanguageTranslatorService.autoTranslate(
content,
account.dontTranslateFrom,
account.translateTo
).addOnCompleteListener { task ->
if (task.isSuccessful && content != task.result.result) {
if (task.result.sourceLang != null && task.result.targetLang != null) {
val preference = account.preferenceBetween(task.result.sourceLang!!, task.result.targetLang!!)
onTranslated(task.result, preference == task.result.sourceLang)
}
}
}
}
}
}