diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 153dafcef..9060740f9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -25,6 +25,7 @@ class LocalPreferences(context: Context) { remove("hidden_users") remove("relays") remove("dontTranslateFrom") + remove("languagePreferences") remove("translateTo") remove("zapAmounts") remove("latestContactList") @@ -39,6 +40,7 @@ class LocalPreferences(context: Context) { account.hiddenUsers.let { putStringSet("hidden_users", it) } account.localRelays.let { putString("relays", gson.toJson(it)) } account.dontTranslateFrom.let { putStringSet("dontTranslateFrom", it) } + account.languagePreferences.let { putString("languagePreferences", gson.toJson(it)) } account.translateTo.let { putString("translateTo", it) } account.zapAmountChoices.let { putString("zapAmounts", gson.toJson(it)) } account.backupContactList.let { putString("latestContactList", Event.gson.toJson(it)) } @@ -73,6 +75,15 @@ class LocalPreferences(context: Context) { null } + val languagePreferences = try { + getString("languagePreferences", null)?.let { + gson.fromJson(it, object : TypeToken>() {}.type) as Map + } ?: mapOf() + } catch (e: Throwable) { + e.printStackTrace() + mapOf() + } + if (pubKey != null) { return Account( Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()), @@ -80,6 +91,7 @@ class LocalPreferences(context: Context) { hiddenUsers, localRelays, dontTranslateFrom, + languagePreferences, translateTo, zapAmountChoices, latestContactList diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index c0c796105..41a40b168 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -56,6 +56,7 @@ class Account( var hiddenUsers: Set = setOf(), var localRelays: Set = Constants.defaultRelays.toSet(), var dontTranslateFrom: Set = getLanguagesSpokenByUser(), + var languagePreferences: Map = mapOf(), var translateTo: String = Locale.getDefault().language, var zapAmountChoices: List = listOf(500L, 1000L, 5000L), var backupContactList: ContactListEvent? = null @@ -417,6 +418,15 @@ class Account( saveable.invalidateData() } + fun prefer(source: String, target: String, preference: String) { + languagePreferences = languagePreferences + Pair("$source,$target", preference) + saveable.invalidateData() + } + + fun preferenceBetween(source: String, target: String): String? { + return languagePreferences.get("$source,$target") + } + private fun updateContactListTo(newContactList: ContactListEvent?) { if (newContactList?.follows.isNullOrEmpty()) return @@ -491,6 +501,8 @@ class Account( saveable.invalidateData() } + + init { backupContactList?.let { println("Loading saved contacts ${it.toJson()}") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslateableRichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslateableRichTextViewer.kt index 20cc8a1c1..d8e9e939a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslateableRichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TranslateableRichTextViewer.kt @@ -3,15 +3,20 @@ package com.vitorpamplona.amethyst.ui.components import android.content.res.Resources import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.ClickableText import androidx.compose.material.Divider import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon import androidx.compose.material.LocalTextStyle import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -55,14 +60,21 @@ fun TranslateableRichTextViewer( val account = accountState?.account ?: return LaunchedEffect(accountState) { - LanguageTranslatorService.autoTranslate(content, account.dontTranslateFrom, account.translateTo) - .addOnCompleteListener { task -> - if (task.isSuccessful) { - translatedTextState.value = task.result - } else { - translatedTextState.value = ResultOrError(content, null, null, null) + LanguageTranslatorService.autoTranslate( + content, + account.dontTranslateFrom, + account.translateTo + ).addOnCompleteListener { task -> + if (task.isSuccessful) { + 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.value = task.result + } else { + translatedTextState.value = ResultOrError(content, null, null, null) } + } } val toBeViewed = if (showOriginal) content else translatedTextState.value.result ?: content @@ -82,7 +94,9 @@ fun TranslateableRichTextViewer( if (source != null && target != null) { if (source != target) { - Row(modifier = Modifier.fillMaxWidth().padding(top = 5.dp)) { + Row(modifier = Modifier + .fillMaxWidth() + .padding(top = 5.dp)) { val clickableTextStyle = SpanStyle(color = MaterialTheme.colors.primary.copy(alpha = 0.52f)) @@ -131,9 +145,56 @@ fun TranslateableRichTextViewer( accountViewModel.dontTranslateFrom(source, context) 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)) + Text("Never translate from ${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("Show in ${Locale(source).displayName} first") + } + 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("Show in ${Locale(target).displayName} first") + } + Divider() + val languageList = ConfigurationCompat.getLocales(Resources.getSystem().getConfiguration()) for (i in 0 until languageList.size()) { @@ -142,6 +203,17 @@ fun TranslateableRichTextViewer( accountViewModel.translateTo(lang, context) 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("Always translate to ${lang.displayName}") } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 09812ac45..887fd1062 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -82,4 +82,8 @@ class AccountViewModel(private val account: Account): ViewModel() { fun dontTranslateFrom(lang: String, ctx: Context) { account.addDontTranslateFrom(lang) } + + fun prefer(source: String, target: String, preference: String) { + account.prefer(source, target, preference) + } } \ No newline at end of file