diff --git a/app/src/main/java/org/mozilla/fenix/compose/SwitchWithLabel.kt b/app/src/main/java/org/mozilla/fenix/compose/SwitchWithLabel.kt index 3462940cf..71d6d5b6c 100644 --- a/app/src/main/java/org/mozilla/fenix/compose/SwitchWithLabel.kt +++ b/app/src/main/java/org/mozilla/fenix/compose/SwitchWithLabel.kt @@ -35,6 +35,7 @@ private const val DISABLED_ALPHA = 0.5f * UI for a switch with label that can be on or off. * * @param label Text to be displayed next to the switch. + * @param description An optional description text below the label. * @param checked Whether or not the switch is checked. * @param onCheckedChange Invoked when Switch is being clicked, therefore the change of checked * state is requested. @@ -44,6 +45,7 @@ private const val DISABLED_ALPHA = 0.5f @Composable fun SwitchWithLabel( label: String, + description: String? = null, checked: Boolean, onCheckedChange: ((Boolean) -> Unit), modifier: Modifier = Modifier, @@ -60,16 +62,28 @@ fun SwitchWithLabel( horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically, ) { - Text( - text = label, - color = if (enabled) { - FirefoxTheme.colors.textPrimary - } else { - FirefoxTheme.colors.textDisabled - }, - style = FirefoxTheme.typography.subtitle1, - modifier = Modifier.weight(1f), - ) + Column( + modifier = Modifier + .weight(1f), + ) { + Text( + text = label, + color = if (enabled) { + FirefoxTheme.colors.textPrimary + } else { + FirefoxTheme.colors.textDisabled + }, + style = FirefoxTheme.typography.subtitle1, + ) + + description?.let { + Text( + text = description, + color = FirefoxTheme.colors.textSecondary, + style = FirefoxTheme.typography.body2, + ) + } + } Switch( modifier = Modifier.clearAndSetSemantics {}, @@ -139,6 +153,7 @@ private fun SwitchWithLabelPreview() { var enabledSwitchState by remember { mutableStateOf(false) } SwitchWithLabel( label = if (enabledSwitchState) "On" else "Off", + description = "Description text", checked = enabledSwitchState, onCheckedChange = { enabledSwitchState = it }, ) diff --git a/app/src/main/java/org/mozilla/fenix/translations/TranslationOptionsDialog.kt b/app/src/main/java/org/mozilla/fenix/translations/TranslationOptionsDialog.kt index edc111bd2..584f42004 100644 --- a/app/src/main/java/org/mozilla/fenix/translations/TranslationOptionsDialog.kt +++ b/app/src/main/java/org/mozilla/fenix/translations/TranslationOptionsDialog.kt @@ -17,6 +17,9 @@ import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.snapshots.SnapshotStateList +import androidx.compose.runtime.toMutableStateList import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource @@ -49,9 +52,42 @@ fun TranslationOptionsDialog( ) { TranslationOptionsDialogHeader(onBackClicked) + val translationOptionsListState = remember { + translationOptionsList.toMutableStateList() + } + + EnabledTranslationOptionsItems( + translationOptionsListState, + ) + LazyColumn { - items(translationOptionsList) { item: TranslationSwitchItem -> - TranslationOptions(translationSwitchItem = item) + items(translationOptionsListState) { item: TranslationSwitchItem -> + + val translationSwitchItem = TranslationSwitchItem( + textLabel = item.textLabel, + description = if (item.isChecked) item.description else null, + importance = item.importance, + isChecked = item.isChecked, + isEnabled = item.isEnabled, + hasDivider = item.hasDivider, + onStateChange = { checked -> + // If the item has the same importance, only one switch should be enabled. + val iterator = translationOptionsListState.iterator() + iterator.forEach { + if (it != item && it.importance == item.importance && it.isChecked) { + it.isChecked = false + } + } + + val index = translationOptionsListState.indexOf(item) + translationOptionsListState[index] = translationOptionsListState[index].copy( + isChecked = checked, + ) + }, + ) + TranslationOptions( + translationSwitchItem = translationSwitchItem, + ) } item { @@ -79,14 +115,43 @@ fun TranslationOptionsDialog( } } +/** + * If the item with the highest importance is checked, all other items should be disabled. + * If all items are unchecked, all of them are enabled. + * If the item with the highest importance is unchecked and a item with importance 1 is checked , + * the item with importance 0 is disabled. + * If the item with importance 0 is checked all the items are enabled. + */ @Composable -private fun TranslationOptions(translationSwitchItem: TranslationSwitchItem) { +private fun EnabledTranslationOptionsItems( + translationOptionsListState: SnapshotStateList, +) { + val itemCheckedWithHighestImportance = + translationOptionsListState.sortedByDescending { listItem -> listItem.importance } + .firstOrNull { it.isChecked } + + if (itemCheckedWithHighestImportance == null || itemCheckedWithHighestImportance.importance == 0) { + translationOptionsListState.forEach { + it.isEnabled = true + } + } else { + translationOptionsListState.forEach { + it.isEnabled = it.importance >= itemCheckedWithHighestImportance.importance + } + } +} + +@Composable +private fun TranslationOptions( + translationSwitchItem: TranslationSwitchItem, +) { SwitchWithLabel( + label = translationSwitchItem.textLabel, + description = translationSwitchItem.description, + enabled = translationSwitchItem.isEnabled, checked = translationSwitchItem.isChecked, onCheckedChange = translationSwitchItem.onStateChange, - label = translationSwitchItem.textLabel, - modifier = Modifier - .padding(start = 72.dp, end = 16.dp), + modifier = Modifier.padding(start = 72.dp, end = 16.dp), ) if (translationSwitchItem.hasDivider) { @@ -106,8 +171,7 @@ private fun TranslationOptionsDialogHeader( ) { IconButton( onClick = { onBackClicked() }, - modifier = Modifier - .size(24.dp), + modifier = Modifier.size(24.dp), ) { Icon( painter = painterResource(id = R.drawable.mozac_ic_back_24), @@ -140,7 +204,8 @@ fun getTranslationOptionsList(): List { textLabel = stringResource(R.string.translation_option_bottom_sheet_always_translate), isChecked = false, hasDivider = true, - onStateChange = {}, + isEnabled = true, + onStateChange = { }, ), ) add( @@ -149,7 +214,10 @@ fun getTranslationOptionsList(): List { id = R.string.translation_option_bottom_sheet_always_translate_in_language, formatArgs = arrayOf(Locale("es").displayName), ), + description = stringResource(id = R.string.translation_option_bottom_sheet_switch_description), + importance = 1, isChecked = false, + isEnabled = true, hasDivider = false, onStateChange = {}, ), @@ -160,7 +228,10 @@ fun getTranslationOptionsList(): List { id = R.string.translation_option_bottom_sheet_never_translate_in_language, formatArgs = arrayOf(Locale("es").displayName), ), + description = stringResource(id = R.string.translation_option_bottom_sheet_switch_description), + importance = 1, isChecked = true, + isEnabled = true, hasDivider = true, onStateChange = {}, ), @@ -168,7 +239,12 @@ fun getTranslationOptionsList(): List { add( TranslationSwitchItem( textLabel = stringResource(R.string.translation_option_bottom_sheet_never_translate_site), + description = stringResource( + id = R.string.translation_option_bottom_sheet_switch_never_translate_site_description, + ), + importance = 2, isChecked = true, + isEnabled = true, hasDivider = true, onStateChange = {}, ), diff --git a/app/src/main/java/org/mozilla/fenix/translations/TranslationSettings.kt b/app/src/main/java/org/mozilla/fenix/translations/TranslationSettings.kt index 69cc28bcd..691532e0e 100644 --- a/app/src/main/java/org/mozilla/fenix/translations/TranslationSettings.kt +++ b/app/src/main/java/org/mozilla/fenix/translations/TranslationSettings.kt @@ -122,6 +122,7 @@ internal fun getTranslationSettingsSwitchList(): List { textLabel = stringResource(R.string.translation_settings_offer_to_translate), isChecked = true, hasDivider = false, + isEnabled = true, onStateChange = {}, ), ) @@ -130,6 +131,7 @@ internal fun getTranslationSettingsSwitchList(): List { textLabel = stringResource(R.string.translation_settings_always_download), isChecked = false, hasDivider = true, + isEnabled = true, onStateChange = {}, ), ) diff --git a/app/src/main/java/org/mozilla/fenix/translations/TranslationSwitchItem.kt b/app/src/main/java/org/mozilla/fenix/translations/TranslationSwitchItem.kt index 58efbab32..ec6b60f1c 100644 --- a/app/src/main/java/org/mozilla/fenix/translations/TranslationSwitchItem.kt +++ b/app/src/main/java/org/mozilla/fenix/translations/TranslationSwitchItem.kt @@ -8,14 +8,20 @@ package org.mozilla.fenix.translations * TranslationSwitchItem that will appear on Translation screens. * * @property textLabel The text that will appear on the switch item. + * @property description An optional description text below the label. + * @property importance Based on this, the translation switch item is enabled or disabled. * @property isChecked Whether the switch is checked or not. + * @property isEnabled Whether the switch is enabled or not. * @property hasDivider Whether a divider should appear under the switch item. * @property onStateChange Invoked when the switch item is clicked, * the new checked state is passed into the callback. */ data class TranslationSwitchItem( val textLabel: String, - val isChecked: Boolean, + var description: String? = null, + val importance: Int = 0, + var isChecked: Boolean, + var isEnabled: Boolean = true, val hasDivider: Boolean, val onStateChange: (Boolean) -> Unit, ) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 67d6f8b07..e63052abe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2391,6 +2391,10 @@ Never translate %1$s Never translate this site + + Overrides all other settings + + Overrides offers to translate Translation settings