Bug 1855988 - Translation Options UI Dialog Screen
parent
7a1afde8d0
commit
de391e74a5
@ -0,0 +1,199 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.translations
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.heading
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.compose.Divider
|
||||
import org.mozilla.fenix.compose.SwitchWithLabel
|
||||
import org.mozilla.fenix.compose.annotation.LightDarkPreview
|
||||
import org.mozilla.fenix.compose.list.TextListItem
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Firefox Translation options bottom sheet dialog.
|
||||
*
|
||||
* @param translationOptionsList A list of [TranslationSwitchItem]s to display.
|
||||
* @param onBackClicked Invoked when the user clicks on the back button.
|
||||
* @param onTranslationSettingsClicked Invoked when the user clicks on the "Translation Settings" button.
|
||||
* @param aboutTranslationClicked Invoked when the user clicks on the "About Translation" button.
|
||||
*/
|
||||
@Composable
|
||||
fun TranslationOptionsDialogBottomSheet(
|
||||
translationOptionsList: List<TranslationSwitchItem>,
|
||||
onBackClicked: () -> Unit,
|
||||
onTranslationSettingsClicked: () -> Unit,
|
||||
aboutTranslationClicked: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = FirefoxTheme.colors.layer2,
|
||||
shape = RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp),
|
||||
)
|
||||
.nestedScroll(rememberNestedScrollInteropConnection()),
|
||||
) {
|
||||
TranslationOptionsDialogHeader(onBackClicked)
|
||||
|
||||
LazyColumn {
|
||||
items(translationOptionsList) { item: TranslationSwitchItem ->
|
||||
SwitchWithLabel(
|
||||
checked = item.isChecked,
|
||||
onCheckedChange = item.onStateChange,
|
||||
label = item.textLabel,
|
||||
modifier = Modifier
|
||||
.padding(start = 72.dp, end = 16.dp),
|
||||
)
|
||||
|
||||
if (item.hasDivider) {
|
||||
Divider(Modifier.padding(top = 4.dp, bottom = 4.dp))
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
TextListItem(
|
||||
label = stringResource(id = R.string.translation_option_bottom_sheet_translation_settings),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 56.dp),
|
||||
onClick = { onTranslationSettingsClicked() },
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
TextListItem(
|
||||
label = stringResource(
|
||||
id = R.string.translation_option_bottom_sheet_about_translations,
|
||||
formatArgs = arrayOf(stringResource(R.string.app_name)),
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 56.dp),
|
||||
onClick = { aboutTranslationClicked() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TranslationOptionsDialogHeader(
|
||||
onBackClicked: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp, start = 16.dp)
|
||||
.defaultMinSize(minHeight = 56.dp),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { onBackClicked() },
|
||||
modifier = Modifier
|
||||
.size(24.dp),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.mozac_ic_back_24),
|
||||
contentDescription = stringResource(R.string.etp_back_button_content_description),
|
||||
tint = FirefoxTheme.colors.iconPrimary,
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(32.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.translation_option_bottom_sheet_title),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.semantics { heading() },
|
||||
color = FirefoxTheme.colors.textPrimary,
|
||||
style = FirefoxTheme.typography.headline7,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of Translation option switch list item.
|
||||
*/
|
||||
@Composable
|
||||
fun getTranslationOptionsList(): List<TranslationSwitchItem> {
|
||||
return mutableListOf<TranslationSwitchItem>().apply {
|
||||
add(
|
||||
TranslationSwitchItem(
|
||||
textLabel = stringResource(R.string.translation_option_bottom_sheet_always_translate),
|
||||
isChecked = false,
|
||||
hasDivider = true,
|
||||
onStateChange = {},
|
||||
),
|
||||
)
|
||||
add(
|
||||
TranslationSwitchItem(
|
||||
textLabel = stringResource(
|
||||
id = R.string.translation_option_bottom_sheet_always_translate_in_language,
|
||||
formatArgs = arrayOf(Locale("es").displayName),
|
||||
),
|
||||
isChecked = false,
|
||||
hasDivider = false,
|
||||
onStateChange = {},
|
||||
),
|
||||
)
|
||||
add(
|
||||
TranslationSwitchItem(
|
||||
textLabel = stringResource(
|
||||
id = R.string.translation_option_bottom_sheet_never_translate_in_language,
|
||||
formatArgs = arrayOf(Locale("es").displayName),
|
||||
),
|
||||
isChecked = true,
|
||||
hasDivider = true,
|
||||
onStateChange = {},
|
||||
),
|
||||
)
|
||||
add(
|
||||
TranslationSwitchItem(
|
||||
textLabel = stringResource(R.string.translation_option_bottom_sheet_never_translate_site),
|
||||
isChecked = true,
|
||||
hasDivider = true,
|
||||
onStateChange = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@LightDarkPreview
|
||||
private fun TranslationSettingsPreview() {
|
||||
FirefoxTheme {
|
||||
TranslationOptionsDialogBottomSheet(
|
||||
translationOptionsList = getTranslationOptionsList(),
|
||||
onBackClicked = {},
|
||||
onTranslationSettingsClicked = {},
|
||||
aboutTranslationClicked = {},
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.translations
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
|
||||
/**
|
||||
* A bottom sheet fragment displaying the Firefox Translation Options dialog.
|
||||
*/
|
||||
class TranslationOptionsDialogFragment : BottomSheetDialogFragment() {
|
||||
|
||||
private var behavior: BottomSheetBehavior<View>? = null
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
|
||||
super.onCreateDialog(savedInstanceState).apply {
|
||||
setOnShowListener {
|
||||
val bottomSheet =
|
||||
findViewById<View?>(R.id.design_bottom_sheet)
|
||||
bottomSheet?.setBackgroundResource(android.R.color.transparent)
|
||||
behavior = BottomSheetBehavior.from(bottomSheet)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
FirefoxTheme {
|
||||
TranslationOptionsDialogBottomSheet(
|
||||
translationOptionsList = getTranslationOptionsList(),
|
||||
onBackClicked = {
|
||||
findNavController().popBackStack()
|
||||
findNavController().navigate(
|
||||
BrowserFragmentDirections.actionBrowserFragmentToTranslationsDialogFragment(),
|
||||
)
|
||||
},
|
||||
onTranslationSettingsClicked = {
|
||||
findNavController().popBackStack()
|
||||
findNavController().navigate(
|
||||
TranslationSettingsFragmentDirections.actionGlobalToTranslationSettingsFragment(),
|
||||
)
|
||||
},
|
||||
aboutTranslationClicked = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.translations
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.heading
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.compose.Divider
|
||||
import org.mozilla.fenix.compose.SwitchWithLabel
|
||||
import org.mozilla.fenix.compose.annotation.LightDarkPreview
|
||||
import org.mozilla.fenix.compose.list.TextListItem
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
|
||||
/**
|
||||
* Firefox Translation settings fragment compose view.
|
||||
*
|
||||
* @param translationSwitchList list of [TranslationSwitchItem]s to display.
|
||||
* @param onAutomaticTranslationClicked Invoked when the user clicks on the "Automatic Translation" button.
|
||||
* @param onNeverTranslationClicked Invoked when the user clicks on the "Never Translation" button.
|
||||
* @param onDownloadLanguageClicked Invoked when the user clicks on the "Download Language" button.
|
||||
*/
|
||||
@Composable
|
||||
fun TranslationSettings(
|
||||
translationSwitchList: List<TranslationSwitchItem>,
|
||||
onAutomaticTranslationClicked: () -> Unit,
|
||||
onNeverTranslationClicked: () -> Unit,
|
||||
onDownloadLanguageClicked: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = FirefoxTheme.colors.layer1,
|
||||
),
|
||||
) {
|
||||
LazyColumn {
|
||||
items(translationSwitchList) { item: TranslationSwitchItem ->
|
||||
SwitchWithLabel(
|
||||
checked = item.isChecked,
|
||||
onCheckedChange = item.onStateChange,
|
||||
label = item.textLabel,
|
||||
modifier = Modifier
|
||||
.padding(start = 72.dp, end = 16.dp),
|
||||
)
|
||||
|
||||
if (item.hasDivider) {
|
||||
Divider(Modifier.padding(top = 8.dp, bottom = 8.dp))
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.translation_settings_translation_preference,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 72.dp, end = 16.dp, bottom = 16.dp, top = 8.dp)
|
||||
.semantics { heading() },
|
||||
color = FirefoxTheme.colors.textAccent,
|
||||
style = FirefoxTheme.typography.headline8,
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
TextListItem(
|
||||
label = stringResource(id = R.string.translation_settings_automatic_translation),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 56.dp),
|
||||
onClick = { onAutomaticTranslationClicked() },
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
TextListItem(
|
||||
label = stringResource(
|
||||
id = R.string.translation_settings_automatic_never_translate_sites,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 56.dp),
|
||||
onClick = { onNeverTranslationClicked() },
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
TextListItem(
|
||||
label = stringResource(
|
||||
id = R.string.translation_settings_download_language,
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 56.dp),
|
||||
onClick = { onDownloadLanguageClicked() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of Translation option switch list item.
|
||||
*/
|
||||
@Composable
|
||||
internal fun getTranslationSettingsSwitchList(): List<TranslationSwitchItem> {
|
||||
return mutableListOf<TranslationSwitchItem>().apply {
|
||||
add(
|
||||
TranslationSwitchItem(
|
||||
textLabel = stringResource(R.string.translation_settings_offer_to_translate),
|
||||
isChecked = true,
|
||||
hasDivider = false,
|
||||
onStateChange = {},
|
||||
),
|
||||
)
|
||||
add(
|
||||
TranslationSwitchItem(
|
||||
textLabel = stringResource(R.string.translation_settings_always_download),
|
||||
isChecked = false,
|
||||
hasDivider = true,
|
||||
onStateChange = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@LightDarkPreview
|
||||
private fun TranslationSettingsPreview() {
|
||||
FirefoxTheme {
|
||||
TranslationSettings(
|
||||
translationSwitchList = getTranslationSettingsSwitchList(),
|
||||
onAutomaticTranslationClicked = {},
|
||||
onDownloadLanguageClicked = {},
|
||||
onNeverTranslationClicked = {},
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.translations
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import mozilla.components.support.base.feature.UserInteractionHandler
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.showToolbar
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
|
||||
/**
|
||||
* A fragment displaying the Firefox Translation settings screen.
|
||||
*/
|
||||
class TranslationSettingsFragment : Fragment(), UserInteractionHandler {
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
showToolbar(getString(R.string.translation_settings_toolbar_title))
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
FirefoxTheme {
|
||||
TranslationSettings(
|
||||
translationSwitchList = getTranslationSettingsSwitchList(),
|
||||
onAutomaticTranslationClicked = {},
|
||||
onDownloadLanguageClicked = {},
|
||||
onNeverTranslationClicked = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
findNavController().popBackStack()
|
||||
findNavController().navigate(
|
||||
TranslationsDialogFragmentDirections.actionGlobalToTranslationOptionsDialogFragment(),
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.translations
|
||||
|
||||
/**
|
||||
* TranslationSwitchItem that will appear on Translation screens.
|
||||
*
|
||||
* @property textLabel The text that will appear on the switch item.
|
||||
* @property isChecked Whether the switch is checked 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,
|
||||
val hasDivider: Boolean,
|
||||
val onStateChange: (Boolean) -> Unit,
|
||||
)
|
Loading…
Reference in New Issue