From ae99a7c2c2fd942819f8ae31a8a6b3cfe58b9094 Mon Sep 17 00:00:00 2001 From: Diego Beraldin Date: Thu, 27 Jul 2023 23:22:25 +0200 Subject: [PATCH] feat(settings): implement language change --- .../racconforlemmy/core_utils/Extensions.kt | 1 - .../modals/ListingTypeBottomSheet.kt | 7 ++- .../feature_home/modals/SortBottomSheet.kt | 7 ++- .../feature_home/ui/HomeTab.kt | 13 ++-- .../raccoonforlemmy/feature_inbox/InboxTab.kt | 15 +++-- .../feature_profile/ProfileTab.kt | 15 +++-- .../feature_search/SearchTab.kt | 15 +++-- .../feature_settings/di/SettingsModule.kt | 10 ++- .../modals/LanguageBottomSheet.kt | 63 +++++++++++++++++++ .../modals/ThemeBottomSheet.kt | 7 ++- .../feature_settings/ui/SettingsContent.kt | 41 ++++++------ .../feature_settings/ui/SettingsRow.kt | 38 +++++++++++ .../feature_settings/ui/SettingsTab.kt | 36 ++++++++--- .../viewmodel/SettingsScreenModel.kt | 19 +++++- .../viewmodel/SettingsScreenMviModel.kt | 2 + .../resources/LocalizationModule.kt | 14 ----- .../resources/di/LocalizationModule.kt | 30 +++++++++ .../resources/LocalizationModule.kt | 7 --- .../resources/di/LocalizationModule.kt | 11 ++++ .../commonMain/resources/MR/base/strings.xml | 1 + .../commonMain/resources/MR/it/strings.xml | 28 ++++++++- .../resources/{ => di}/LocalizationModule.kt | 9 ++- .../diegoberaldin/raccoonforlemmy/DiHelper.kt | 2 +- .../diegoberaldin/raccoonforlemmy/App.kt | 41 ++++++------ .../diegoberaldin/raccoonforlemmy/DiHelper.kt | 2 +- 25 files changed, 328 insertions(+), 106 deletions(-) create mode 100644 feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/modals/LanguageBottomSheet.kt create mode 100644 feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsRow.kt delete mode 100644 resources/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt create mode 100644 resources/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt delete mode 100644 resources/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt create mode 100644 resources/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt rename resources/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/{ => di}/LocalizationModule.kt (56%) diff --git a/core-utils/src/commonMain/kotlin/com/github/diegoberaldin/racconforlemmy/core_utils/Extensions.kt b/core-utils/src/commonMain/kotlin/com/github/diegoberaldin/racconforlemmy/core_utils/Extensions.kt index 96c339a08..ca88cfb73 100644 --- a/core-utils/src/commonMain/kotlin/com/github/diegoberaldin/racconforlemmy/core_utils/Extensions.kt +++ b/core-utils/src/commonMain/kotlin/com/github/diegoberaldin/racconforlemmy/core_utils/Extensions.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.composed -import org.koin.core.parameter.parametersOf fun Modifier.onClick(onClick: () -> Unit): Modifier = composed { clickable(indication = null, diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/modals/ListingTypeBottomSheet.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/modals/ListingTypeBottomSheet.kt index 415661f40..04d03c276 100644 --- a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/modals/ListingTypeBottomSheet.kt +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/modals/ListingTypeBottomSheet.kt @@ -30,7 +30,12 @@ fun ListingTypeBottomSheet( Column( modifier = Modifier .background(MaterialTheme.colorScheme.background) - .padding(Spacing.s), + .padding( + top = Spacing.s, + start = Spacing.s, + end = Spacing.s, + bottom = Spacing.m, + ), verticalArrangement = Arrangement.spacedBy(Spacing.s) ) { Text( diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/modals/SortBottomSheet.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/modals/SortBottomSheet.kt index 20527ce6b..5e3e2f281 100644 --- a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/modals/SortBottomSheet.kt +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/modals/SortBottomSheet.kt @@ -30,7 +30,12 @@ fun SortBottomSheet( Column( modifier = Modifier .background(MaterialTheme.colorScheme.background) - .padding(Spacing.s), + .padding( + top = Spacing.s, + start = Spacing.s, + end = Spacing.s, + bottom = Spacing.m, + ), verticalArrangement = Arrangement.spacedBy(Spacing.s) ) { Text( diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/ui/HomeTab.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/ui/HomeTab.kt index f304e3756..be7ded2ac 100644 --- a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/ui/HomeTab.kt +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_home/ui/HomeTab.kt @@ -31,12 +31,14 @@ import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.TabOptions import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core_architecture.bindToLifecycle -import com.github.diegoberaldin.raccoonforlemmy.feature_home.viewmodel.HomeScreenMviModel import com.github.diegoberaldin.raccoonforlemmy.feature_home.di.getHomeScreenModel import com.github.diegoberaldin.raccoonforlemmy.feature_home.modals.ListingTypeBottomSheet import com.github.diegoberaldin.raccoonforlemmy.feature_home.modals.SortBottomSheet +import com.github.diegoberaldin.raccoonforlemmy.feature_home.viewmodel.HomeScreenMviModel import com.github.diegoberaldin.raccoonforlemmy.resources.MR -import dev.icerock.moko.resources.compose.stringResource +import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString +import dev.icerock.moko.resources.desc.desc import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow @@ -48,10 +50,11 @@ object HomeTab : Tab { override val options: TabOptions @Composable get() { - val title = stringResource(MR.strings.navigation_home) val icon = rememberVectorPainter(Icons.Default.SpaceDashboard) - - return remember { + val languageRepository = remember { getLanguageRepository() } + val lang by languageRepository.currentLanguage.collectAsState() + return remember(lang) { + val title = staticString(MR.strings.navigation_home.desc()) TabOptions( index = 0u, title = title, diff --git a/feature-inbox/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_inbox/InboxTab.kt b/feature-inbox/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_inbox/InboxTab.kt index 698c26f59..663a75b0b 100644 --- a/feature-inbox/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_inbox/InboxTab.kt +++ b/feature-inbox/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_inbox/InboxTab.kt @@ -6,6 +6,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Inbox import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.rememberVectorPainter @@ -15,19 +17,22 @@ import cafe.adriel.voyager.navigator.tab.TabOptions import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core_architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.resources.MR -import dev.icerock.moko.resources.compose.stringResource +import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString +import dev.icerock.moko.resources.desc.desc object InboxTab : Tab { override val options: TabOptions @Composable get() { - val title = stringResource(MR.strings.navigation_inbox) val icon = rememberVectorPainter(Icons.Default.Inbox) - - return remember { + val languageRepository = remember { getLanguageRepository() } + val lang by languageRepository.currentLanguage.collectAsState() + return remember(lang) { + val title = staticString(MR.strings.navigation_inbox.desc()) TabOptions( - index = 1u, + index = 0u, title = title, icon = icon ) diff --git a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_profile/ProfileTab.kt b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_profile/ProfileTab.kt index 7221e3eaa..44f49897c 100644 --- a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_profile/ProfileTab.kt +++ b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_profile/ProfileTab.kt @@ -6,6 +6,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Person import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.rememberVectorPainter @@ -15,19 +17,22 @@ import cafe.adriel.voyager.navigator.tab.TabOptions import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core_architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.resources.MR -import dev.icerock.moko.resources.compose.stringResource +import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString +import dev.icerock.moko.resources.desc.desc object ProfileTab : Tab { override val options: TabOptions @Composable get() { - val title = stringResource(MR.strings.navigation_profile) val icon = rememberVectorPainter(Icons.Default.Person) - - return remember { + val languageRepository = remember { getLanguageRepository() } + val lang by languageRepository.currentLanguage.collectAsState() + return remember(lang) { + val title = staticString(MR.strings.navigation_profile.desc()) TabOptions( - index = 2u, + index = 0u, title = title, icon = icon ) diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_search/SearchTab.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_search/SearchTab.kt index 3115bcb1f..de5b9cf4d 100644 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_search/SearchTab.kt +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_search/SearchTab.kt @@ -6,6 +6,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Explore import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.rememberVectorPainter @@ -15,19 +17,22 @@ import cafe.adriel.voyager.navigator.tab.TabOptions import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core_architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.resources.MR -import dev.icerock.moko.resources.compose.stringResource +import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString +import dev.icerock.moko.resources.desc.desc object SearchTab : Tab { override val options: TabOptions @Composable get() { - val title = stringResource(MR.strings.navigation_search) val icon = rememberVectorPainter(Icons.Default.Explore) - - return remember { + val languageRepository = remember { getLanguageRepository() } + val lang by languageRepository.currentLanguage.collectAsState() + return remember(lang) { + val title = staticString(MR.strings.navigation_search.desc()) TabOptions( - index = 3u, + index = 1u, title = title, icon = icon ) diff --git a/feature-settings/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/di/SettingsModule.kt b/feature-settings/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/di/SettingsModule.kt index a294362a4..2edfe02d0 100644 --- a/feature-settings/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/di/SettingsModule.kt +++ b/feature-settings/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/di/SettingsModule.kt @@ -1,22 +1,20 @@ package com.github.diegoberaldin.raccoonforlemmy.feature_settings.di -import com.github.diegoberaldin.raccoonforlemmy.core_appearance.repository.ThemeRepository import com.github.diegoberaldin.raccoonforlemmy.core_architecture.DefaultMviModel -import com.github.diegoberaldin.raccoonforlemmy.core_preferences.TemporaryKeyStore import com.github.diegoberaldin.raccoonforlemmy.feature_settings.viewmodel.SettingsScreenModel import com.github.diegoberaldin.raccoonforlemmy.feature_settings.viewmodel.SettingsScreenMviModel import org.koin.dsl.module -import org.koin.java.KoinJavaComponent.get import org.koin.java.KoinJavaComponent.inject actual val settingsTabModule = module { factory { SettingsScreenModel( - themeRepository = get(ThemeRepository::class.java), - keyStore = get(TemporaryKeyStore::class.java), mvi = DefaultMviModel( SettingsScreenMviModel.UiState() - ) + ), + keyStore = get(), + themeRepository = get(), + languageRepository = get() ) } } diff --git a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/modals/LanguageBottomSheet.kt b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/modals/LanguageBottomSheet.kt new file mode 100644 index 000000000..97aeea6b0 --- /dev/null +++ b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/modals/LanguageBottomSheet.kt @@ -0,0 +1,63 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature_settings.modals + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.github.diegoberaldin.racconforlemmy.core_utils.onClick +import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing +import com.github.diegoberaldin.raccoonforlemmy.feature_settings.ui.toLanguageName +import com.github.diegoberaldin.raccoonforlemmy.resources.MR +import dev.icerock.moko.resources.compose.stringResource + +@Composable +fun LanguageBottomSheet( + onDismiss: (String) -> Unit, +) { + Column( + modifier = Modifier + .background(MaterialTheme.colorScheme.background) + .padding( + top = Spacing.s, + start = Spacing.s, + end = Spacing.s, + bottom = Spacing.m, + ), + verticalArrangement = Arrangement.spacedBy(Spacing.s) + ) { + Text( + modifier = Modifier.padding(start = Spacing.s, top = Spacing.s), + text = stringResource(MR.strings.settings_language), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onBackground, + ) + val values = listOf( + "en", + "it", + ) + Column( + modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(Spacing.xxxs) + ) { + for (value in values) { + Row(modifier = Modifier.padding(Spacing.s).onClick { + onDismiss(value) + }) { + Text( + text = value.toLanguageName(), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onBackground, + ) + } + } + } + } +} \ No newline at end of file diff --git a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/modals/ThemeBottomSheet.kt b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/modals/ThemeBottomSheet.kt index 319d9805f..d3277851a 100644 --- a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/modals/ThemeBottomSheet.kt +++ b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/modals/ThemeBottomSheet.kt @@ -30,7 +30,12 @@ fun ThemeBottomSheet( Column( modifier = Modifier .background(MaterialTheme.colorScheme.background) - .padding(Spacing.s), + .padding( + top = Spacing.s, + start = Spacing.s, + end = Spacing.s, + bottom = Spacing.m, + ), verticalArrangement = Arrangement.spacedBy(Spacing.s) ) { Text( diff --git a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsContent.kt b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsContent.kt index 197f91f50..2af2c7e61 100644 --- a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsContent.kt +++ b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsContent.kt @@ -2,19 +2,14 @@ package com.github.diegoberaldin.raccoonforlemmy.feature_settings.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.DarkMode import androidx.compose.material.icons.filled.LightMode import androidx.compose.material.icons.outlined.DarkMode -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import com.github.diegoberaldin.racconforlemmy.core_utils.onClick import com.github.diegoberaldin.raccoonforlemmy.core_appearance.data.ThemeState import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.feature_settings.viewmodel.SettingsScreenMviModel @@ -25,28 +20,38 @@ import dev.icerock.moko.resources.compose.stringResource internal fun SettingsContent( uiState: SettingsScreenMviModel.UiState, onSelectTheme: () -> Unit, + onSelectLanguage: () -> Unit, ) { Column( modifier = Modifier.fillMaxSize().padding(horizontal = Spacing.m), verticalArrangement = Arrangement.spacedBy(Spacing.xs) ) { - Row( - modifier = Modifier.onClick { + // theme + SettingsRow( + title = stringResource(MR.strings.settings_ui_theme), + value = uiState.currentTheme.toReadableName(), + onTap = { onSelectTheme() - }, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = stringResource(MR.strings.settings_ui_theme) - ) - Spacer(modifier = Modifier.weight(1f)) - Text( - text = uiState.currentTheme.toReadableName() - ) - } + } + ) + + // language + SettingsRow( + title = stringResource(MR.strings.settings_language), + value = uiState.lang.toLanguageName(), + onTap = { + onSelectLanguage() + } + ) } } +@Composable +internal fun String.toLanguageName() = when (this) { + "it" -> stringResource(MR.strings.language_it) + else -> stringResource(MR.strings.language_en) +} + @Composable internal fun ThemeState.toReadableName() = when (this) { ThemeState.Black -> stringResource(MR.strings.settings_theme_black) diff --git a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsRow.kt b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsRow.kt new file mode 100644 index 000000000..f0c6bf32e --- /dev/null +++ b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsRow.kt @@ -0,0 +1,38 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature_settings.ui + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.github.diegoberaldin.racconforlemmy.core_utils.onClick +import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing + +@Composable +internal fun SettingsRow( + title: String, + value: String, + onTap: () -> Unit, +) { + Row( + modifier = Modifier + .padding(vertical = Spacing.s) + .onClick { + onTap() + }, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = title, + style = MaterialTheme.typography.bodyMedium, + ) + Spacer(modifier = Modifier.weight(1f)) + Text( + text = value, + style = MaterialTheme.typography.bodyMedium, + ) + } +} \ No newline at end of file diff --git a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsTab.kt b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsTab.kt index 8a8fd4ea5..33b874db6 100644 --- a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsTab.kt +++ b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/ui/SettingsTab.kt @@ -12,6 +12,7 @@ import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.rememberVectorPainter @@ -21,10 +22,13 @@ import cafe.adriel.voyager.navigator.tab.TabOptions import com.github.diegoberaldin.raccoonforlemmy.core_appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core_architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.feature_settings.di.getSettingsScreenModel +import com.github.diegoberaldin.raccoonforlemmy.feature_settings.modals.LanguageBottomSheet import com.github.diegoberaldin.raccoonforlemmy.feature_settings.modals.ThemeBottomSheet import com.github.diegoberaldin.raccoonforlemmy.feature_settings.viewmodel.SettingsScreenMviModel import com.github.diegoberaldin.raccoonforlemmy.resources.MR -import dev.icerock.moko.resources.compose.stringResource +import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString +import dev.icerock.moko.resources.desc.desc import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow @@ -34,12 +38,12 @@ object SettingsTab : Tab { val bottomSheetFlow = bottomSheetChannel.receiveAsFlow() override val options: TabOptions - @Composable - get() { - val title = stringResource(MR.strings.navigation_settings) + @Composable get() { val icon = rememberVectorPainter(Icons.Default.Settings) - - return remember { + val languageRepository = remember { getLanguageRepository() } + val lang by languageRepository.currentLanguage.collectAsState() + return remember(lang) { + val title = staticString(MR.strings.navigation_settings.desc()) TabOptions( index = 4u, title = title, @@ -59,9 +63,14 @@ object SettingsTab : Tab { Scaffold( modifier = Modifier.padding(Spacing.xxs), topBar = { - TopAppBar({ + val languageRepository = remember { getLanguageRepository() } + val lang by languageRepository.currentLanguage.collectAsState() + val title by remember(lang) { + mutableStateOf(staticString(MR.strings.navigation_settings.desc())) + } + TopAppBar(title = { Text( - text = stringResource(MR.strings.navigation_settings), + text = title, style = MaterialTheme.typography.titleMedium ) }) @@ -79,8 +88,15 @@ object SettingsTab : Tab { bottomSheetChannel.trySend(null) } } - } - ) + }, + onSelectLanguage = { + bottomSheetChannel.trySend { + LanguageBottomSheet { newValue -> + model.reduce(SettingsScreenMviModel.Intent.ChangeLanguage(newValue)) + bottomSheetChannel.trySend(null) + } + } + }) } } } diff --git a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/viewmodel/SettingsScreenModel.kt b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/viewmodel/SettingsScreenModel.kt index ffb3efa44..5a735d291 100644 --- a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/viewmodel/SettingsScreenModel.kt +++ b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/viewmodel/SettingsScreenModel.kt @@ -8,12 +8,14 @@ import com.github.diegoberaldin.raccoonforlemmy.core_architecture.DefaultMviMode import com.github.diegoberaldin.raccoonforlemmy.core_architecture.MviModel import com.github.diegoberaldin.raccoonforlemmy.core_preferences.KeyStoreKeys import com.github.diegoberaldin.raccoonforlemmy.core_preferences.TemporaryKeyStore +import com.github.diegoberaldin.raccoonforlemmy.resources.LanguageRepository import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch class SettingsScreenModel( private val themeRepository: ThemeRepository, + private val languageRepository: LanguageRepository, private val keyStore: TemporaryKeyStore, private val mvi: DefaultMviModel, ) : ScreenModel, @@ -22,13 +24,21 @@ class SettingsScreenModel( override fun onStarted() { mvi.onStarted() themeRepository.state.onEach { currentTheme -> - mvi.updateState { it.copy(currentTheme = currentTheme) } + mvi.updateState { + it.copy(currentTheme = currentTheme) + } + }.launchIn(mvi.scope) + languageRepository.currentLanguage.onEach { lang -> + mvi.updateState { + it.copy(lang = lang) + } }.launchIn(mvi.scope) } override fun reduce(intent: SettingsScreenMviModel.Intent) { when (intent) { is SettingsScreenMviModel.Intent.ChangeTheme -> applyTheme(intent.value) + is SettingsScreenMviModel.Intent.ChangeLanguage -> changeLanguage(intent.value) } } @@ -38,4 +48,11 @@ class SettingsScreenModel( keyStore.save(KeyStoreKeys.UITheme, value.toInt()) } } + + private fun changeLanguage(value: String) { + languageRepository.changeLanguage(value) + mvi.scope.launch { + keyStore.save(KeyStoreKeys.Locale, value) + } + } } \ No newline at end of file diff --git a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/viewmodel/SettingsScreenMviModel.kt b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/viewmodel/SettingsScreenMviModel.kt index a784d178f..90b0598e0 100644 --- a/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/viewmodel/SettingsScreenMviModel.kt +++ b/feature-settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature_settings/viewmodel/SettingsScreenMviModel.kt @@ -8,10 +8,12 @@ interface SettingsScreenMviModel : sealed interface Intent { data class ChangeTheme(val value: ThemeState) : Intent + data class ChangeLanguage(val value: String) : Intent } data class UiState( val currentTheme: ThemeState = ThemeState.Light, + val lang: String = "", ) sealed interface Effect diff --git a/resources/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt b/resources/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt deleted file mode 100644 index 378b9451a..000000000 --- a/resources/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.github.diegoberaldin.raccoonforlemmy.resources - -import org.koin.core.module.dsl.singleOf -import org.koin.dsl.module -import org.koin.java.KoinJavaComponent.inject - -actual val localizationModule = module { - singleOf(::DefaultLanguageRepository) -} - -actual fun getLanguageRepository(): LanguageRepository { - val res: LanguageRepository by inject(LanguageRepository::class.java) - return res -} diff --git a/resources/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt b/resources/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt new file mode 100644 index 000000000..3324fb845 --- /dev/null +++ b/resources/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt @@ -0,0 +1,30 @@ +package com.github.diegoberaldin.raccoonforlemmy.resources.di + +import android.content.Context +import com.github.diegoberaldin.raccoonforlemmy.resources.DefaultLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.LanguageRepository +import dev.icerock.moko.resources.desc.StringDesc +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module +import org.koin.java.KoinJavaComponent.inject + +actual val localizationModule = module { + singleOf(::DefaultLanguageRepository) + singleOf(::ResourceStringProvider) +} + +actual fun getLanguageRepository(): LanguageRepository { + val res: LanguageRepository by inject(LanguageRepository::class.java) + return res +} + +private class ResourceStringProvider( + private val context: Context, +) { + fun getString(stringDesc: StringDesc): String = stringDesc.toString(context) +} + +actual fun staticString(stringDesc: StringDesc): String { + val provider by inject(ResourceStringProvider::class.java) + return provider.getString(stringDesc) +} \ No newline at end of file diff --git a/resources/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt b/resources/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt deleted file mode 100644 index 24a8f92ab..000000000 --- a/resources/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.diegoberaldin.raccoonforlemmy.resources - -import org.koin.core.module.Module - -expect val localizationModule: Module - -expect fun getLanguageRepository(): LanguageRepository diff --git a/resources/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt b/resources/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt new file mode 100644 index 000000000..989393dc6 --- /dev/null +++ b/resources/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt @@ -0,0 +1,11 @@ +package com.github.diegoberaldin.raccoonforlemmy.resources.di + +import com.github.diegoberaldin.raccoonforlemmy.resources.LanguageRepository +import dev.icerock.moko.resources.desc.StringDesc +import org.koin.core.module.Module + +expect val localizationModule: Module + +expect fun getLanguageRepository(): LanguageRepository + +expect fun staticString(stringDesc: StringDesc): String diff --git a/resources/src/commonMain/resources/MR/base/strings.xml b/resources/src/commonMain/resources/MR/base/strings.xml index ed32c19c2..24ee9ea7e 100644 --- a/resources/src/commonMain/resources/MR/base/strings.xml +++ b/resources/src/commonMain/resources/MR/base/strings.xml @@ -35,4 +35,5 @@ Dark Light Pure black + Language \ No newline at end of file diff --git a/resources/src/commonMain/resources/MR/it/strings.xml b/resources/src/commonMain/resources/MR/it/strings.xml index e3b7cc31d..7b4f1bdb9 100644 --- a/resources/src/commonMain/resources/MR/it/strings.xml +++ b/resources/src/commonMain/resources/MR/it/strings.xml @@ -3,10 +3,34 @@ it Post - Inbox + In arrivo Profilo Ricerca Impostazioni - Tema scuro + Tutti + Locali + Iscrizioni + Ordinamento + Tipo di feed + Attivi + Popolari + Più commentati + Recenti + Commenti recenti + Top… + Top giorno + Top mese + Top ultime 12h + Top ultime 6h + Top ultima ora + Top settimana + Top anno + via %1$s + + Tema interfaccia + Scuro + Chiaro + Scuro (AMOLED) + Lingua \ No newline at end of file diff --git a/resources/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt b/resources/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt similarity index 56% rename from resources/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt rename to resources/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt index 9c979a713..c83aa59db 100644 --- a/resources/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/LocalizationModule.kt +++ b/resources/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/resources/di/LocalizationModule.kt @@ -1,5 +1,8 @@ -package com.github.diegoberaldin.raccoonforlemmy.resources +package com.github.diegoberaldin.raccoonforlemmy.resources.di +import com.github.diegoberaldin.raccoonforlemmy.resources.DefaultLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.LanguageRepository +import dev.icerock.moko.resources.desc.StringDesc import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.koin.core.module.dsl.singleOf @@ -13,4 +16,6 @@ actual fun getLanguageRepository(): LanguageRepository = LanguageRepositoryHelpe object LanguageRepositoryHelper : KoinComponent { val repository: LanguageRepository by inject() -} \ No newline at end of file +} + +actual fun staticString(stringDesc: StringDesc): String = stringDesc.localized() \ No newline at end of file diff --git a/shared/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt b/shared/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt index bb15f24e2..8b195a836 100644 --- a/shared/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt +++ b/shared/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt @@ -8,7 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.feature_profile.profileTabModule import com.github.diegoberaldin.raccoonforlemmy.feature_search.searchTabModule import com.github.diegoberaldin.raccoonforlemmy.feature_home.di.homeTabModule import com.github.diegoberaldin.raccoonforlemmy.feature_settings.di.settingsTabModule -import com.github.diegoberaldin.raccoonforlemmy.resources.localizationModule +import com.github.diegoberaldin.raccoonforlemmy.resources.di.localizationModule import org.koin.dsl.module val sharedHelperModule = module { diff --git a/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt b/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt index 30dd786b8..d8350d844 100644 --- a/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt +++ b/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt @@ -27,10 +27,11 @@ import com.github.diegoberaldin.raccoonforlemmy.feature_profile.ProfileTab import com.github.diegoberaldin.raccoonforlemmy.feature_search.SearchTab import com.github.diegoberaldin.raccoonforlemmy.feature_settings.ui.SettingsTab import com.github.diegoberaldin.raccoonforlemmy.resources.MR -import com.github.diegoberaldin.raccoonforlemmy.resources.getLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository import com.github.diegoberaldin.raccoonforlemmy.ui.navigation.TabNavigationItem import dev.icerock.moko.resources.compose.stringResource import dev.icerock.moko.resources.desc.StringDesc +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -50,7 +51,10 @@ fun App() { keyStore.get(KeyStoreKeys.Locale, defaultLocale) } val languageRepository = remember { getLanguageRepository() } - languageRepository.changeLanguage(langCode) + LaunchedEffect(Unit) { + delay(100) + languageRepository.changeLanguage(langCode) + } val scope = rememberCoroutineScope() languageRepository.currentLanguage.onEach { lang -> @@ -65,29 +69,26 @@ fun App() { val bottomSheetContent = remember { mutableStateOf<(@Composable () -> Unit)?>(null) } val bottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden) - LaunchedEffect(HomeTab) { - HomeTab.bottomSheetFlow.debounce(250).onEach { content -> - when { - content != null -> { - bottomSheetContent.value = content - bottomSheetState.show() - } - else -> bottomSheetState.hide() + suspend fun handleBottomSheet(content: (@Composable () -> Unit)?) { + when { + content != null -> { + bottomSheetContent.value = content + bottomSheetState.show() } - }.launchIn(this) + + else -> bottomSheetState.hide() + } } + LaunchedEffect(HomeTab) { + HomeTab.bottomSheetFlow.debounce(250).onEach { content -> + handleBottomSheet(content) + }.launchIn(this) + } LaunchedEffect(SettingsTab) { SettingsTab.bottomSheetFlow.debounce(250).onEach { content -> - when { - content != null -> { - bottomSheetContent.value = content - bottomSheetState.show() - } - - else -> bottomSheetState.hide() - } + handleBottomSheet(content) }.launchIn(this) } @@ -104,7 +105,7 @@ fun App() { }, bottomBar = { BottomAppBar { - TabNavigationItem(tab = HomeTab) + TabNavigationItem(HomeTab) TabNavigationItem(SearchTab) TabNavigationItem(ProfileTab) TabNavigationItem(InboxTab) diff --git a/shared/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt b/shared/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt index 61571c02c..75f3b4d7b 100644 --- a/shared/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt +++ b/shared/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt @@ -8,7 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.feature_inbox.inboxTabModule import com.github.diegoberaldin.raccoonforlemmy.feature_profile.profileTabModule import com.github.diegoberaldin.raccoonforlemmy.feature_search.searchTabModule import com.github.diegoberaldin.raccoonforlemmy.feature_settings.di.settingsTabModule -import com.github.diegoberaldin.raccoonforlemmy.resources.localizationModule +import com.github.diegoberaldin.raccoonforlemmy.resources.di.localizationModule import org.koin.core.context.startKoin fun initKoin() {