refactor: create language model

This commit is contained in:
Acclorite 2025-07-26 21:49:38 +03:00
parent 0fa8041d5c
commit 96c3917169
No known key found for this signature in database
GPG key ID: 6E54C611F6EE8593
11 changed files with 109 additions and 52 deletions

View file

@ -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()
}

View file

@ -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)
)
}
}
}

View file

@ -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() }
}
}
}

View file

@ -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<String, String>(
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<Language, String>(
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<Theme, String>(
key = stringPreferencesKey("theme"), default = Theme.Companion.entries().first(),
serialize = { it.name }, deserialize = { Theme.valueOf(it) }

View file

@ -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)
}

View file

@ -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(

View file

@ -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(

View file

@ -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 ->

View file

@ -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<ListItem<String>>,
updateLanguage: (String) -> Unit,
languages: List<ListItem<Language>>,
updateLanguage: (Language) -> Unit,
navigateForward: () -> Unit,
navigateBack: () -> Unit,
navigateToBrowse: () -> Unit,

View file

@ -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<ListItem<String>>,
updateLanguage: (String) -> Unit,
languages: List<ListItem<Language>>,
updateLanguage: (Language) -> Unit,
navigateForward: () -> Unit
) {
StartSettingsScaffold(

View file

@ -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<ListItem<String>>,
updateLanguage: (String) -> Unit,
languages: List<ListItem<Language>>,
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)
}
}