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 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 { object CoreData {
val languages = persistentListOf( val defaultLanguage = Language.fromCode(code = "en")
Pair("en", "English"), val languages = listOf(
Pair("uk", "Українська"), Language.fromCode(code = "en"),
Pair("de", "Deutsch"), Language.fromCode(code = "uk"),
Pair("ar", "اَلْعَرَبِيَّةُ"), Language.fromCode(code = "de"),
Pair("es", "Español"), Language.fromCode(code = "ar"),
Pair("tr", "Türkçe"), Language.fromCode(code = "es"),
Pair("fr", "Français"), Language.fromCode(code = "tr"),
Pair("pl", "Polski"), Language.fromCode(code = "fr"),
Pair("it", "Italiano"), Language.fromCode(code = "pl"),
Pair("zh", "汉语"), Language.fromCode(code = "it"),
Pair("hi", "हिन्दी"), Language.fromCode(code = "zh"),
// Currently as "pt" (which is Portuguese) instead of "pt-BR" Language.fromCode(code = "hi"),
Pair("pt", "Português (Brasil)"), Language.fromCode(code = "pt", displayName = "pt-BR"),
Pair("ta", "தமிழ்"), Language.fromCode(code = "ta"),
Pair("ml", "മലയാളം"), Language.fromCode(code = "ml"),
Pair("cs", "Čeština"), Language.fromCode(code = "cs"),
Pair("ro", "Română"), Language.fromCode(code = "ro"),
Pair("be", "Беларуская"), Language.fromCode(code = "be"),
Pair("ja", "日本語") 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 kotlinx.coroutines.launch
import ua.acclorite.book_story.core.data.CoreData import ua.acclorite.book_story.core.data.CoreData
import ua.acclorite.book_story.core.log.logI 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.local.data_store.DataStore
import ua.acclorite.book_story.data.settings.model.Setting import ua.acclorite.book_story.data.settings.model.Setting
import ua.acclorite.book_story.presentation.browse.model.BrowseLayout import ua.acclorite.book_story.presentation.browse.model.BrowseLayout
@ -62,13 +63,17 @@ class SettingsManager @Inject constructor(
/* ------ Settings --------------------------- */ /* ------ Settings --------------------------- */
/* ------ General ---------------------------- */ /* ------ General ---------------------------- */
val language = setting<String, String>( val language =
setting<Language, String>(
key = stringPreferencesKey("language"), key = stringPreferencesKey("language"),
default = Locale.getDefault().language.take(2).let { locale -> default = Locale.getDefault().language.take(2).let { defaultLocale ->
CoreData.languages.any { locale == it.first }.run { CoreData.languages.find { locale -> locale.languageCode.code == defaultLocale }
if (this) locale ?: CoreData.defaultLanguage
else "en"// Default language (English) },
} serialize = { it.languageCode.code },
deserialize = { code ->
CoreData.languages.find { locale -> locale.languageCode.code == code }
?: CoreData.defaultLanguage
} }
) )
val theme = setting<Theme, String>( val theme = setting<Theme, String>(

View file

@ -8,6 +8,7 @@ package ua.acclorite.book_story.domain.use_case.settings
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
import ua.acclorite.book_story.core.model.Language
import ua.acclorite.book_story.data.settings.SettingsManager import ua.acclorite.book_story.data.settings.SettingsManager
import javax.inject.Inject import javax.inject.Inject
@ -15,8 +16,8 @@ class UpdateLanguageUseCase @Inject constructor(
private val settings: SettingsManager private val settings: SettingsManager
) { ) {
operator fun invoke(language: String) { operator fun invoke(language: Language) {
val appLocale = LocaleListCompat.forLanguageTags(language) val appLocale = LocaleListCompat.forLanguageTags(language.languageCode.code)
AppCompatDelegate.setApplicationLocales(appLocale) AppCompatDelegate.setApplicationLocales(appLocale)
settings.language.update(language) settings.language.update(language)
} }

View file

@ -11,13 +11,14 @@ import android.net.Uri
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.core.ID 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.domain.model.library.Category
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
@Immutable @Immutable
sealed class SettingsEvent { sealed class SettingsEvent {
data class OnUpdateLanguage( data class OnUpdateLanguage(
val language: String val language: Language
) : SettingsEvent() ) : SettingsEvent()
data class OnGrantPersistableUriPermission( data class OnGrantPersistableUriPermission(

View file

@ -58,13 +58,13 @@ object StartScreen : Screen, Parcelable {
val stackEvent = remember { mutableStateOf(StackEvent.DEFAULT) } val stackEvent = remember { mutableStateOf(StackEvent.DEFAULT) }
val languages = remember(settings.language.value) { val languages = remember(settings.language.value) {
CoreData.languages.sortedBy { it.second }.map { CoreData.languages.map { item ->
ListItem( ListItem(
item = it.first, item = item,
title = it.second, title = item.displayName,
selected = it.first == settings.language.lastValue selected = item == settings.language.lastValue
) )
}.sortedBy { it.title } }
} }
StartContent( StartContent(

View file

@ -24,11 +24,11 @@ fun AppLanguageOption() {
ChipsWithTitle( ChipsWithTitle(
title = stringResource(id = R.string.language_option), title = stringResource(id = R.string.language_option),
chips = CoreData.languages.sortedBy { it.second }.map { item -> chips = CoreData.languages.map { item ->
ListItem( ListItem(
item = item.first, item = item,
title = item.second, title = item.displayName,
selected = item.first == settings.language.value selected = item == settings.language.value
) )
}, },
onClick = { item -> onClick = { item ->

View file

@ -10,6 +10,7 @@ import androidx.compose.foundation.background
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier 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.navigator.StackEvent
import ua.acclorite.book_story.presentation.start.StartScreen import ua.acclorite.book_story.presentation.start.StartScreen
import ua.acclorite.book_story.ui.common.model.ListItem import ua.acclorite.book_story.ui.common.model.ListItem
@ -18,8 +19,8 @@ import ua.acclorite.book_story.ui.common.model.ListItem
fun StartContent( fun StartContent(
currentPage: Int, currentPage: Int,
stackEvent: StackEvent, stackEvent: StackEvent,
languages: List<ListItem<String>>, languages: List<ListItem<Language>>,
updateLanguage: (String) -> Unit, updateLanguage: (Language) -> Unit,
navigateForward: () -> Unit, navigateForward: () -> Unit,
navigateBack: () -> Unit, navigateBack: () -> Unit,
navigateToBrowse: () -> Unit, navigateToBrowse: () -> Unit,

View file

@ -7,6 +7,7 @@
package ua.acclorite.book_story.ui.start package ua.acclorite.book_story.ui.start
import androidx.compose.runtime.Composable 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.navigator.StackEvent
import ua.acclorite.book_story.presentation.start.StartScreen import ua.acclorite.book_story.presentation.start.StartScreen
import ua.acclorite.book_story.ui.common.model.ListItem import ua.acclorite.book_story.ui.common.model.ListItem
@ -15,8 +16,8 @@ import ua.acclorite.book_story.ui.common.model.ListItem
fun StartSettings( fun StartSettings(
currentPage: Int, currentPage: Int,
stackEvent: StackEvent, stackEvent: StackEvent,
languages: List<ListItem<String>>, languages: List<ListItem<Language>>,
updateLanguage: (String) -> Unit, updateLanguage: (Language) -> Unit,
navigateForward: () -> Unit navigateForward: () -> Unit
) { ) {
StartSettingsScaffold( StartSettingsScaffold(

View file

@ -17,13 +17,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R 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.components.dialog.SelectableDialogItem
import ua.acclorite.book_story.ui.common.model.ListItem import ua.acclorite.book_story.ui.common.model.ListItem
import ua.acclorite.book_story.ui.settings.components.SettingsSubcategoryTitle import ua.acclorite.book_story.ui.settings.components.SettingsSubcategoryTitle
fun LazyListScope.StartSettingsLayoutGeneral( fun LazyListScope.StartSettingsLayoutGeneral(
languages: List<ListItem<String>>, languages: List<ListItem<Language>>,
updateLanguage: (String) -> Unit, updateLanguage: (Language) -> Unit,
) { ) {
item { item {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
@ -34,13 +35,13 @@ fun LazyListScope.StartSettingsLayoutGeneral(
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
} }
items(languages, key = { it.item }) { items(languages, key = { it.item }) { item ->
SelectableDialogItem( SelectableDialogItem(
selected = it.selected, selected = item.selected,
title = it.title, title = item.title,
horizontalPadding = 18.dp horizontalPadding = 18.dp
) { ) {
updateLanguage(it.item) updateLanguage(item.item)
} }
} }