Merge pull request #1814 from vitorpamplona/claude/add-translation-settings-MIoUT

feat: add missing translation settings to Translation settings menu
This commit is contained in:
Vitor Pamplona
2026-03-12 19:41:40 -04:00
committed by GitHub
2 changed files with 185 additions and 0 deletions
@@ -20,18 +20,23 @@
*/ */
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
import android.content.res.Resources
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
@@ -47,6 +52,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
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 androidx.core.os.ConfigurationCompat
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
@@ -54,6 +60,7 @@ import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size10dp
import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.Size20dp
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow
@@ -88,6 +95,8 @@ fun UserSettingsScreen(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
DontTranslateFromSetting(accountViewModel) DontTranslateFromSetting(accountViewModel)
TranslateToSetting(accountViewModel)
LanguagePreferencesSetting(accountViewModel)
} }
} }
} }
@@ -143,3 +152,174 @@ fun DontTranslateFromSetting(accountViewModel: AccountViewModel) {
} }
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TranslateToSetting(accountViewModel: AccountViewModel) {
var expanded by remember { mutableStateOf(false) }
val currentTranslateTo = accountViewModel.translateTo()
val languageList = ConfigurationCompat.getLocales(Resources.getSystem().configuration)
Column {
SettingsRow(
name = R.string.translate_to,
description = R.string.translate_to_description,
) {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
) {
OutlinedTextField(
value = JavaLocale(currentTranslateTo).displayName,
onValueChange = {},
readOnly = true,
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryEditable),
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
for (i in 0 until languageList.size()) {
languageList.get(i)?.let { lang ->
DropdownMenuItem(
text = {
Row(verticalAlignment = Alignment.CenterVertically) {
if (accountViewModel.account.settings.translateToContains(lang)) {
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(text = lang.displayName)
}
},
onClick = {
accountViewModel.updateTranslateTo(lang)
expanded = false
},
)
}
}
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LanguagePreferencesSetting(accountViewModel: AccountViewModel) {
val languagePreferences = accountViewModel.account.settings.syncedSettings.languages.languagePreferences
if (languagePreferences.isEmpty()) return
Column {
SettingsRow(
name = R.string.language_preferences,
description = R.string.language_preferences_description,
) {}
languagePreferences.forEach { (key, preference) ->
val parts = key.split(",")
if (parts.size == 2) {
LanguagePreferenceItem(
source = parts[0],
target = parts[1],
preference = preference,
accountViewModel = accountViewModel,
)
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun LanguagePreferenceItem(
source: String,
target: String,
preference: String,
accountViewModel: AccountViewModel,
) {
val sourceName = JavaLocale(source).displayName
val targetName = JavaLocale(target).displayName
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
modifier = Modifier.padding(vertical = 4.dp),
) {
OutlinedTextField(
value = stringRes(R.string.language_preference_pair, sourceName, targetName),
onValueChange = {},
readOnly = true,
label = {
Text(
if (preference == source) {
stringRes(R.string.translations_show_in_lang_first, sourceName)
} else {
stringRes(R.string.translations_show_in_lang_first, targetName)
},
)
},
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryEditable),
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
DropdownMenuItem(
text = {
Row(verticalAlignment = Alignment.CenterVertically) {
if (preference == 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(stringRes(R.string.translations_show_in_lang_first, sourceName))
}
},
onClick = {
accountViewModel.prefer(source, target, source)
expanded = false
},
)
HorizontalDivider(thickness = DividerThickness)
DropdownMenuItem(
text = {
Row(verticalAlignment = Alignment.CenterVertically) {
if (preference == 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(stringRes(R.string.translations_show_in_lang_first, targetName))
}
},
onClick = {
accountViewModel.prefer(source, target, target)
expanded = false
},
)
}
}
}
+5
View File
@@ -1500,6 +1500,11 @@
<string name="dont_translate_from">Don\'t Translate From</string> <string name="dont_translate_from">Don\'t Translate From</string>
<string name="dont_translate_from_description">Languages shown here will not be translated. Select a language to remove it and have it translated again.</string> <string name="dont_translate_from_description">Languages shown here will not be translated. Select a language to remove it and have it translated again.</string>
<string name="translate_to">Translate To</string>
<string name="translate_to_description">Choose the language to translate content into.</string>
<string name="language_preferences">Language Display Preferences</string>
<string name="language_preferences_description">For each translated language pair, choose which language to show first.</string>
<string name="language_preference_pair">%1$s → %2$s</string>
<string name="pause">Pause</string> <string name="pause">Pause</string>
<string name="play">Play</string> <string name="play">Play</string>
<string name="open_dropdown_menu">Open dropdown menu</string> <string name="open_dropdown_menu">Open dropdown menu</string>