diff --git a/app/src/main/java/com/bnyro/translate/obj/ListPreferenceOption.kt b/app/src/main/java/com/bnyro/translate/obj/ListPreferenceOption.kt index ca71582ce..980c8466e 100644 --- a/app/src/main/java/com/bnyro/translate/obj/ListPreferenceOption.kt +++ b/app/src/main/java/com/bnyro/translate/obj/ListPreferenceOption.kt @@ -19,5 +19,6 @@ package com.bnyro.translate.obj data class ListPreferenceOption( val name: String, - val value: Int + val value: Int, + val isSelected: Boolean = false ) diff --git a/app/src/main/java/com/bnyro/translate/ui/components/BlockRadioButton.kt b/app/src/main/java/com/bnyro/translate/ui/components/BlockRadioButton.kt index 4bfd28ff9..adf14cff5 100644 --- a/app/src/main/java/com/bnyro/translate/ui/components/BlockRadioButton.kt +++ b/app/src/main/java/com/bnyro/translate/ui/components/BlockRadioButton.kt @@ -18,6 +18,8 @@ package com.bnyro.translate.ui.components import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid @@ -35,13 +37,15 @@ fun BlockRadioButton( ) { Column { LazyVerticalGrid( - columns = GridCells.Fixed(3) + columns = GridCells.Fixed(3), + modifier = Modifier.heightIn(max = 200.dp) ) { items(items) { val index = items.indexOf(it) BlockButton( modifier = Modifier .weight(1f) + .fillMaxWidth() .padding(4.dp, 4.dp), text = it, selected = selected == index diff --git a/app/src/main/java/com/bnyro/translate/ui/components/SelectableItem.kt b/app/src/main/java/com/bnyro/translate/ui/components/SelectableItem.kt index c27bd38a8..9be43faf3 100644 --- a/app/src/main/java/com/bnyro/translate/ui/components/SelectableItem.kt +++ b/app/src/main/java/com/bnyro/translate/ui/components/SelectableItem.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -33,6 +34,7 @@ import androidx.compose.ui.unit.dp @Composable fun SelectableItem( text: String, + isSelected: Boolean = false, onClick: () -> Unit = {} ) { Card( @@ -54,7 +56,8 @@ fun SelectableItem( text = text, modifier = Modifier .fillMaxWidth() - .padding(15.dp) + .padding(15.dp), + color = if (isSelected) MaterialTheme.colorScheme.primary else Color.Unspecified ) } } diff --git a/app/src/main/java/com/bnyro/translate/ui/components/ThemeModeDialog.kt b/app/src/main/java/com/bnyro/translate/ui/components/ThemeModeDialog.kt index 0cf0aed5b..56eaa1bfe 100644 --- a/app/src/main/java/com/bnyro/translate/ui/components/ThemeModeDialog.kt +++ b/app/src/main/java/com/bnyro/translate/ui/components/ThemeModeDialog.kt @@ -32,6 +32,7 @@ fun ThemeModeDialog( ) { val activity = LocalContext.current as MainActivity ListPreferenceDialog( + title = stringResource(R.string.select_theme), preferenceKey = Preferences.themeModeKey, onDismissRequest = { onDismiss.invoke() @@ -39,15 +40,18 @@ fun ThemeModeDialog( options = listOf( ListPreferenceOption( name = stringResource(R.string.theme_auto), - value = ThemeMode.AUTO + value = ThemeMode.AUTO, + isSelected = activity.themeMode == ThemeMode.AUTO ), ListPreferenceOption( name = stringResource(R.string.theme_light), - value = ThemeMode.LIGHT + value = ThemeMode.LIGHT, + isSelected = activity.themeMode == ThemeMode.LIGHT ), ListPreferenceOption( name = stringResource(R.string.theme_dark), - value = ThemeMode.DARK + value = ThemeMode.DARK, + isSelected = activity.themeMode == ThemeMode.DARK ) ), onOptionSelected = { diff --git a/app/src/main/java/com/bnyro/translate/ui/components/prefs/AccentColorPref.kt b/app/src/main/java/com/bnyro/translate/ui/components/prefs/AccentColorPref.kt index 8626e1bf0..b6b580f03 100644 --- a/app/src/main/java/com/bnyro/translate/ui/components/prefs/AccentColorPref.kt +++ b/app/src/main/java/com/bnyro/translate/ui/components/prefs/AccentColorPref.kt @@ -18,8 +18,11 @@ package com.bnyro.translate.ui.components.prefs import android.os.Build -import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -39,6 +42,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.PointerInputChange +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -105,54 +113,72 @@ fun AccentColorPrefDialog( ) } } - Row( - modifier = Modifier.height(250.dp) - ) { - AnimatedVisibility( - visible = color != null - ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally - ) { - listOf("R", "G", "B").forEachIndexed { index, c -> - val startIndex = index * 2 - color?.let { - ColorSlider( - label = c, - value = it.substring(startIndex, startIndex + 2).toInt(16), - onChange = { colorInt -> - var newHex = colorInt.toHexString() - if (newHex.length == 1) newHex = "0$newHex" - color = StringBuilder(it).apply { - setCharAt(startIndex, newHex[0]) - setCharAt(startIndex + 1, newHex[1]) - }.toString() - } - ) - } - } - Spacer(modifier = Modifier.height(20.dp)) - color?.let { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - Modifier.size(50.dp).background( - MaterialTheme.colorScheme.primary, - CircleShape - ) - ) - Text(text = " => ", fontSize = 27.sp) - Box( - modifier = Modifier.size(50.dp).background( - it.hexToColor(), - CircleShape - ) - ) + + val isColorPickerEnabled = color != null + val imageAlpha: Float by animateFloatAsState( + targetValue = if (isColorPickerEnabled) 1f else .5f, + animationSpec = tween( + durationMillis = 250, + easing = LinearEasing, + ) + ) + + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.height(250.dp).alpha(imageAlpha).let { + if (isColorPickerEnabled) { + it + } else { + // disable input + it.pointerInput(Unit){ + awaitPointerEventScope { + while (true) { + awaitPointerEvent(pass = PointerEventPass.Initial) + .changes + .forEach(PointerInputChange::consume) + } } } } } + ) { + listOf("R", "G", "B").forEachIndexed { index, c -> + val startIndex = index * 2 + ColorSlider( + label = c, + value = color?.substring(startIndex, startIndex + 2)?.toInt(16) ?: 0, + onChange = { colorInt -> + var newHex = colorInt.toHexString() + if (newHex.length == 1) newHex = "0$newHex" + color = StringBuilder(color).apply { + setCharAt(startIndex, newHex[0]) + setCharAt(startIndex + 1, newHex[1]) + }.toString() + } + ) + } + Spacer(modifier = Modifier.height(20.dp)) + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + Modifier + .size(50.dp) + .background( + MaterialTheme.colorScheme.primary, + CircleShape + ) + ) + Text(text = " => ", fontSize = 27.sp) + Box( + modifier = Modifier + .size(50.dp) + .background( + color?.hexToColor() ?: Color.Black, + CircleShape + ) + ) + } } } } diff --git a/app/src/main/java/com/bnyro/translate/ui/components/prefs/ListPreferenceDialog.kt b/app/src/main/java/com/bnyro/translate/ui/components/prefs/ListPreferenceDialog.kt index 5b4650705..2d87c1363 100644 --- a/app/src/main/java/com/bnyro/translate/ui/components/prefs/ListPreferenceDialog.kt +++ b/app/src/main/java/com/bnyro/translate/ui/components/prefs/ListPreferenceDialog.kt @@ -34,10 +34,15 @@ fun ListPreferenceDialog( onDismissRequest: () -> Unit, options: List, currentValue: Int? = null, + title: String? = null, onOptionSelected: (ListPreferenceOption) -> Unit = {} ) { AlertDialog( onDismissRequest = onDismissRequest, + title = { + if (title != null) + Text(title) + }, text = { LazyColumn { items(options) { @@ -50,7 +55,8 @@ fun ListPreferenceDialog( ) onOptionSelected.invoke(it) onDismissRequest.invoke() - } + }, + isSelected = it.isSelected ) } } diff --git a/app/src/main/java/com/bnyro/translate/ui/screens/SettingsScreen.kt b/app/src/main/java/com/bnyro/translate/ui/screens/SettingsScreen.kt index c5c115a53..43c7b3524 100644 --- a/app/src/main/java/com/bnyro/translate/ui/screens/SettingsScreen.kt +++ b/app/src/main/java/com/bnyro/translate/ui/screens/SettingsScreen.kt @@ -20,7 +20,7 @@ package com.bnyro.translate.ui.screens import android.os.Handler import android.os.Looper import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -67,7 +67,7 @@ import com.bnyro.translate.util.LocaleHelper import com.bnyro.translate.util.Preferences @Suppress("KotlinConstantConditions") -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun SettingsScreen( navController: NavController @@ -134,163 +134,175 @@ fun SettingsScreen( ) } ) { pV -> - Column( + LazyColumn( + horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier .padding(pV) .fillMaxSize() .padding(15.dp, 0.dp) ) { - EnginePref() - - LazyColumn( - horizontalAlignment = Alignment.CenterHorizontally - ) { - item { - SettingsCategory( - title = stringResource(R.string.general) - ) - - val appLanguages = LocaleHelper.getLanguages(context) + item { + EnginePref() + } - ListPreference( - title = stringResource(R.string.app_language), - preferenceKey = Preferences.appLanguageKey, - defaultValue = "", - entries = appLanguages.map { it.name }, - values = appLanguages.map { it.code } - ) { - Handler(Looper.getMainLooper()).postDelayed({ - (context as MainActivity).recreate() - }, 100) - } + item { + SettingsCategory( + title = stringResource(R.string.general) + ) + + val appLanguages = LocaleHelper.getLanguages(context) + + ListPreference( + title = stringResource(R.string.app_language), + preferenceKey = Preferences.appLanguageKey, + defaultValue = "", + entries = appLanguages.map { it.name }, + values = appLanguages.map { it.code } + ) { + Handler(Looper.getMainLooper()).postDelayed({ + (context as MainActivity).recreate() + }, 100) } + } - item { - PreferenceItem( - modifier = Modifier.padding(top = 10.dp), - title = stringResource(R.string.image_translation), - summary = stringResource(R.string.image_translation_summary) - ) { - showTessSettings = true - } + item { + PreferenceItem( + modifier = Modifier.padding(top = 10.dp), + title = stringResource(R.string.image_translation), + summary = stringResource(R.string.image_translation_summary) + ) { + showTessSettings = true } + } - item { - SettingsCategory( - title = stringResource(R.string.history) - ) + item { + SettingsCategory( + title = stringResource(R.string.history) + ) + + SwitchPreference( + preferenceKey = Preferences.historyEnabledKey, + defaultValue = true, + preferenceTitle = stringResource(R.string.history_enabled), + preferenceSummary = stringResource(R.string.history_summary) + ) + + SwitchPreference( + preferenceKey = Preferences.compactHistory, + defaultValue = true, + preferenceTitle = stringResource(R.string.compact_history), + preferenceSummary = stringResource(R.string.compact_history_summary) + ) + + SwitchPreference( + preferenceKey = Preferences.skipSimilarHistoryKey, + defaultValue = true, + preferenceTitle = stringResource(R.string.skip_similar_entries), + preferenceSummary = stringResource(R.string.skip_similar_entries_desc) + ) + } - SwitchPreference( - preferenceKey = Preferences.historyEnabledKey, - defaultValue = true, - preferenceTitle = stringResource(R.string.history_enabled), - preferenceSummary = stringResource(R.string.history_summary) - ) + item { + SettingsCategory( + title = stringResource(R.string.translation) + ) - SwitchPreference( - preferenceKey = Preferences.compactHistory, - defaultValue = true, - preferenceTitle = stringResource(R.string.compact_history), - preferenceSummary = stringResource(R.string.compact_history_summary) - ) + var translateAutomatically by remember { + mutableStateOf(Preferences.get(Preferences.translateAutomatically, true)) + } - SwitchPreference( - preferenceKey = Preferences.skipSimilarHistoryKey, - defaultValue = true, - preferenceTitle = stringResource(R.string.skip_similar_entries), - preferenceSummary = stringResource(R.string.skip_similar_entries_desc) - ) + SwitchPreference( + preferenceKey = Preferences.translateAutomatically, + defaultValue = true, + preferenceTitle = stringResource(R.string.translate_automatically), + preferenceSummary = stringResource(R.string.translate_automatically_summary) + ) { + translateAutomatically = it } - item { - SettingsCategory( - title = stringResource(R.string.translation) + AnimatedVisibility(visible = translateAutomatically) { + SliderPreference( + preferenceKey = Preferences.fetchDelay, + preferenceTitle = stringResource(R.string.fetch_delay), + preferenceSummary = stringResource(R.string.fetch_delay_summary), + defaultValue = 500f, + minValue = 100f, + maxValue = 1000f, + stepSize = 100f ) + } - var translateAutomatically by remember { - mutableStateOf(Preferences.get(Preferences.translateAutomatically, true)) - } - - SwitchPreference( - preferenceKey = Preferences.translateAutomatically, - defaultValue = true, - preferenceTitle = stringResource(R.string.translate_automatically), - preferenceSummary = stringResource(R.string.translate_automatically_summary) - ) { - translateAutomatically = it - } - - AnimatedVisibility(visible = translateAutomatically) { - SliderPreference( - preferenceKey = Preferences.fetchDelay, - preferenceTitle = stringResource(R.string.fetch_delay), - preferenceSummary = stringResource(R.string.fetch_delay_summary), - defaultValue = 500f, - minValue = 100f, - maxValue = 1000f, - stepSize = 100f - ) - } + SwitchPreference( + preferenceKey = Preferences.showAdditionalInfo, + defaultValue = true, + preferenceTitle = stringResource(R.string.additional_info), + preferenceSummary = stringResource(R.string.additional_info_summary) + ) + } - SwitchPreference( - preferenceKey = Preferences.showAdditionalInfo, - defaultValue = true, - preferenceTitle = stringResource(R.string.additional_info), - preferenceSummary = stringResource(R.string.additional_info_summary) + item { + SettingsCategory( + title = stringResource(R.string.simultaneous_translation) + ) + + SwitchPreference( + preferenceKey = Preferences.simultaneousTranslationKey, + defaultValue = false, + preferenceTitle = stringResource(R.string.simultaneous_translation), + preferenceSummary = stringResource( + R.string.simultaneous_translation_summary ) + ) { + enableSimultaneousTranslation = it } - item { - SettingsCategory( - title = stringResource(R.string.simultaneous_translation) - ) - - SwitchPreference( - preferenceKey = Preferences.simultaneousTranslationKey, - defaultValue = false, - preferenceTitle = stringResource(R.string.simultaneous_translation), - preferenceSummary = stringResource( - R.string.simultaneous_translation_summary - ) - ) { - enableSimultaneousTranslation = it - } - - AnimatedVisibility(visible = enableSimultaneousTranslation) { - Spacer( - modifier = Modifier - .height(10.dp) - ) - PreferenceItem( - title = stringResource(R.string.enabled_engines), - summary = stringResource(R.string.enabled_engines_summary), - modifier = Modifier.fillMaxWidth() - ) { - showEngineSelectDialog = true - } - } + AnimatedVisibility(visible = enableSimultaneousTranslation) { Spacer( modifier = Modifier .height(10.dp) ) - - val charCounterLimits = listOf(stringResource(R.string.none), "50", "100", "150", "200", "300", "400", "500", "1000", "2000", "3000", "5000") - ListPreference( - title = stringResource(R.string.character_warning_limit), - summary = stringResource(R.string.character_warning_limit_summary), - preferenceKey = Preferences.charCounterLimitKey, - defaultValue = charCounterLimits.first(), - entries = charCounterLimits, - values = charCounterLimits.map { - if (it.all { char -> char.isDigit() }) it else "" - } - ) - - Spacer( - modifier = Modifier - .height(15.dp) - ) + PreferenceItem( + title = stringResource(R.string.enabled_engines), + summary = stringResource(R.string.enabled_engines_summary), + modifier = Modifier.fillMaxWidth() + ) { + showEngineSelectDialog = true + } } + Spacer( + modifier = Modifier + .height(10.dp) + ) + + val charCounterLimits = listOf( + stringResource(R.string.none), + "50", + "100", + "150", + "200", + "300", + "400", + "500", + "1000", + "2000", + "3000", + "5000" + ) + ListPreference( + title = stringResource(R.string.character_warning_limit), + summary = stringResource(R.string.character_warning_limit_summary), + preferenceKey = Preferences.charCounterLimitKey, + defaultValue = charCounterLimits.first(), + entries = charCounterLimits, + values = charCounterLimits.map { + if (it.all { char -> char.isDigit() }) it else "" + } + ) + + Spacer( + modifier = Modifier + .height(15.dp) + ) } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0f35676db..0481e705c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -83,4 +83,5 @@ Download and apply languages for text recognition from images. Please download language data in the settings first. Please select a language for the text recognition of images in the settings. + Select Theme \ No newline at end of file