Add dropdown with auto translate language excludes to app settings

Persist changes to settings

TODO:
Load actually excluded languages
Optimise code
Improve UI
This commit is contained in:
David Kaspar
2025-06-16 15:52:46 +02:00
parent f536abb22a
commit 0495dc88fc
5 changed files with 113 additions and 1 deletions
@@ -27,6 +27,7 @@ import com.vitorpamplona.amethyst.R
data class Settings(
val theme: ThemeType = ThemeType.SYSTEM,
val preferredLanguage: String? = null,
val dontTranslateFrom: Set<String> = emptySet(),
val automaticallyShowImages: ConnectivityType = ConnectivityType.ALWAYS,
val automaticallyStartPlayback: ConnectivityType = ConnectivityType.ALWAYS,
val automaticallyShowUrlPreview: ConnectivityType = ConnectivityType.ALWAYS,
@@ -52,6 +52,7 @@ class SharedPreferencesViewModel : ViewModel() {
sharedPrefs.theme = savedSettings.theme
sharedPrefs.language = savedSettings.preferredLanguage
sharedPrefs.dontTranslateFrom = savedSettings.dontTranslateFrom
sharedPrefs.automaticallyShowImages = savedSettings.automaticallyShowImages
sharedPrefs.automaticallyStartPlayback = savedSettings.automaticallyStartPlayback
sharedPrefs.automaticallyShowUrlPreview = savedSettings.automaticallyShowUrlPreview
@@ -82,6 +83,22 @@ class SharedPreferencesViewModel : ViewModel() {
}
}
fun addDontTranslateFrom(languageCode: String) {
val newSet = sharedPrefs.dontTranslateFrom.plus(languageCode)
if (newSet != sharedPrefs.dontTranslateFrom) {
sharedPrefs.dontTranslateFrom = newSet
saveSharedSettings()
}
}
fun removeDontTranslateFrom(languageCode: String) {
val newSet = sharedPrefs.dontTranslateFrom.minus(languageCode)
if (newSet != sharedPrefs.dontTranslateFrom) {
sharedPrefs.dontTranslateFrom = newSet
saveSharedSettings()
}
}
fun updateLanguageInTheUI() {
if (sharedPrefs.language != null) {
viewModelScope.launch(Dispatchers.Main) {
@@ -188,6 +205,7 @@ class SharedPreferencesViewModel : ViewModel() {
Settings(
sharedPrefs.theme,
sharedPrefs.language,
sharedPrefs.dontTranslateFrom,
sharedPrefs.automaticallyShowImages,
sharedPrefs.automaticallyStartPlayback,
sharedPrefs.automaticallyShowUrlPreview,
@@ -38,7 +38,7 @@ import com.vitorpamplona.amethyst.model.ThemeType
class SharedSettingsState {
var theme by mutableStateOf(ThemeType.SYSTEM)
var language by mutableStateOf<String?>(null)
var dontTranslateFrom by mutableStateOf<Set<String>>(emptySet())
var automaticallyShowImages by mutableStateOf(ConnectivityType.ALWAYS)
var automaticallyStartPlayback by mutableStateOf(ConnectivityType.ALWAYS)
var automaticallyShowUrlPreview by mutableStateOf(ConnectivityType.ALWAYS)
@@ -32,10 +32,22 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -77,6 +89,7 @@ import kotlinx.collections.immutable.toImmutableMap
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import java.io.IOException
import java.util.Locale as JavaLocale
fun Context.getLocaleListFromXml(): LocaleListCompat {
val tagsList = mutableListOf<CharSequence>()
@@ -233,6 +246,10 @@ fun SettingsScreen(sharedPreferencesViewModel: SharedPreferencesViewModel) {
Spacer(modifier = HalfVertSpacer)
DontTranslateFromSetting(sharedPreferencesViewModel, languageEntries)
Spacer(modifier = HalfVertSpacer)
SettingsRow(
R.string.theme,
R.string.theme_description,
@@ -322,6 +339,78 @@ fun SettingsScreen(sharedPreferencesViewModel: SharedPreferencesViewModel) {
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DontTranslateFromSetting(
sharedPreferencesViewModel: SharedPreferencesViewModel,
languageEntries: ImmutableMap<String, String>,
) {
var expanded by remember { mutableStateOf(false) }
val selectedLanguages = sharedPreferencesViewModel.sharedPrefs.dontTranslateFrom
Column {
SettingsRow(
name = R.string.dont_translate_from,
description = R.string.dont_translate_from_description,
) {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
) {
OutlinedTextField(
value = stringRes(R.string.add_a_language),
onValueChange = {},
readOnly = true,
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
modifier = Modifier.menuAnchor(),
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
languageEntries.forEach { (displayName, languageCode) ->
if (!selectedLanguages.contains(languageCode)) {
DropdownMenuItem(
text = { Text(text = displayName) },
onClick = {
sharedPreferencesViewModel.addDontTranslateFrom(languageCode)
expanded = false
},
)
}
}
}
}
}
selectedLanguages.forEach { languageCode ->
val displayName =
languageEntries.entries.find { it.value == languageCode }?.key
?: JavaLocale.forLanguageTag(languageCode).displayName
Row(
verticalAlignment = Alignment.CenterVertically,
modifier =
Modifier
.fillMaxWidth()
.padding(vertical = Size10dp),
) {
Text(
text = displayName,
modifier = Modifier.weight(1f),
)
IconButton(onClick = { sharedPreferencesViewModel.removeDontTranslateFrom(languageCode) }) {
Icon(
imageVector = Icons.Default.Clear,
contentDescription = stringRes(R.string.remove),
tint = MaterialTheme.colorScheme.onSurface,
)
}
}
}
}
}
@Composable
fun SettingsRow(
name: Int,
+4
View File
@@ -1178,4 +1178,8 @@
<string name="share_image">Share image…</string>
<string name="search_by_hashtag">Search hashtag: #%1$s</string>
<string name="dont_translate_from">Don\'t Translate From</string>
<string name="dont_translate_from_description">Languages selected here will not be translated</string>
<string name="add_a_language">Add a language</string>
</resources>