forked from mirrors/gecko-dev
Bug 1862293 - Translations UI Integration Integrate Download Languages - Global Settings r=android-reviewers,ohall
Differential Revision: https://phabricator.services.mozilla.com/D211357
This commit is contained in:
parent
9eaeb8ac81
commit
0067c27e35
10 changed files with 607 additions and 230 deletions
|
|
@ -40,5 +40,6 @@ enum class BrowserDirection(@IdRes val fragmentId: Int) {
|
||||||
FromReviewQualityCheck(R.id.reviewQualityCheckFragment),
|
FromReviewQualityCheck(R.id.reviewQualityCheckFragment),
|
||||||
FromAddonsManagementFragment(R.id.addonsManagementFragment),
|
FromAddonsManagementFragment(R.id.addonsManagementFragment),
|
||||||
FromTranslationsDialogFragment(R.id.translationsDialogFragment),
|
FromTranslationsDialogFragment(R.id.translationsDialogFragment),
|
||||||
|
FromDownloadLanguagesPreferenceFragment(R.id.downloadLanguagesPreferenceFragment),
|
||||||
FromMenuDialogFragment(R.id.menuDialogFragment),
|
FromMenuDialogFragment(R.id.menuDialogFragment),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ import org.mozilla.fenix.shopping.ReviewQualityCheckFragmentDirections
|
||||||
import org.mozilla.fenix.tabstray.TabsTrayFragmentDirections
|
import org.mozilla.fenix.tabstray.TabsTrayFragmentDirections
|
||||||
import org.mozilla.fenix.trackingprotection.TrackingProtectionPanelDialogFragmentDirections
|
import org.mozilla.fenix.trackingprotection.TrackingProtectionPanelDialogFragmentDirections
|
||||||
import org.mozilla.fenix.translations.TranslationsDialogFragmentDirections
|
import org.mozilla.fenix.translations.TranslationsDialogFragmentDirections
|
||||||
|
import org.mozilla.fenix.translations.preferences.downloadlanguages.DownloadLanguagesPreferenceFragmentDirections
|
||||||
import java.security.InvalidParameterException
|
import java.security.InvalidParameterException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -326,6 +327,9 @@ private fun getHomeNavDirections(
|
||||||
BrowserDirection.FromTranslationsDialogFragment -> TranslationsDialogFragmentDirections.actionGlobalBrowser()
|
BrowserDirection.FromTranslationsDialogFragment -> TranslationsDialogFragmentDirections.actionGlobalBrowser()
|
||||||
|
|
||||||
BrowserDirection.FromMenuDialogFragment -> MenuDialogFragmentDirections.actionGlobalBrowser()
|
BrowserDirection.FromMenuDialogFragment -> MenuDialogFragmentDirections.actionGlobalBrowser()
|
||||||
|
|
||||||
|
BrowserDirection.FromDownloadLanguagesPreferenceFragment ->
|
||||||
|
DownloadLanguagesPreferenceFragmentDirections.actionGlobalBrowser()
|
||||||
}
|
}
|
||||||
|
|
||||||
const val REQUEST_CODE_BROWSER_ROLE = 1
|
const val REQUEST_CODE_BROWSER_ROLE = 1
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,9 @@ import java.util.Locale
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun DeleteLanguageFileDialog(
|
fun DeleteLanguageFileDialog(
|
||||||
language: String,
|
language: String? = null,
|
||||||
isAllLanguagesItemType: Boolean,
|
isAllLanguagesItemType: Boolean,
|
||||||
fileSize: Long,
|
fileSize: Long? = null,
|
||||||
onConfirmDelete: () -> Unit,
|
onConfirmDelete: () -> Unit,
|
||||||
onCancel: () -> Unit,
|
onCancel: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
|
@ -43,24 +43,28 @@ fun DeleteLanguageFileDialog(
|
||||||
shape = RoundedCornerShape(8.dp),
|
shape = RoundedCornerShape(8.dp),
|
||||||
),
|
),
|
||||||
title = {
|
title = {
|
||||||
val title: String = if (isAllLanguagesItemType) {
|
val title: String? = if (isAllLanguagesItemType) {
|
||||||
stringResource(
|
stringResource(
|
||||||
id = R.string.delete_language_all_languages_file_dialog_title,
|
id = R.string.delete_language_all_languages_file_dialog_title,
|
||||||
fileSize.toMegabyteOrKilobyteString(),
|
fileSize?.toMegabyteOrKilobyteString() ?: 0L,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
stringResource(
|
language?.let {
|
||||||
id = R.string.delete_language_file_dialog_title,
|
stringResource(
|
||||||
language,
|
id = R.string.delete_language_file_dialog_title,
|
||||||
fileSize.toMegabyteOrKilobyteString(),
|
it,
|
||||||
)
|
fileSize?.toMegabyteOrKilobyteString() ?: 0L,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
title?.let {
|
||||||
text = title,
|
Text(
|
||||||
color = FirefoxTheme.colors.textPrimary,
|
text = it,
|
||||||
style = FirefoxTheme.typography.headline7,
|
color = FirefoxTheme.colors.textPrimary,
|
||||||
)
|
style = FirefoxTheme.typography.headline7,
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
text = {
|
text = {
|
||||||
val message: String = if (isAllLanguagesItemType) {
|
val message: String = if (isAllLanguagesItemType) {
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ import org.mozilla.fenix.theme.FirefoxTheme
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
fun DownloadLanguageFileDialog(
|
fun DownloadLanguageFileDialog(
|
||||||
downloadLanguageDialogType: DownloadLanguageFileDialogType,
|
downloadLanguageDialogType: DownloadLanguageFileDialogType,
|
||||||
fileSize: Long,
|
fileSize: Long? = null,
|
||||||
isCheckBoxEnabled: Boolean,
|
isCheckBoxEnabled: Boolean,
|
||||||
isCacheMessage: Boolean = false,
|
isCacheMessage: Boolean = false,
|
||||||
onSavingModeStateChange: (Boolean) -> Unit,
|
onSavingModeStateChange: (Boolean) -> Unit,
|
||||||
|
|
@ -70,12 +70,12 @@ fun DownloadLanguageFileDialog(
|
||||||
if (downloadLanguageDialogType is DownloadLanguageFileDialogType.TranslationRequest) {
|
if (downloadLanguageDialogType is DownloadLanguageFileDialogType.TranslationRequest) {
|
||||||
stringResource(
|
stringResource(
|
||||||
R.string.translations_download_language_file_dialog_title,
|
R.string.translations_download_language_file_dialog_title,
|
||||||
fileSize.toMegabyteOrKilobyteString(),
|
fileSize?.toMegabyteOrKilobyteString() ?: 0L,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
stringResource(
|
stringResource(
|
||||||
R.string.download_language_file_dialog_title,
|
R.string.download_language_file_dialog_title,
|
||||||
fileSize.toMegabyteOrKilobyteString(),
|
fileSize?.toMegabyteOrKilobyteString() ?: 0L,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -90,11 +90,15 @@ fun DownloadLanguageFileDialog(
|
||||||
downloadLanguageDialogType is DownloadLanguageFileDialogType.TranslationRequest
|
downloadLanguageDialogType is DownloadLanguageFileDialogType.TranslationRequest
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = if (isCacheMessage) { stringResource(
|
text = if (isCacheMessage) {
|
||||||
R.string.download_language_file_dialog_message_all_languages,
|
stringResource(
|
||||||
) } else { stringResource(
|
R.string.download_language_file_dialog_message_all_languages,
|
||||||
R.string.download_language_file_dialog_message_all_languages_no_cache,
|
)
|
||||||
) },
|
} else {
|
||||||
|
stringResource(
|
||||||
|
R.string.download_language_file_dialog_message_all_languages_no_cache,
|
||||||
|
)
|
||||||
|
},
|
||||||
modifier = Modifier.padding(top = 16.dp, bottom = 16.dp),
|
modifier = Modifier.padding(top = 16.dp, bottom = 16.dp),
|
||||||
style = FirefoxTheme.typography.body2,
|
style = FirefoxTheme.typography.body2,
|
||||||
color = FirefoxTheme.colors.textPrimary,
|
color = FirefoxTheme.colors.textPrimary,
|
||||||
|
|
|
||||||
|
|
@ -4,32 +4,21 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.translations.preferences.downloadlanguages
|
package org.mozilla.fenix.translations.preferences.downloadlanguages
|
||||||
|
|
||||||
import android.os.Parcelable
|
import mozilla.components.concept.engine.translate.LanguageModel
|
||||||
import kotlinx.parcelize.Parcelize
|
|
||||||
import org.mozilla.geckoview.TranslationsController
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DownloadLanguageItemPreference that will appear on [DownloadLanguagesPreferenceFragment] screen.
|
* DownloadLanguageItemPreference that will appear on [DownloadLanguagesPreferenceFragment] screen.
|
||||||
*
|
*
|
||||||
* @property languageModel The object comes from the translation engine.
|
* @property languageModel The object comes from the translation engine.
|
||||||
* @property state State of the [languageModel].
|
* @property type The type of the language item.
|
||||||
|
* @property enabled Whether the item is enabled or not.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
data class DownloadLanguageItemPreference(
|
data class DownloadLanguageItemPreference(
|
||||||
val languageModel: TranslationsController.RuntimeTranslation.LanguageModel,
|
val languageModel: LanguageModel,
|
||||||
val state: DownloadLanguageItemStatePreference,
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DownloadLanguageItemStatePreference the state of the [DownloadLanguageItemPreference]
|
|
||||||
*
|
|
||||||
* @property type The type of the language item.
|
|
||||||
* @property status State of the language file.
|
|
||||||
*/
|
|
||||||
@Parcelize
|
|
||||||
data class DownloadLanguageItemStatePreference(
|
|
||||||
val type: DownloadLanguageItemTypePreference,
|
val type: DownloadLanguageItemTypePreference,
|
||||||
val status: DownloadLanguageItemStatusPreference,
|
val enabled: Boolean = true,
|
||||||
) : Parcelable
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DownloadLanguageItemTypePreference the type of the [DownloadLanguageItemPreference]
|
* DownloadLanguageItemTypePreference the type of the [DownloadLanguageItemPreference]
|
||||||
|
|
@ -39,13 +28,3 @@ enum class DownloadLanguageItemTypePreference {
|
||||||
AllLanguages,
|
AllLanguages,
|
||||||
GeneralLanguage,
|
GeneralLanguage,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DownloadLanguageItemStatusPreference the status of the [DownloadLanguageItemPreference]
|
|
||||||
*/
|
|
||||||
enum class DownloadLanguageItemStatusPreference {
|
|
||||||
Downloaded,
|
|
||||||
NotDownloaded,
|
|
||||||
DownloadInProgress,
|
|
||||||
Selected,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,12 @@ import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.defaultMinSize
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
|
|
@ -38,6 +40,9 @@ import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.text.withStyle
|
import androidx.compose.ui.text.withStyle
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import mozilla.components.concept.engine.translate.Language
|
||||||
|
import mozilla.components.concept.engine.translate.LanguageModel
|
||||||
|
import mozilla.components.concept.engine.translate.ModelState
|
||||||
import mozilla.components.feature.downloads.toMegabyteOrKilobyteString
|
import mozilla.components.feature.downloads.toMegabyteOrKilobyteString
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.compose.Divider
|
import org.mozilla.fenix.compose.Divider
|
||||||
|
|
@ -46,42 +51,73 @@ import org.mozilla.fenix.compose.LinkTextState
|
||||||
import org.mozilla.fenix.compose.annotation.LightDarkPreview
|
import org.mozilla.fenix.compose.annotation.LightDarkPreview
|
||||||
import org.mozilla.fenix.theme.FirefoxTheme
|
import org.mozilla.fenix.theme.FirefoxTheme
|
||||||
import org.mozilla.fenix.translations.DownloadIconIndicator
|
import org.mozilla.fenix.translations.DownloadIconIndicator
|
||||||
import org.mozilla.geckoview.TranslationsController
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Firefox Download Languages preference screen.
|
* Firefox Download Languages preference screen.
|
||||||
*
|
*
|
||||||
* @param downloadLanguageItemPreferences List of [DownloadLanguageItemPreference]s that needs to be displayed.
|
* @param downloadLanguageItemPreferences List of [DownloadLanguageItemPreference]s that needs to be displayed.
|
||||||
|
* @param learnMoreUrl The learn more link for translations website.
|
||||||
|
* @param onLearnMoreClicked Invoked when the user clicks on the "Learn More" button.
|
||||||
* @param onItemClick Invoked when the user clicks on the language item.
|
* @param onItemClick Invoked when the user clicks on the language item.
|
||||||
*/
|
*/
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
@Composable
|
@Composable
|
||||||
fun DownloadLanguagesPreference(
|
fun DownloadLanguagesPreference(
|
||||||
downloadLanguageItemPreferences: List<DownloadLanguageItemPreference>,
|
downloadLanguageItemPreferences: List<DownloadLanguageItemPreference>,
|
||||||
|
learnMoreUrl: String,
|
||||||
|
onLearnMoreClicked: () -> Unit,
|
||||||
onItemClick: (DownloadLanguageItemPreference) -> Unit,
|
onItemClick: (DownloadLanguageItemPreference) -> Unit,
|
||||||
) {
|
) {
|
||||||
val downloadedItems = downloadLanguageItemPreferences.filter {
|
val downloadedItems = downloadLanguageItemPreferences.filter {
|
||||||
it.state.status == DownloadLanguageItemStatusPreference.Downloaded &&
|
it.languageModel.status == ModelState.DOWNLOADED &&
|
||||||
it.state.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
it.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
||||||
}
|
}
|
||||||
|
|
||||||
val notDownloadedItems = downloadLanguageItemPreferences.filter {
|
val notDownloadedItems = downloadLanguageItemPreferences.filter {
|
||||||
it.state.status == DownloadLanguageItemStatusPreference.NotDownloaded &&
|
it.languageModel.status == ModelState.NOT_DOWNLOADED &&
|
||||||
it.state.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
it.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
||||||
}
|
}
|
||||||
|
|
||||||
val inProgressItems = downloadLanguageItemPreferences.filter {
|
val downloadInProgressItems = downloadLanguageItemPreferences.filter {
|
||||||
it.state.status == DownloadLanguageItemStatusPreference.DownloadInProgress &&
|
it.languageModel.status == ModelState.DOWNLOAD_IN_PROGRESS &&
|
||||||
it.state.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
it.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
||||||
}
|
}
|
||||||
|
|
||||||
val allLanguagesItem = downloadLanguageItemPreferences.last {
|
val deleteInProgressItems = downloadLanguageItemPreferences.filter {
|
||||||
it.state.type == DownloadLanguageItemTypePreference.AllLanguages
|
it.languageModel.status == ModelState.DELETION_IN_PROGRESS &&
|
||||||
|
it.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaultLanguageItem = downloadLanguageItemPreferences.last {
|
var allLanguagesItemDownloaded: DownloadLanguageItemPreference? = null
|
||||||
it.state.type == DownloadLanguageItemTypePreference.PivotLanguage
|
if (downloadLanguageItemPreferences.any {
|
||||||
|
it.type == DownloadLanguageItemTypePreference.AllLanguages &&
|
||||||
|
it.languageModel.status == ModelState.DOWNLOADED
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
allLanguagesItemDownloaded = downloadLanguageItemPreferences.last {
|
||||||
|
it.type == DownloadLanguageItemTypePreference.AllLanguages &&
|
||||||
|
it.languageModel.status == ModelState.DOWNLOADED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var allLanguagesItemNotDownloaded: DownloadLanguageItemPreference? = null
|
||||||
|
if (downloadLanguageItemPreferences.any {
|
||||||
|
it.type == DownloadLanguageItemTypePreference.AllLanguages &&
|
||||||
|
it.languageModel.status == ModelState.NOT_DOWNLOADED
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
allLanguagesItemNotDownloaded = downloadLanguageItemPreferences.last {
|
||||||
|
it.type == DownloadLanguageItemTypePreference.AllLanguages &&
|
||||||
|
it.languageModel.status == ModelState.NOT_DOWNLOADED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pivotLanguage: DownloadLanguageItemPreference? = null
|
||||||
|
if (downloadLanguageItemPreferences.any { it.type == DownloadLanguageItemTypePreference.PivotLanguage }) {
|
||||||
|
pivotLanguage = downloadLanguageItemPreferences.last {
|
||||||
|
it.type == DownloadLanguageItemTypePreference.PivotLanguage
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
|
@ -89,22 +125,33 @@ fun DownloadLanguagesPreference(
|
||||||
color = FirefoxTheme.colors.layer1,
|
color = FirefoxTheme.colors.layer1,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
DownloadLanguagesHeaderPreference()
|
DownloadLanguagesHeaderPreference(
|
||||||
|
learnMoreUrl = learnMoreUrl,
|
||||||
|
onLearnMoreClicked = onLearnMoreClicked,
|
||||||
|
)
|
||||||
|
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
if (
|
||||||
DownloadLanguagesHeader(
|
allLanguagesItemDownloaded != null ||
|
||||||
stringResource(
|
pivotLanguage?.languageModel?.status == ModelState.DOWNLOADED ||
|
||||||
id = R.string.download_languages_available_languages_preference,
|
downloadInProgressItems.isNotEmpty()
|
||||||
),
|
) {
|
||||||
)
|
item {
|
||||||
|
DownloadLanguagesHeader(
|
||||||
|
stringResource(
|
||||||
|
id = R.string.download_languages_available_languages_preference,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item {
|
allLanguagesItemDownloaded?.let {
|
||||||
LanguageItemPreference(
|
item {
|
||||||
item = defaultLanguageItem,
|
LanguageItemPreference(
|
||||||
onItemClick = onItemClick,
|
item = allLanguagesItemDownloaded,
|
||||||
)
|
onItemClick = onItemClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items(downloadedItems) { item: DownloadLanguageItemPreference ->
|
items(downloadedItems) { item: DownloadLanguageItemPreference ->
|
||||||
|
|
@ -114,31 +161,75 @@ fun DownloadLanguagesPreference(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
items(inProgressItems) { item: DownloadLanguageItemPreference ->
|
items(downloadInProgressItems) { item: DownloadLanguageItemPreference ->
|
||||||
LanguageItemPreference(
|
LanguageItemPreference(
|
||||||
item = item,
|
item = item,
|
||||||
onItemClick = onItemClick,
|
onItemClick = onItemClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
item {
|
if (
|
||||||
Divider(Modifier.padding(top = 8.dp, bottom = 8.dp))
|
pivotLanguage != null &&
|
||||||
|
pivotLanguage.languageModel.status == ModelState.DOWNLOADED
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
LanguageItemPreference(
|
||||||
|
item = pivotLanguage,
|
||||||
|
onItemClick = onItemClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item {
|
if (pivotLanguage?.languageModel?.status == ModelState.NOT_DOWNLOADED ||
|
||||||
DownloadLanguagesHeader(
|
shouldShowDownloadLanguagesHeader(
|
||||||
stringResource(
|
allLanguagesItemNotDownloaded = allLanguagesItemNotDownloaded,
|
||||||
id = R.string.download_language_header_preference,
|
deleteInProgressItems = deleteInProgressItems,
|
||||||
),
|
notDownloadedItems = notDownloadedItems,
|
||||||
)
|
)
|
||||||
|
) {
|
||||||
|
if (pivotLanguage?.languageModel?.status == ModelState.DOWNLOADED ||
|
||||||
|
downloadInProgressItems.isNotEmpty() ||
|
||||||
|
allLanguagesItemDownloaded != null
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
Divider(Modifier.padding(top = 8.dp, bottom = 8.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
DownloadLanguagesHeader(
|
||||||
|
stringResource(
|
||||||
|
id = R.string.download_language_header_preference,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item {
|
allLanguagesItemNotDownloaded?.let {
|
||||||
|
item {
|
||||||
|
LanguageItemPreference(
|
||||||
|
item = allLanguagesItemNotDownloaded,
|
||||||
|
onItemClick = onItemClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pivotLanguage != null &&
|
||||||
|
pivotLanguage.languageModel.status == ModelState.NOT_DOWNLOADED
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
LanguageItemPreference(
|
||||||
|
item = pivotLanguage,
|
||||||
|
onItemClick = onItemClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items(deleteInProgressItems) { item: DownloadLanguageItemPreference ->
|
||||||
LanguageItemPreference(
|
LanguageItemPreference(
|
||||||
item = allLanguagesItem,
|
item = item,
|
||||||
onItemClick = onItemClick,
|
onItemClick = onItemClick,
|
||||||
)
|
)
|
||||||
Divider(Modifier.padding(top = 8.dp, bottom = 8.dp))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items(notDownloadedItems) { item: DownloadLanguageItemPreference ->
|
items(notDownloadedItems) { item: DownloadLanguageItemPreference ->
|
||||||
|
|
@ -153,14 +244,26 @@ fun DownloadLanguagesPreference(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun shouldShowDownloadLanguagesHeader(
|
||||||
|
allLanguagesItemNotDownloaded: DownloadLanguageItemPreference?,
|
||||||
|
deleteInProgressItems: List<DownloadLanguageItemPreference>,
|
||||||
|
notDownloadedItems: List<DownloadLanguageItemPreference>,
|
||||||
|
): Boolean {
|
||||||
|
return allLanguagesItemNotDownloaded != null ||
|
||||||
|
deleteInProgressItems.isNotEmpty() ||
|
||||||
|
notDownloadedItems.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DownloadLanguagesHeader(title: String) {
|
private fun DownloadLanguagesHeader(title: String) {
|
||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 72.dp, end = 16.dp, top = 8.dp)
|
.padding(start = 72.dp, end = 16.dp)
|
||||||
.semantics { heading() },
|
.semantics { heading() }
|
||||||
|
.defaultMinSize(minHeight = 36.dp)
|
||||||
|
.wrapContentHeight(),
|
||||||
color = FirefoxTheme.colors.textAccent,
|
color = FirefoxTheme.colors.textAccent,
|
||||||
style = FirefoxTheme.typography.headline8,
|
style = FirefoxTheme.typography.headline8,
|
||||||
)
|
)
|
||||||
|
|
@ -172,16 +275,36 @@ private fun LanguageItemPreference(
|
||||||
onItemClick: (DownloadLanguageItemPreference) -> Unit,
|
onItemClick: (DownloadLanguageItemPreference) -> Unit,
|
||||||
) {
|
) {
|
||||||
val description: String =
|
val description: String =
|
||||||
if (item.state.type == DownloadLanguageItemTypePreference.PivotLanguage) {
|
if (
|
||||||
|
item.type == DownloadLanguageItemTypePreference.PivotLanguage &&
|
||||||
|
item.languageModel.status == ModelState.DOWNLOADED &&
|
||||||
|
!item.enabled
|
||||||
|
) {
|
||||||
stringResource(id = R.string.download_languages_default_system_language_require_preference)
|
stringResource(id = R.string.download_languages_default_system_language_require_preference)
|
||||||
} else {
|
} else {
|
||||||
item.languageModel.size.toMegabyteOrKilobyteString()
|
var size = 0L
|
||||||
|
item.languageModel.size?.let { size = it }
|
||||||
|
size.toMegabyteOrKilobyteString()
|
||||||
}
|
}
|
||||||
|
|
||||||
val contentDescription =
|
val label = if (item.type == DownloadLanguageItemTypePreference.AllLanguages) {
|
||||||
downloadLanguageItemContentDescriptionPreference(item = item, itemDescription = description)
|
if (item.languageModel.status == ModelState.NOT_DOWNLOADED) {
|
||||||
|
stringResource(id = R.string.download_language_all_languages_item_preference)
|
||||||
|
} else {
|
||||||
|
stringResource(id = R.string.download_language_all_languages_item_preference_to_delete)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.languageModel.language?.localizedDisplayName
|
||||||
|
}
|
||||||
|
|
||||||
item.languageModel.language?.localizedDisplayName?.let {
|
val contentDescription =
|
||||||
|
downloadLanguageItemContentDescriptionPreference(
|
||||||
|
item = item,
|
||||||
|
label = label,
|
||||||
|
itemDescription = description,
|
||||||
|
)
|
||||||
|
|
||||||
|
label?.let {
|
||||||
TextListItemInlineDescription(
|
TextListItemInlineDescription(
|
||||||
label = it,
|
label = it,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -190,25 +313,33 @@ private fun LanguageItemPreference(
|
||||||
)
|
)
|
||||||
.clearAndSetSemantics {
|
.clearAndSetSemantics {
|
||||||
role = Role.Button
|
role = Role.Button
|
||||||
this.contentDescription =
|
this.contentDescription = contentDescription
|
||||||
contentDescription
|
}
|
||||||
},
|
.defaultMinSize(minHeight = 56.dp)
|
||||||
|
.wrapContentHeight(),
|
||||||
description = description,
|
description = description,
|
||||||
enabled = item.state.status != DownloadLanguageItemStatusPreference.DownloadInProgress,
|
enabled = item.enabled,
|
||||||
onClick = { onItemClick(item) },
|
onClick = { onItemClick(item) },
|
||||||
icon = { IconDownloadLanguageItemPreference(item = item) },
|
icon = {
|
||||||
|
IconDownloadLanguageItemPreference(
|
||||||
|
item = item,
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DownloadLanguagesHeaderPreference() {
|
private fun DownloadLanguagesHeaderPreference(
|
||||||
|
learnMoreUrl: String,
|
||||||
|
onLearnMoreClicked: () -> Unit,
|
||||||
|
) {
|
||||||
val learnMoreText =
|
val learnMoreText =
|
||||||
stringResource(id = R.string.download_languages_header_learn_more_preference)
|
stringResource(id = R.string.download_languages_header_learn_more_preference)
|
||||||
val learnMoreState = LinkTextState(
|
val learnMoreState = LinkTextState(
|
||||||
text = learnMoreText,
|
text = learnMoreText,
|
||||||
url = "www.mozilla.com",
|
url = learnMoreUrl,
|
||||||
onClick = {},
|
onClick = { onLearnMoreClicked() },
|
||||||
)
|
)
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -232,52 +363,53 @@ private fun DownloadLanguagesHeaderPreference() {
|
||||||
linkTextDecoration = TextDecoration.Underline,
|
linkTextDecoration = TextDecoration.Underline,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.size(8.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun downloadLanguageItemContentDescriptionPreference(
|
private fun downloadLanguageItemContentDescriptionPreference(
|
||||||
item: DownloadLanguageItemPreference,
|
item: DownloadLanguageItemPreference,
|
||||||
|
label: String? = null,
|
||||||
itemDescription: String,
|
itemDescription: String,
|
||||||
): String {
|
): String {
|
||||||
val contentDescription: String
|
val contentDescription: String
|
||||||
|
|
||||||
when (item.state.status) {
|
when (item.languageModel.status) {
|
||||||
DownloadLanguageItemStatusPreference.Downloaded -> {
|
ModelState.DOWNLOADED -> {
|
||||||
contentDescription =
|
contentDescription =
|
||||||
item.languageModel.language?.localizedDisplayName + " " + itemDescription + stringResource(
|
"$label $itemDescription" + stringResource(
|
||||||
id = R.string.download_languages_item_content_description_downloaded_state,
|
id = R.string.download_languages_item_content_description_downloaded_state,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadLanguageItemStatusPreference.NotDownloaded -> {
|
ModelState.NOT_DOWNLOADED -> {
|
||||||
contentDescription =
|
contentDescription =
|
||||||
item.languageModel.language?.localizedDisplayName + " " + itemDescription + " " + stringResource(
|
"$label $itemDescription " + stringResource(
|
||||||
id = R.string.download_languages_item_content_description_not_downloaded_state,
|
id = R.string.download_languages_item_content_description_not_downloaded_state,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadLanguageItemStatusPreference.DownloadInProgress -> {
|
ModelState.DOWNLOAD_IN_PROGRESS, ModelState.DELETION_IN_PROGRESS -> {
|
||||||
contentDescription =
|
contentDescription =
|
||||||
item.languageModel.language?.localizedDisplayName + " " + itemDescription + " " + stringResource(
|
"$label $itemDescription " + stringResource(
|
||||||
id = R.string.download_languages_item_content_description_in_progress_state,
|
id = R.string.download_languages_item_content_description_in_progress_state,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadLanguageItemStatusPreference.Selected -> {
|
|
||||||
contentDescription =
|
|
||||||
item.languageModel.language?.localizedDisplayName + " " + itemDescription + stringResource(
|
|
||||||
id = R.string.download_languages_item_content_description_selected_state,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return contentDescription
|
return contentDescription
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun IconDownloadLanguageItemPreference(item: DownloadLanguageItemPreference) {
|
private fun IconDownloadLanguageItemPreference(
|
||||||
when (item.state.status) {
|
item: DownloadLanguageItemPreference,
|
||||||
DownloadLanguageItemStatusPreference.Downloaded -> {
|
) {
|
||||||
if (item.state.type != DownloadLanguageItemTypePreference.PivotLanguage) {
|
when (item.languageModel.status) {
|
||||||
|
ModelState.DOWNLOADED -> {
|
||||||
|
if (
|
||||||
|
item.type != DownloadLanguageItemTypePreference.PivotLanguage ||
|
||||||
|
item.enabled
|
||||||
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(
|
painter = painterResource(
|
||||||
id = R.drawable.ic_delete,
|
id = R.drawable.ic_delete,
|
||||||
|
|
@ -288,27 +420,21 @@ private fun IconDownloadLanguageItemPreference(item: DownloadLanguageItemPrefere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadLanguageItemStatusPreference.NotDownloaded -> {
|
ModelState.NOT_DOWNLOADED -> {
|
||||||
if (item.state.type != DownloadLanguageItemTypePreference.PivotLanguage) {
|
Icon(
|
||||||
Icon(
|
painter = painterResource(
|
||||||
painter = painterResource(
|
id = R.drawable.ic_download,
|
||||||
id = R.drawable.ic_download,
|
),
|
||||||
),
|
contentDescription = null,
|
||||||
contentDescription = null,
|
tint = FirefoxTheme.colors.iconPrimary,
|
||||||
tint = FirefoxTheme.colors.iconPrimary,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadLanguageItemStatusPreference.DownloadInProgress -> {
|
ModelState.DOWNLOAD_IN_PROGRESS, ModelState.DELETION_IN_PROGRESS -> {
|
||||||
if (item.state.type != DownloadLanguageItemTypePreference.PivotLanguage) {
|
DownloadIconIndicator(
|
||||||
DownloadIconIndicator(
|
icon = painterResource(id = R.drawable.mozac_ic_sync_24),
|
||||||
icon = painterResource(id = R.drawable.mozac_ic_sync_24),
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadLanguageItemStatusPreference.Selected -> {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -368,6 +494,7 @@ private fun TextListItemInlineDescription(
|
||||||
}
|
}
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { onClick.invoke() },
|
onClick = { onClick.invoke() },
|
||||||
|
enabled = enabled,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(end = 16.dp)
|
.padding(end = 16.dp)
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
|
|
@ -384,82 +511,51 @@ internal fun getLanguageListPreference(): List<DownloadLanguageItemPreference> {
|
||||||
return mutableListOf<DownloadLanguageItemPreference>().apply {
|
return mutableListOf<DownloadLanguageItemPreference>().apply {
|
||||||
add(
|
add(
|
||||||
DownloadLanguageItemPreference(
|
DownloadLanguageItemPreference(
|
||||||
languageModel = TranslationsController.RuntimeTranslation.LanguageModel(
|
languageModel = LanguageModel(
|
||||||
TranslationsController.Language(
|
language = Language(Locale.FRENCH.toLanguageTag(), Locale.FRENCH.displayName),
|
||||||
Locale.FRENCH.toLanguageTag(),
|
status = ModelState.DOWNLOADED,
|
||||||
Locale.FRENCH.displayLanguage,
|
size = 100L,
|
||||||
),
|
|
||||||
false,
|
|
||||||
30000000,
|
|
||||||
),
|
|
||||||
state = DownloadLanguageItemStatePreference(
|
|
||||||
type = DownloadLanguageItemTypePreference.GeneralLanguage,
|
|
||||||
status = DownloadLanguageItemStatusPreference.Downloaded,
|
|
||||||
),
|
),
|
||||||
|
type = DownloadLanguageItemTypePreference.GeneralLanguage,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
add(
|
add(
|
||||||
DownloadLanguageItemPreference(
|
DownloadLanguageItemPreference(
|
||||||
languageModel = TranslationsController.RuntimeTranslation.LanguageModel(
|
languageModel = LanguageModel(
|
||||||
TranslationsController.Language(
|
language = Language(Locale.GERMAN.toLanguageTag(), Locale.GERMAN.displayName),
|
||||||
Locale.GERMAN.toLanguageTag(),
|
status = ModelState.NOT_DOWNLOADED,
|
||||||
Locale.GERMAN.displayLanguage,
|
size = 100L,
|
||||||
),
|
|
||||||
false,
|
|
||||||
30000000,
|
|
||||||
),
|
|
||||||
state = DownloadLanguageItemStatePreference(
|
|
||||||
type = DownloadLanguageItemTypePreference.GeneralLanguage,
|
|
||||||
status = DownloadLanguageItemStatusPreference.NotDownloaded,
|
|
||||||
),
|
),
|
||||||
|
type = DownloadLanguageItemTypePreference.GeneralLanguage,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
add(
|
add(
|
||||||
DownloadLanguageItemPreference(
|
DownloadLanguageItemPreference(
|
||||||
languageModel = TranslationsController.RuntimeTranslation.LanguageModel(
|
languageModel = LanguageModel(
|
||||||
TranslationsController.Language(
|
language = Language(Locale.ITALIAN.toLanguageTag(), Locale.ITALIAN.displayName),
|
||||||
Locale.ITALIAN.toLanguageTag(),
|
status = ModelState.DOWNLOAD_IN_PROGRESS,
|
||||||
Locale.ITALIAN.displayLanguage,
|
size = 100L,
|
||||||
),
|
|
||||||
false,
|
|
||||||
30000000,
|
|
||||||
),
|
|
||||||
state = DownloadLanguageItemStatePreference(
|
|
||||||
type = DownloadLanguageItemTypePreference.GeneralLanguage,
|
|
||||||
status = DownloadLanguageItemStatusPreference.DownloadInProgress,
|
|
||||||
),
|
),
|
||||||
|
type = DownloadLanguageItemTypePreference.GeneralLanguage,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
add(
|
add(
|
||||||
DownloadLanguageItemPreference(
|
DownloadLanguageItemPreference(
|
||||||
languageModel = TranslationsController.RuntimeTranslation.LanguageModel(
|
languageModel = LanguageModel(
|
||||||
TranslationsController.Language(
|
language = Language(Locale.ENGLISH.toLanguageTag(), Locale.ENGLISH.displayName),
|
||||||
Locale.ENGLISH.toLanguageTag(),
|
status = ModelState.DELETION_IN_PROGRESS,
|
||||||
Locale.ENGLISH.displayLanguage,
|
size = 100L,
|
||||||
),
|
|
||||||
true,
|
|
||||||
30000000,
|
|
||||||
),
|
|
||||||
state = DownloadLanguageItemStatePreference(
|
|
||||||
type = DownloadLanguageItemTypePreference.PivotLanguage,
|
|
||||||
status = DownloadLanguageItemStatusPreference.Selected,
|
|
||||||
),
|
),
|
||||||
|
type = DownloadLanguageItemTypePreference.GeneralLanguage,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
add(
|
add(
|
||||||
DownloadLanguageItemPreference(
|
DownloadLanguageItemPreference(
|
||||||
languageModel = TranslationsController.RuntimeTranslation.LanguageModel(
|
languageModel = LanguageModel(
|
||||||
TranslationsController.Language(
|
status = ModelState.NOT_DOWNLOADED,
|
||||||
stringResource(id = R.string.download_language_all_languages_item_preference),
|
size = 100L,
|
||||||
stringResource(id = R.string.download_language_all_languages_item_preference),
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
90000000,
|
|
||||||
),
|
|
||||||
state = DownloadLanguageItemStatePreference(
|
|
||||||
type = DownloadLanguageItemTypePreference.AllLanguages,
|
|
||||||
status = DownloadLanguageItemStatusPreference.NotDownloaded,
|
|
||||||
),
|
),
|
||||||
|
type = DownloadLanguageItemTypePreference.AllLanguages,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -471,6 +567,8 @@ private fun DownloadLanguagesPreferencePreview() {
|
||||||
FirefoxTheme {
|
FirefoxTheme {
|
||||||
DownloadLanguagesPreference(
|
DownloadLanguagesPreference(
|
||||||
downloadLanguageItemPreferences = getLanguageListPreference(),
|
downloadLanguageItemPreferences = getLanguageListPreference(),
|
||||||
|
learnMoreUrl = "https://www.mozilla.org",
|
||||||
|
onLearnMoreClicked = {},
|
||||||
onItemClick = {},
|
onItemClick = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,30 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
|
import mozilla.components.browser.state.action.TranslationsAction
|
||||||
|
import mozilla.components.browser.state.store.BrowserStore
|
||||||
|
import mozilla.components.concept.engine.translate.LanguageModel
|
||||||
|
import mozilla.components.concept.engine.translate.ModelManagementOptions
|
||||||
|
import mozilla.components.concept.engine.translate.ModelOperation
|
||||||
|
import mozilla.components.concept.engine.translate.ModelState
|
||||||
|
import mozilla.components.concept.engine.translate.OperationLevel
|
||||||
|
import mozilla.components.lib.state.ext.observeAsComposableState
|
||||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||||
|
import mozilla.components.support.locale.LocaleManager
|
||||||
|
import org.mozilla.fenix.BrowserDirection
|
||||||
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.ext.showToolbar
|
import org.mozilla.fenix.ext.showToolbar
|
||||||
|
import org.mozilla.fenix.settings.SupportUtils
|
||||||
import org.mozilla.fenix.theme.FirefoxTheme
|
import org.mozilla.fenix.theme.FirefoxTheme
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fragment displaying Download Languages screen.
|
* A fragment displaying Download Languages screen.
|
||||||
|
|
@ -25,6 +40,7 @@ class DownloadLanguagesPreferenceFragment : Fragment() {
|
||||||
private val downloadLanguagesFeature =
|
private val downloadLanguagesFeature =
|
||||||
ViewBoundFeatureWrapper<DownloadLanguagesFeature>()
|
ViewBoundFeatureWrapper<DownloadLanguagesFeature>()
|
||||||
private var isDataSaverEnabledAndWifiDisabled = false
|
private var isDataSaverEnabledAndWifiDisabled = false
|
||||||
|
private val browserStore: BrowserStore by lazy { requireComponents.core.store }
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
@ -38,24 +54,48 @@ class DownloadLanguagesPreferenceFragment : Fragment() {
|
||||||
): View = ComposeView(requireContext()).apply {
|
): View = ComposeView(requireContext()).apply {
|
||||||
setContent {
|
setContent {
|
||||||
FirefoxTheme {
|
FirefoxTheme {
|
||||||
|
val learnMoreUrl = SupportUtils.getSumoURLForTopic(
|
||||||
|
requireContext(),
|
||||||
|
SupportUtils.SumoTopic.TRANSLATIONS,
|
||||||
|
)
|
||||||
|
val downloadLanguageItemsPreference = getDownloadLanguageItemsPreference()
|
||||||
|
|
||||||
DownloadLanguagesPreference(
|
DownloadLanguagesPreference(
|
||||||
downloadLanguageItemPreferences = getLanguageListPreference(),
|
downloadLanguageItemPreferences = downloadLanguageItemsPreference,
|
||||||
|
learnMoreUrl = learnMoreUrl,
|
||||||
|
onLearnMoreClicked = { openBrowserAndLoad(learnMoreUrl) },
|
||||||
onItemClick = { downloadLanguageItemPreference ->
|
onItemClick = { downloadLanguageItemPreference ->
|
||||||
if (downloadLanguageItemPreference.state.status ==
|
if (downloadLanguageItemPreference.languageModel.status ==
|
||||||
DownloadLanguageItemStatusPreference.Downloaded ||
|
ModelState.DOWNLOADED ||
|
||||||
shouldShowPrefDownloadLanguageFileDialog(
|
shouldShowPrefDownloadLanguageFileDialog(
|
||||||
downloadLanguageItemPreference,
|
downloadLanguageItemPreference,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
downloadLanguageItemPreference.languageModel.language?.localizedDisplayName?.let {
|
var size = 0L
|
||||||
findNavController().navigate(
|
downloadLanguageItemPreference.languageModel.size?.let { size = it }
|
||||||
DownloadLanguagesPreferenceFragmentDirections
|
|
||||||
.actionDownloadLanguagesPreferenceToDownloadLanguagesDialogPreference(
|
findNavController().navigate(
|
||||||
downloadLanguageItemPreference.state,
|
DownloadLanguagesPreferenceFragmentDirections
|
||||||
it,
|
.actionDownloadLanguagesPreferenceToDownloadLanguagesDialogPreference(
|
||||||
downloadLanguageItemPreference.languageModel.size,
|
modelState = downloadLanguageItemPreference.languageModel.status,
|
||||||
),
|
itemType = downloadLanguageItemPreference.type,
|
||||||
|
languageCode = downloadLanguageItemPreference.languageModel.language?.code,
|
||||||
|
languageDisplayName =
|
||||||
|
downloadLanguageItemPreference.languageModel.language?.localizedDisplayName,
|
||||||
|
modelSize = size,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
downloadLanguageItemPreference.type ==
|
||||||
|
DownloadLanguageItemTypePreference.AllLanguages
|
||||||
|
) {
|
||||||
|
deleteOrDownloadAllLanguagesModel(
|
||||||
|
allLanguagesItemPreference = downloadLanguageItemPreference,
|
||||||
|
allLanguages = downloadLanguageItemsPreference,
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
deleteOrDownloadModel(downloadLanguageItemPreference)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -64,15 +104,6 @@ class DownloadLanguagesPreferenceFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldShowPrefDownloadLanguageFileDialog(
|
|
||||||
downloadLanguageItemPreference: DownloadLanguageItemPreference,
|
|
||||||
) =
|
|
||||||
(
|
|
||||||
downloadLanguageItemPreference.state.status == DownloadLanguageItemStatusPreference.NotDownloaded &&
|
|
||||||
isDataSaverEnabledAndWifiDisabled &&
|
|
||||||
!requireContext().settings().ignoreTranslationsDataSaverWarning
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
downloadLanguagesFeature.set(
|
downloadLanguagesFeature.set(
|
||||||
|
|
@ -87,4 +118,175 @@ class DownloadLanguagesPreferenceFragment : Fragment() {
|
||||||
view = view,
|
view = view,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun deleteOrDownloadModel(downloadLanguageItemPreference: DownloadLanguageItemPreference) {
|
||||||
|
val options = ModelManagementOptions(
|
||||||
|
languageToManage = downloadLanguageItemPreference.languageModel.language?.code,
|
||||||
|
operation = if (
|
||||||
|
downloadLanguageItemPreference.languageModel.status ==
|
||||||
|
ModelState.NOT_DOWNLOADED
|
||||||
|
) {
|
||||||
|
ModelOperation.DOWNLOAD
|
||||||
|
} else {
|
||||||
|
ModelOperation.DELETE
|
||||||
|
},
|
||||||
|
operationLevel = OperationLevel.LANGUAGE,
|
||||||
|
)
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.ManageLanguageModelsAction(
|
||||||
|
options = options,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteOrDownloadAllLanguagesModel(
|
||||||
|
allLanguagesItemPreference: DownloadLanguageItemPreference,
|
||||||
|
allLanguages: List<DownloadLanguageItemPreference>,
|
||||||
|
) {
|
||||||
|
if (allLanguagesItemPreference.languageModel.status == ModelState.DOWNLOADED) {
|
||||||
|
val downloadedItems = allLanguages.filter {
|
||||||
|
it.languageModel.status == ModelState.DOWNLOADED &&
|
||||||
|
it.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
||||||
|
}
|
||||||
|
|
||||||
|
for (downloadedItem in downloadedItems) {
|
||||||
|
if (!downloadedItem.languageModel.language?.code.equals(Locale.ENGLISH.language)) {
|
||||||
|
deleteOrDownloadModel(downloadedItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (allLanguagesItemPreference.languageModel.status == ModelState.NOT_DOWNLOADED) {
|
||||||
|
val notDownloadedItems = allLanguages.filter {
|
||||||
|
it.languageModel.status == ModelState.NOT_DOWNLOADED &&
|
||||||
|
it.type == DownloadLanguageItemTypePreference.GeneralLanguage
|
||||||
|
}
|
||||||
|
for (notDownloadedItem in notDownloadedItems) {
|
||||||
|
deleteOrDownloadModel(notDownloadedItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openBrowserAndLoad(learnMoreUrl: String) {
|
||||||
|
(requireActivity() as HomeActivity).openToBrowserAndLoad(
|
||||||
|
searchTermOrURL = learnMoreUrl,
|
||||||
|
newTab = true,
|
||||||
|
from = BrowserDirection.FromDownloadLanguagesPreferenceFragment,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun getDownloadLanguageItemsPreference(): List<DownloadLanguageItemPreference> {
|
||||||
|
val languageModels = browserStore.observeAsComposableState { state ->
|
||||||
|
state.translationEngine.languageModels
|
||||||
|
}.value?.toMutableList()
|
||||||
|
val languageItemPreferenceList = mutableListOf<DownloadLanguageItemPreference>()
|
||||||
|
val appLocale = browserStore.state.locale ?: LocaleManager.getSystemDefault()
|
||||||
|
|
||||||
|
languageModels?.let {
|
||||||
|
var allLanguagesSizeNotDownloaded = 0L
|
||||||
|
var allLanguagesSizeDownloaded = 0L
|
||||||
|
|
||||||
|
for (languageModel in languageModels) {
|
||||||
|
var size = 0L
|
||||||
|
languageModel.size?.let { size = it }
|
||||||
|
|
||||||
|
if (languageModel.status == ModelState.NOT_DOWNLOADED) {
|
||||||
|
allLanguagesSizeNotDownloaded += size
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
languageModel.status == ModelState.DOWNLOADED &&
|
||||||
|
!languageModel.language?.code.equals(
|
||||||
|
Locale.ENGLISH.language,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
allLanguagesSizeDownloaded += size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addAllLanguagesNotDownloaded(
|
||||||
|
allLanguagesSizeNotDownloaded,
|
||||||
|
languageItemPreferenceList,
|
||||||
|
)
|
||||||
|
|
||||||
|
addAllLanguagesDownloaded(
|
||||||
|
allLanguagesSizeDownloaded,
|
||||||
|
languageItemPreferenceList,
|
||||||
|
)
|
||||||
|
|
||||||
|
val iterator = languageModels.iterator()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val languageModel = iterator.next()
|
||||||
|
if (!appLocale.language.equals(Locale.ENGLISH.language) && languageModel.language?.code.equals(
|
||||||
|
Locale.ENGLISH.language,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
languageItemPreferenceList.add(
|
||||||
|
DownloadLanguageItemPreference(
|
||||||
|
languageModel = languageModel,
|
||||||
|
type = DownloadLanguageItemTypePreference.PivotLanguage,
|
||||||
|
enabled = allLanguagesSizeDownloaded == 0L,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!languageModel.language?.code.equals(Locale.ENGLISH.language)) {
|
||||||
|
languageItemPreferenceList.add(
|
||||||
|
DownloadLanguageItemPreference(
|
||||||
|
languageModel = languageModel,
|
||||||
|
type = DownloadLanguageItemTypePreference.GeneralLanguage,
|
||||||
|
enabled = languageModel.status == ModelState.DOWNLOADED ||
|
||||||
|
languageModel.status == ModelState.NOT_DOWNLOADED,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return languageItemPreferenceList
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addAllLanguagesNotDownloaded(
|
||||||
|
allLanguageSizeNotDownloaded: Long,
|
||||||
|
languageItemPreferenceList: MutableList<DownloadLanguageItemPreference>,
|
||||||
|
) {
|
||||||
|
if (allLanguageSizeNotDownloaded != 0L) {
|
||||||
|
languageItemPreferenceList.add(
|
||||||
|
DownloadLanguageItemPreference(
|
||||||
|
languageModel = LanguageModel(
|
||||||
|
status = ModelState.NOT_DOWNLOADED,
|
||||||
|
size = allLanguageSizeNotDownloaded,
|
||||||
|
),
|
||||||
|
type = DownloadLanguageItemTypePreference.AllLanguages,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addAllLanguagesDownloaded(
|
||||||
|
allLanguagesSizeDownloaded: Long,
|
||||||
|
languageItemPreferenceList: MutableList<DownloadLanguageItemPreference>,
|
||||||
|
) {
|
||||||
|
if (allLanguagesSizeDownloaded != 0L) {
|
||||||
|
languageItemPreferenceList.add(
|
||||||
|
DownloadLanguageItemPreference(
|
||||||
|
languageModel = LanguageModel(
|
||||||
|
status = ModelState.DOWNLOADED,
|
||||||
|
size = allLanguagesSizeDownloaded,
|
||||||
|
),
|
||||||
|
type = DownloadLanguageItemTypePreference.AllLanguages,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldShowPrefDownloadLanguageFileDialog(
|
||||||
|
downloadLanguageItemPreference: DownloadLanguageItemPreference,
|
||||||
|
) =
|
||||||
|
(
|
||||||
|
downloadLanguageItemPreference.languageModel.status == ModelState.NOT_DOWNLOADED &&
|
||||||
|
isDataSaverEnabledAndWifiDisabled &&
|
||||||
|
!requireContext().settings().ignoreTranslationsDataSaverWarning
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,24 @@ import androidx.compose.ui.platform.ComposeView
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import mozilla.components.browser.state.action.TranslationsAction
|
||||||
|
import mozilla.components.browser.state.store.BrowserStore
|
||||||
|
import mozilla.components.concept.engine.translate.ModelManagementOptions
|
||||||
|
import mozilla.components.concept.engine.translate.ModelOperation
|
||||||
|
import mozilla.components.concept.engine.translate.ModelState
|
||||||
|
import mozilla.components.concept.engine.translate.OperationLevel
|
||||||
|
import mozilla.components.lib.state.ext.observeAsComposableState
|
||||||
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.theme.FirefoxTheme
|
import org.mozilla.fenix.theme.FirefoxTheme
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fragment dialog displays a delete or download language.
|
* A fragment dialog displays a delete or download language.
|
||||||
*/
|
*/
|
||||||
class LanguageDialogPreferenceFragment : DialogFragment() {
|
class LanguageDialogPreferenceFragment : DialogFragment() {
|
||||||
private val args by navArgs<LanguageDialogPreferenceFragmentArgs>()
|
private val args by navArgs<LanguageDialogPreferenceFragmentArgs>()
|
||||||
|
private val browserStore: BrowserStore by lazy { requireComponents.core.store }
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
|
||||||
super.onCreateDialog(savedInstanceState).apply {
|
super.onCreateDialog(savedInstanceState).apply {
|
||||||
|
|
@ -39,10 +49,10 @@ class LanguageDialogPreferenceFragment : DialogFragment() {
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
): View {
|
): View {
|
||||||
val view = ComposeView(requireContext())
|
val view = ComposeView(requireContext())
|
||||||
if (args.downloadLanguageItemStatePreference.status == DownloadLanguageItemStatusPreference.Downloaded) {
|
if (args.modelState == ModelState.DOWNLOADED) {
|
||||||
setPrefDeleteLanguageFileDialog(view)
|
setPrefDeleteLanguageFileDialog(view)
|
||||||
} else {
|
} else {
|
||||||
if (args.downloadLanguageItemStatePreference.status == DownloadLanguageItemStatusPreference.NotDownloaded) {
|
if (args.modelState == ModelState.NOT_DOWNLOADED) {
|
||||||
setDownloadLanguageFileDialog(view)
|
setDownloadLanguageFileDialog(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -54,13 +64,43 @@ class LanguageDialogPreferenceFragment : DialogFragment() {
|
||||||
composeView.apply {
|
composeView.apply {
|
||||||
setContent {
|
setContent {
|
||||||
FirefoxTheme {
|
FirefoxTheme {
|
||||||
|
val languageModels = browserStore.observeAsComposableState { state ->
|
||||||
|
state.translationEngine.languageModels
|
||||||
|
}.value?.toMutableList()
|
||||||
|
|
||||||
DeleteLanguageFileDialog(
|
DeleteLanguageFileDialog(
|
||||||
language = args.languageNamePreference,
|
language = args.languageDisplayName,
|
||||||
isAllLanguagesItemType =
|
isAllLanguagesItemType =
|
||||||
args.downloadLanguageItemStatePreference.type ==
|
args.itemType ==
|
||||||
DownloadLanguageItemTypePreference.AllLanguages,
|
DownloadLanguageItemTypePreference.AllLanguages,
|
||||||
fileSize = args.itemFileSizePreference,
|
fileSize = args.modelSize,
|
||||||
onConfirmDelete = { findNavController().popBackStack() },
|
onConfirmDelete = {
|
||||||
|
if (args.itemType == DownloadLanguageItemTypePreference.AllLanguages) {
|
||||||
|
languageModels?.let {
|
||||||
|
val downloadedItems = it.filter { languageModel ->
|
||||||
|
languageModel.status == ModelState.DOWNLOADED
|
||||||
|
}
|
||||||
|
|
||||||
|
for (downloadedItem in downloadedItems) {
|
||||||
|
if (!downloadedItem.language?.code.equals(
|
||||||
|
Locale.ENGLISH.language,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
deleteOrDownloadModel(
|
||||||
|
modelOperation = ModelOperation.DELETE,
|
||||||
|
languageToManage = downloadedItem.language?.code,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deleteOrDownloadModel(
|
||||||
|
modelOperation = ModelOperation.DELETE,
|
||||||
|
languageToManage = args.languageCode,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
findNavController().popBackStack()
|
||||||
|
},
|
||||||
onCancel = { findNavController().popBackStack() },
|
onCancel = { findNavController().popBackStack() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -73,20 +113,44 @@ class LanguageDialogPreferenceFragment : DialogFragment() {
|
||||||
setContent {
|
setContent {
|
||||||
FirefoxTheme {
|
FirefoxTheme {
|
||||||
var checkBoxEnabled by remember { mutableStateOf(false) }
|
var checkBoxEnabled by remember { mutableStateOf(false) }
|
||||||
|
val languageModels = browserStore.observeAsComposableState { state ->
|
||||||
|
state.translationEngine.languageModels
|
||||||
|
}.value?.toMutableList()
|
||||||
|
|
||||||
DownloadLanguageFileDialog(
|
DownloadLanguageFileDialog(
|
||||||
downloadLanguageDialogType = if (args.downloadLanguageItemStatePreference.type ==
|
downloadLanguageDialogType = if (args.itemType ==
|
||||||
DownloadLanguageItemTypePreference.AllLanguages
|
DownloadLanguageItemTypePreference.AllLanguages
|
||||||
) {
|
) {
|
||||||
DownloadLanguageFileDialogType.AllLanguages
|
DownloadLanguageFileDialogType.AllLanguages
|
||||||
} else {
|
} else {
|
||||||
DownloadLanguageFileDialogType.Default
|
DownloadLanguageFileDialogType.Default
|
||||||
},
|
},
|
||||||
fileSize = args.itemFileSizePreference,
|
fileSize = args.modelSize,
|
||||||
isCheckBoxEnabled = checkBoxEnabled,
|
isCheckBoxEnabled = checkBoxEnabled,
|
||||||
onSavingModeStateChange = { checkBoxEnabled = it },
|
onSavingModeStateChange = { checkBoxEnabled = it },
|
||||||
onConfirmDownload = {
|
onConfirmDownload = {
|
||||||
requireContext().settings().ignoreTranslationsDataSaverWarning =
|
requireContext().settings().ignoreTranslationsDataSaverWarning =
|
||||||
checkBoxEnabled
|
checkBoxEnabled
|
||||||
|
|
||||||
|
if (args.itemType == DownloadLanguageItemTypePreference.AllLanguages) {
|
||||||
|
languageModels?.let {
|
||||||
|
val downloadedItems = it.filter { languageModel ->
|
||||||
|
languageModel.status == ModelState.NOT_DOWNLOADED
|
||||||
|
}
|
||||||
|
for (downloadedItem in downloadedItems) {
|
||||||
|
deleteOrDownloadModel(
|
||||||
|
modelOperation = ModelOperation.DOWNLOAD,
|
||||||
|
languageToManage = downloadedItem.language?.code,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deleteOrDownloadModel(
|
||||||
|
modelOperation = ModelOperation.DOWNLOAD,
|
||||||
|
languageToManage = args.languageCode,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
findNavController().popBackStack()
|
findNavController().popBackStack()
|
||||||
},
|
},
|
||||||
onCancel = { findNavController().popBackStack() },
|
onCancel = { findNavController().popBackStack() },
|
||||||
|
|
@ -95,4 +159,17 @@ class LanguageDialogPreferenceFragment : DialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun deleteOrDownloadModel(modelOperation: ModelOperation, languageToManage: String?) {
|
||||||
|
val options = ModelManagementOptions(
|
||||||
|
languageToManage = languageToManage,
|
||||||
|
operation = modelOperation,
|
||||||
|
operationLevel = OperationLevel.LANGUAGE,
|
||||||
|
)
|
||||||
|
browserStore.dispatch(
|
||||||
|
TranslationsAction.ManageLanguageModelsAction(
|
||||||
|
options = options,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1519,16 +1519,22 @@
|
||||||
android:id="@+id/downloadLanguagesDialogPreferenceFragment"
|
android:id="@+id/downloadLanguagesDialogPreferenceFragment"
|
||||||
android:name="org.mozilla.fenix.translations.preferences.downloadlanguages.LanguageDialogPreferenceFragment">
|
android:name="org.mozilla.fenix.translations.preferences.downloadlanguages.LanguageDialogPreferenceFragment">
|
||||||
<argument
|
<argument
|
||||||
android:name="downloadLanguageItemStatePreference"
|
android:name="modelState"
|
||||||
app:argType="org.mozilla.fenix.translations.preferences.downloadlanguages.DownloadLanguageItemStatePreference" />
|
app:argType="mozilla.components.concept.engine.translate.ModelState" />
|
||||||
<argument
|
<argument
|
||||||
android:name="languageNamePreference"
|
android:name="itemType"
|
||||||
app:argType="string"
|
app:argType="org.mozilla.fenix.translations.preferences.downloadlanguages.DownloadLanguageItemTypePreference" />
|
||||||
app:nullable="false" />
|
|
||||||
<argument
|
<argument
|
||||||
android:name="itemFileSizePreference"
|
android:name="languageCode"
|
||||||
app:argType="long"
|
app:nullable="true"
|
||||||
app:nullable="false" />
|
app:argType="string" />
|
||||||
|
<argument
|
||||||
|
android:name="languageDisplayName"
|
||||||
|
app:nullable="true"
|
||||||
|
app:argType="string" />
|
||||||
|
<argument
|
||||||
|
android:name="modelSize"
|
||||||
|
app:argType="long" />
|
||||||
</dialog>
|
</dialog>
|
||||||
</navigation>
|
</navigation>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2515,8 +2515,10 @@
|
||||||
<string name="download_languages_language_item_preference">%1$s (%2$s)</string>
|
<string name="download_languages_language_item_preference">%1$s (%2$s)</string>
|
||||||
<!-- The subhead of the download language preference screen will appear above the items that were not downloaded. -->
|
<!-- The subhead of the download language preference screen will appear above the items that were not downloaded. -->
|
||||||
<string name="download_language_header_preference">Download Languages</string>
|
<string name="download_language_header_preference">Download Languages</string>
|
||||||
<!-- All languages list item. When the user presses this item, they can download or delete all languages. -->
|
<!-- All languages list item. When the user presses this item, they can download all languages. -->
|
||||||
<string name="download_language_all_languages_item_preference">All languages</string>
|
<string name="download_language_all_languages_item_preference">All languages</string>
|
||||||
|
<!-- All languages list item. When the user presses this item, they can delete all languages that were downloaded. -->
|
||||||
|
<string name="download_language_all_languages_item_preference_to_delete">Delete all languages</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.): For a language list item that was downloaded, the user can now delete it. -->
|
<!-- Content description (not visible, for screen readers etc.): For a language list item that was downloaded, the user can now delete it. -->
|
||||||
<string name="download_languages_item_content_description_downloaded_state">Delete</string>
|
<string name="download_languages_item_content_description_downloaded_state">Delete</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.): For a language list item, downloading is in progress. -->
|
<!-- Content description (not visible, for screen readers etc.): For a language list item, downloading is in progress. -->
|
||||||
|
|
@ -2524,7 +2526,7 @@
|
||||||
<!-- Content description (not visible, for screen readers etc.): For a language list item that was not downloaded. -->
|
<!-- Content description (not visible, for screen readers etc.): For a language list item that was not downloaded. -->
|
||||||
<string name="download_languages_item_content_description_not_downloaded_state">Download</string>
|
<string name="download_languages_item_content_description_not_downloaded_state">Download</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.): For a language list item that is selected. -->
|
<!-- Content description (not visible, for screen readers etc.): For a language list item that is selected. -->
|
||||||
<string name="download_languages_item_content_description_selected_state">Selected</string>
|
<string name="download_languages_item_content_description_selected_state" moz:removedIn="127" tools:ignore="UnusedResources">Selected</string>
|
||||||
|
|
||||||
<!-- Title for the dialog used by the translations feature to confirm deleting a language.
|
<!-- Title for the dialog used by the translations feature to confirm deleting a language.
|
||||||
The dialog will be presented when the user requests deletion of a language.
|
The dialog will be presented when the user requests deletion of a language.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue