diff --git a/app/src/main/java/ua/acclorite/book_story/core/data/CoreData.kt b/app/src/main/java/ua/acclorite/book_story/core/data/CoreData.kt index d2d28808..dc252d81 100644 --- a/app/src/main/java/ua/acclorite/book_story/core/data/CoreData.kt +++ b/app/src/main/java/ua/acclorite/book_story/core/data/CoreData.kt @@ -6,28 +6,29 @@ package ua.acclorite.book_story.core.data -import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList +import ua.acclorite.book_story.core.model.Language object CoreData { - val languages = persistentListOf( - Pair("en", "English"), - Pair("uk", "Українська"), - Pair("de", "Deutsch"), - Pair("ar", "اَلْعَرَبِيَّةُ"), - Pair("es", "Español"), - Pair("tr", "Türkçe"), - Pair("fr", "Français"), - Pair("pl", "Polski"), - Pair("it", "Italiano"), - Pair("zh", "汉语"), - Pair("hi", "हिन्दी"), - // Currently as "pt" (which is Portuguese) instead of "pt-BR" - Pair("pt", "Português (Brasil)"), - Pair("ta", "தமிழ்"), - Pair("ml", "മലയാളം"), - Pair("cs", "Čeština"), - Pair("ro", "Română"), - Pair("be", "Беларуская"), - Pair("ja", "日本語") - ) + val defaultLanguage = Language.fromCode(code = "en") + val languages = listOf( + Language.fromCode(code = "en"), + Language.fromCode(code = "uk"), + Language.fromCode(code = "de"), + Language.fromCode(code = "ar"), + Language.fromCode(code = "es"), + Language.fromCode(code = "tr"), + Language.fromCode(code = "fr"), + Language.fromCode(code = "pl"), + Language.fromCode(code = "it"), + Language.fromCode(code = "zh"), + Language.fromCode(code = "hi"), + Language.fromCode(code = "pt", displayName = "pt-BR"), + Language.fromCode(code = "ta"), + Language.fromCode(code = "ml"), + Language.fromCode(code = "cs"), + Language.fromCode(code = "ro"), + Language.fromCode(code = "be"), + Language.fromCode(code = "ja"), + ).sortedBy { it.displayName }.toPersistentList() } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/core/model/Language.kt b/app/src/main/java/ua/acclorite/book_story/core/model/Language.kt new file mode 100644 index 00000000..4d58ce23 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/core/model/Language.kt @@ -0,0 +1,24 @@ +/* + * Book's Story — free and open-source Material You eBook reader. + * Copyright (C) 2024-2025 Acclorite + * SPDX-License-Identifier: GPL-3.0-only + */ + +package ua.acclorite.book_story.core.model + +import androidx.compose.runtime.Immutable + +@Immutable +data class Language( + val languageCode: LanguageCode, + val displayName: String +) { + companion object { + fun fromCode(code: String, displayName: String = code): Language { + return Language( + languageCode = LanguageCode(code = code), + displayName = LanguageCode.getDisplayName(code = displayName) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/core/model/LanguageCode.kt b/app/src/main/java/ua/acclorite/book_story/core/model/LanguageCode.kt new file mode 100644 index 00000000..af40b2c0 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/core/model/LanguageCode.kt @@ -0,0 +1,22 @@ +/* + * Book's Story — free and open-source Material You eBook reader. + * Copyright (C) 2024-2025 Acclorite + * SPDX-License-Identifier: GPL-3.0-only + */ + +package ua.acclorite.book_story.core.model + +import androidx.compose.runtime.Immutable +import java.util.Locale + +@Immutable +@JvmInline +value class LanguageCode(val code: String) { + companion object { + fun getDisplayName(code: String): String { + val target = Locale.forLanguageTag(code) + val displayName = target.getDisplayName(target) + return displayName.replaceFirstChar { it.uppercaseChar() } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/data/settings/SettingsManager.kt b/app/src/main/java/ua/acclorite/book_story/data/settings/SettingsManager.kt index 53180202..4a725de0 100644 --- a/app/src/main/java/ua/acclorite/book_story/data/settings/SettingsManager.kt +++ b/app/src/main/java/ua/acclorite/book_story/data/settings/SettingsManager.kt @@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import ua.acclorite.book_story.core.data.CoreData import ua.acclorite.book_story.core.log.logI +import ua.acclorite.book_story.core.model.Language import ua.acclorite.book_story.data.local.data_store.DataStore import ua.acclorite.book_story.data.settings.model.Setting import ua.acclorite.book_story.presentation.browse.model.BrowseLayout @@ -62,15 +63,19 @@ class SettingsManager @Inject constructor( /* ------ Settings --------------------------- */ /* ------ General ---------------------------- */ - val language = setting( - key = stringPreferencesKey("language"), - default = Locale.getDefault().language.take(2).let { locale -> - CoreData.languages.any { locale == it.first }.run { - if (this) locale - else "en"// Default language (English) + val language = + setting( + key = stringPreferencesKey("language"), + default = Locale.getDefault().language.take(2).let { defaultLocale -> + CoreData.languages.find { locale -> locale.languageCode.code == defaultLocale } + ?: CoreData.defaultLanguage + }, + serialize = { it.languageCode.code }, + deserialize = { code -> + CoreData.languages.find { locale -> locale.languageCode.code == code } + ?: CoreData.defaultLanguage } - } - ) + ) val theme = setting( key = stringPreferencesKey("theme"), default = Theme.Companion.entries().first(), serialize = { it.name }, deserialize = { Theme.valueOf(it) } diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/settings/UpdateLanguageUseCase.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/settings/UpdateLanguageUseCase.kt index d41d5677..1b1e3024 100644 --- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/settings/UpdateLanguageUseCase.kt +++ b/app/src/main/java/ua/acclorite/book_story/domain/use_case/settings/UpdateLanguageUseCase.kt @@ -8,6 +8,7 @@ package ua.acclorite.book_story.domain.use_case.settings import androidx.appcompat.app.AppCompatDelegate import androidx.core.os.LocaleListCompat +import ua.acclorite.book_story.core.model.Language import ua.acclorite.book_story.data.settings.SettingsManager import javax.inject.Inject @@ -15,8 +16,8 @@ class UpdateLanguageUseCase @Inject constructor( private val settings: SettingsManager ) { - operator fun invoke(language: String) { - val appLocale = LocaleListCompat.forLanguageTags(language) + operator fun invoke(language: Language) { + val appLocale = LocaleListCompat.forLanguageTags(language.languageCode.code) AppCompatDelegate.setApplicationLocales(appLocale) settings.language.update(language) } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/settings/SettingsEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/settings/SettingsEvent.kt index 698d845f..eb8961ba 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/settings/SettingsEvent.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/settings/SettingsEvent.kt @@ -11,13 +11,14 @@ import android.net.Uri import androidx.compose.runtime.Immutable import androidx.compose.ui.graphics.Color import ua.acclorite.book_story.core.ID +import ua.acclorite.book_story.core.model.Language import ua.acclorite.book_story.domain.model.library.Category import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder @Immutable sealed class SettingsEvent { data class OnUpdateLanguage( - val language: String + val language: Language ) : SettingsEvent() data class OnGrantPersistableUriPermission( diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/start/StartScreen.kt b/app/src/main/java/ua/acclorite/book_story/presentation/start/StartScreen.kt index d77bf9da..47f1aa6e 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/start/StartScreen.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/start/StartScreen.kt @@ -58,13 +58,13 @@ object StartScreen : Screen, Parcelable { val stackEvent = remember { mutableStateOf(StackEvent.DEFAULT) } val languages = remember(settings.language.value) { - CoreData.languages.sortedBy { it.second }.map { + CoreData.languages.map { item -> ListItem( - item = it.first, - title = it.second, - selected = it.first == settings.language.lastValue + item = item, + title = item.displayName, + selected = item == settings.language.lastValue ) - }.sortedBy { it.title } + } } StartContent( diff --git a/app/src/main/java/ua/acclorite/book_story/ui/settings/general/components/AppLanguageOption.kt b/app/src/main/java/ua/acclorite/book_story/ui/settings/general/components/AppLanguageOption.kt index abf1aa8f..0233562b 100644 --- a/app/src/main/java/ua/acclorite/book_story/ui/settings/general/components/AppLanguageOption.kt +++ b/app/src/main/java/ua/acclorite/book_story/ui/settings/general/components/AppLanguageOption.kt @@ -24,11 +24,11 @@ fun AppLanguageOption() { ChipsWithTitle( title = stringResource(id = R.string.language_option), - chips = CoreData.languages.sortedBy { it.second }.map { item -> + chips = CoreData.languages.map { item -> ListItem( - item = item.first, - title = item.second, - selected = item.first == settings.language.value + item = item, + title = item.displayName, + selected = item == settings.language.value ) }, onClick = { item -> diff --git a/app/src/main/java/ua/acclorite/book_story/ui/start/StartContent.kt b/app/src/main/java/ua/acclorite/book_story/ui/start/StartContent.kt index d1868401..3ef85d99 100644 --- a/app/src/main/java/ua/acclorite/book_story/ui/start/StartContent.kt +++ b/app/src/main/java/ua/acclorite/book_story/ui/start/StartContent.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.background import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import ua.acclorite.book_story.core.model.Language import ua.acclorite.book_story.presentation.navigator.StackEvent import ua.acclorite.book_story.presentation.start.StartScreen import ua.acclorite.book_story.ui.common.model.ListItem @@ -18,8 +19,8 @@ import ua.acclorite.book_story.ui.common.model.ListItem fun StartContent( currentPage: Int, stackEvent: StackEvent, - languages: List>, - updateLanguage: (String) -> Unit, + languages: List>, + updateLanguage: (Language) -> Unit, navigateForward: () -> Unit, navigateBack: () -> Unit, navigateToBrowse: () -> Unit, diff --git a/app/src/main/java/ua/acclorite/book_story/ui/start/StartSettings.kt b/app/src/main/java/ua/acclorite/book_story/ui/start/StartSettings.kt index 90e34479..aefc814c 100644 --- a/app/src/main/java/ua/acclorite/book_story/ui/start/StartSettings.kt +++ b/app/src/main/java/ua/acclorite/book_story/ui/start/StartSettings.kt @@ -7,6 +7,7 @@ package ua.acclorite.book_story.ui.start import androidx.compose.runtime.Composable +import ua.acclorite.book_story.core.model.Language import ua.acclorite.book_story.presentation.navigator.StackEvent import ua.acclorite.book_story.presentation.start.StartScreen import ua.acclorite.book_story.ui.common.model.ListItem @@ -15,8 +16,8 @@ import ua.acclorite.book_story.ui.common.model.ListItem fun StartSettings( currentPage: Int, stackEvent: StackEvent, - languages: List>, - updateLanguage: (String) -> Unit, + languages: List>, + updateLanguage: (Language) -> Unit, navigateForward: () -> Unit ) { StartSettingsScaffold( diff --git a/app/src/main/java/ua/acclorite/book_story/ui/start/StartSettingsLayoutGeneral.kt b/app/src/main/java/ua/acclorite/book_story/ui/start/StartSettingsLayoutGeneral.kt index 99a5b514..00e8abac 100644 --- a/app/src/main/java/ua/acclorite/book_story/ui/start/StartSettingsLayoutGeneral.kt +++ b/app/src/main/java/ua/acclorite/book_story/ui/start/StartSettingsLayoutGeneral.kt @@ -17,13 +17,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import ua.acclorite.book_story.R +import ua.acclorite.book_story.core.model.Language import ua.acclorite.book_story.ui.common.components.dialog.SelectableDialogItem import ua.acclorite.book_story.ui.common.model.ListItem import ua.acclorite.book_story.ui.settings.components.SettingsSubcategoryTitle fun LazyListScope.StartSettingsLayoutGeneral( - languages: List>, - updateLanguage: (String) -> Unit, + languages: List>, + updateLanguage: (Language) -> Unit, ) { item { Spacer(modifier = Modifier.height(16.dp)) @@ -34,13 +35,13 @@ fun LazyListScope.StartSettingsLayoutGeneral( Spacer(modifier = Modifier.height(12.dp)) } - items(languages, key = { it.item }) { + items(languages, key = { it.item }) { item -> SelectableDialogItem( - selected = it.selected, - title = it.title, + selected = item.selected, + title = item.title, horizontalPadding = 18.dp ) { - updateLanguage(it.item) + updateLanguage(item.item) } }