From 3f0cd812a533038547fb83b3bc2f6115d0e83893 Mon Sep 17 00:00:00 2001 From: Acclorite <2ma0bhpk@anonaddy.com> Date: Mon, 4 Aug 2025 13:16:29 +0300 Subject: [PATCH] refactor: language model --- .../book_story/core/data/CoreData.kt | 40 +++++++++---------- .../book_story/core/language/Language.kt | 32 +++++++++++++++ .../book_story/core/language/LanguageUtils.kt | 29 ++++++++++++++ .../book_story/core/model/Language.kt | 24 ----------- .../book_story/core/model/LanguageCode.kt | 22 ---------- .../data/settings/SettingsManager.kt | 33 ++++++++------- .../book_story/data/settings/model/Setting.kt | 7 +++- .../settings/UpdateLanguageUseCase.kt | 4 +- .../presentation/settings/SettingsEvent.kt | 2 +- .../book_story/ui/start/StartContent.kt | 2 +- .../book_story/ui/start/StartSettings.kt | 2 +- .../ui/start/StartSettingsLayoutGeneral.kt | 4 +- 12 files changed, 112 insertions(+), 89 deletions(-) create mode 100644 app/src/main/java/ua/acclorite/book_story/core/language/Language.kt create mode 100644 app/src/main/java/ua/acclorite/book_story/core/language/LanguageUtils.kt delete mode 100644 app/src/main/java/ua/acclorite/book_story/core/model/Language.kt delete mode 100644 app/src/main/java/ua/acclorite/book_story/core/model/LanguageCode.kt 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 dc252d81..86ab4a53 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 @@ -7,28 +7,28 @@ package ua.acclorite.book_story.core.data import kotlinx.collections.immutable.toPersistentList -import ua.acclorite.book_story.core.model.Language +import ua.acclorite.book_story.core.language.Language object CoreData { - val defaultLanguage = Language.fromCode(code = "en") + val defaultLanguage = Language.fromLanguageTag(languageTag = "en") // English 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"), + Language.fromLanguageTag(languageTag = "en"), // English + Language.fromLanguageTag(languageTag = "uk"), // Ukrainian + Language.fromLanguageTag(languageTag = "de"), // German + Language.fromLanguageTag(languageTag = "ar"), // Arabic + Language.fromLanguageTag(languageTag = "es"), // Spanish + Language.fromLanguageTag(languageTag = "tr"), // Turkish + Language.fromLanguageTag(languageTag = "fr"), // French + Language.fromLanguageTag(languageTag = "pl"), // Polish + Language.fromLanguageTag(languageTag = "it"), // Italian + Language.fromLanguageTag(languageTag = "zh-CN"), // Chinese (China) + Language.fromLanguageTag(languageTag = "hi"), // Hindi + Language.fromLanguageTag(languageTag = "pt-BR"), // Portuguese (Brazil) + Language.fromLanguageTag(languageTag = "ta"), // Tamil + Language.fromLanguageTag(languageTag = "ml"), // Malayalam + Language.fromLanguageTag(languageTag = "cs"), // Czech + Language.fromLanguageTag(languageTag = "ro"), // Romanian + Language.fromLanguageTag(languageTag = "be"), // Belarusian + Language.fromLanguageTag(languageTag = "ja"), // Japanese ).sortedBy { it.displayName }.toPersistentList() } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/core/language/Language.kt b/app/src/main/java/ua/acclorite/book_story/core/language/Language.kt new file mode 100644 index 00000000..ea2a7fc8 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/core/language/Language.kt @@ -0,0 +1,32 @@ +/* + * 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.language + +import androidx.compose.runtime.Immutable +import java.util.Locale + +@Immutable +data class Language( + val locale: Locale, + val displayName: String +) { + companion object { + fun getDisplayName(locale: Locale): String { + return locale + .getDisplayName(locale) + .replaceFirstChar { it.uppercaseChar() } + } + + fun fromLanguageTag(languageTag: String): Language { + val locale = Locale.forLanguageTag(languageTag) + return Language( + locale = locale, + displayName = getDisplayName(locale) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/core/language/LanguageUtils.kt b/app/src/main/java/ua/acclorite/book_story/core/language/LanguageUtils.kt new file mode 100644 index 00000000..8558a493 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/core/language/LanguageUtils.kt @@ -0,0 +1,29 @@ +/* + * 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.language + +import java.util.Locale + +object LanguageUtils { + fun findLanguage( + languages: List, + locale: Locale, + defaultLanguage: Language + ): Language { + // Searching for exact locale match + languages.find { language -> + language.locale == locale + }?.let { return it } + + // Searching for localLe language match + languages.find { language -> + language.locale.language == locale.language + }?.let { return it } + + return defaultLanguage + } +} \ 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 deleted file mode 100644 index 4d58ce23..00000000 --- a/app/src/main/java/ua/acclorite/book_story/core/model/Language.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 deleted file mode 100644 index af40b2c0..00000000 --- a/app/src/main/java/ua/acclorite/book_story/core/model/LanguageCode.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 4a725de0..27f9b474 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 @@ -20,8 +20,9 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import ua.acclorite.book_story.core.data.CoreData +import ua.acclorite.book_story.core.language.Language +import ua.acclorite.book_story.core.language.LanguageUtils 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 @@ -63,19 +64,23 @@ class SettingsManager @Inject constructor( /* ------ Settings --------------------------- */ /* ------ General ---------------------------- */ - 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 language = setting( + key = stringPreferencesKey("language"), + default = LanguageUtils.findLanguage( + languages = CoreData.languages, + locale = Locale.getDefault(), + defaultLanguage = CoreData.defaultLanguage + ), + serialize = { it.locale.toLanguageTag() }, + deserialize = { languageTag -> + val locale = Locale.forLanguageTag(languageTag) + LanguageUtils.findLanguage( + languages = CoreData.languages, + locale = locale, + defaultLanguage = 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/data/settings/model/Setting.kt b/app/src/main/java/ua/acclorite/book_story/data/settings/model/Setting.kt index e5c8a9fb..4f66643f 100644 --- a/app/src/main/java/ua/acclorite/book_story/data/settings/model/Setting.kt +++ b/app/src/main/java/ua/acclorite/book_story/data/settings/model/Setting.kt @@ -16,7 +16,7 @@ import kotlinx.coroutines.flow.update @Stable class Setting( val key: Preferences.Key

, - default: T, + private val default: T, private val setSetting: (P) -> Unit, private val serialize: (T) -> P, private val deserialize: (P) -> T @@ -33,7 +33,10 @@ class Setting( } fun init(value: P?) { - if (value == null) return + if (value == null) { + setSetting(serialize(default)) + return + } _value.update { deserialize(value) } } } \ No newline at end of file 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 1b1e3024..d53794b9 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,7 +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.core.language.Language import ua.acclorite.book_story.data.settings.SettingsManager import javax.inject.Inject @@ -17,7 +17,7 @@ class UpdateLanguageUseCase @Inject constructor( ) { operator fun invoke(language: Language) { - val appLocale = LocaleListCompat.forLanguageTags(language.languageCode.code) + val appLocale = LocaleListCompat.forLanguageTags(language.locale.toLanguageTag()) 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 eb8961ba..ac1ed9f4 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,7 +11,7 @@ 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.core.language.Language import ua.acclorite.book_story.domain.model.library.Category import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder 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 3ef85d99..c986b939 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,7 +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.core.language.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 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 aefc814c..5f3df21f 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,7 +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.core.language.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 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 00e8abac..5cfb32d1 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,7 +17,7 @@ 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.core.language.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 @@ -35,7 +35,7 @@ fun LazyListScope.StartSettingsLayoutGeneral( Spacer(modifier = Modifier.height(12.dp)) } - items(languages, key = { it.item }) { item -> + items(languages) { item -> SelectableDialogItem( selected = item.selected, title = item.title,