diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/MainActivity.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/MainActivity.kt index 177e184ca..e05e1ba08 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/MainActivity.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/MainActivity.kt @@ -21,20 +21,41 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.infomaniak.multiplatform_swisstransfer.common.models.Theme import com.infomaniak.swisstransfer.ui.screen.main.MainScreen +import com.infomaniak.swisstransfer.ui.screen.main.settings.SettingsViewModel import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class MainActivity : ComponentActivity() { + private val settingsViewModel: SettingsViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { - SwissTransferTheme { + val appSettings by settingsViewModel.appSettingsFlow.collectAsStateWithLifecycle(null) + SwissTransferTheme(isDarkTheme = isDarkTheme(getTheme = { appSettings?.theme })) { MainScreen() } } } } + +@Composable +fun isDarkTheme(getTheme: () -> Theme?): Boolean { + val settingsViewModel = hiltViewModel() + val appSettings by settingsViewModel.appSettingsFlow.collectAsStateWithLifecycle(null) + + return getTheme()?.let { + if (it == Theme.SYSTEM) isSystemInDarkTheme() else it== Theme.DARK + } ?: isSystemInDarkTheme() +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/SettingsScreen.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/SettingsScreen.kt index 486377ab5..ee21aa194 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/SettingsScreen.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/SettingsScreen.kt @@ -29,7 +29,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource -import com.infomaniak.multiplatform_swisstransfer.common.interfaces.appSettings.AppSettings import com.infomaniak.multiplatform_swisstransfer.common.models.DownloadLimit import com.infomaniak.multiplatform_swisstransfer.common.models.EmailLanguage import com.infomaniak.multiplatform_swisstransfer.common.models.Theme @@ -47,11 +46,15 @@ import com.infomaniak.swisstransfer.ui.screen.main.settings.components.SettingIt import com.infomaniak.swisstransfer.ui.screen.main.settings.components.SettingTitle import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme +import com.infomaniak.swisstransfer.ui.utils.GetSetCallbacks import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow @Composable fun SettingsScreen( - appSettings: AppSettings, + theme: GetSetCallbacks, + validityPeriod: GetSetCallbacks, + downloadLimit: GetSetCallbacks, + emailLanguage: GetSetCallbacks, onItemClick: (SettingsOptionScreens) -> Unit, getSelectedSetting: () -> SettingsOptionScreens?, ) { @@ -74,7 +77,7 @@ fun SettingsScreen( titleRes = R.string.settingsOptionTheme, isSelected = { selectedSetting == THEME }, icon = AppIcons.PaintbrushPalette, - description = appSettings.theme.getString(), + description = theme.get().getString(), endIcon = CHEVRON, onClick = { onItemClick(THEME) }, ) @@ -93,7 +96,7 @@ fun SettingsScreen( titleRes = R.string.settingsOptionValidityPeriod, isSelected = { selectedSetting == VALIDITY_PERIOD }, icon = AppIcons.ArrowDownFile, - description = appSettings.validityPeriod.getString(), + description = validityPeriod.get().getString(), endIcon = CHEVRON, onClick = { onItemClick(VALIDITY_PERIOD) }, ) @@ -101,7 +104,7 @@ fun SettingsScreen( titleRes = R.string.settingsOptionDownloadLimit, isSelected = { selectedSetting == DOWNLOAD_LIMIT }, icon = AppIcons.Clock, - description = appSettings.downloadLimit.getString(), + description = downloadLimit.get().getString(), endIcon = CHEVRON, onClick = { onItemClick(DOWNLOAD_LIMIT) }, ) @@ -109,7 +112,7 @@ fun SettingsScreen( titleRes = R.string.settingsOptionEmailLanguage, isSelected = { selectedSetting == EMAIL_LANGUAGE }, icon = AppIcons.SpeechBubble, - description = appSettings.emailLanguage.getString(), + description = emailLanguage.get().getString(), endIcon = CHEVRON, onClick = { onItemClick(EMAIL_LANGUAGE) }, ) @@ -182,19 +185,19 @@ enum class SettingsOptionScreens { DISCOVER_INFOMANIAK, SHARE_IDEAS, GIVE_FEEDBACK, } -private class DummyAppSettings( - override var theme: Theme = Theme.SYSTEM, - override var downloadLimit: DownloadLimit = DownloadLimit.TWOHUNDREDFIFTY, - override var emailLanguage: EmailLanguage = EmailLanguage.FRENCH, - override var validityPeriod: ValidityPeriod = ValidityPeriod.THIRTY, -) : AppSettings - @PreviewSmallWindow @Composable private fun SettingsScreenPreview() { SwissTransferTheme { Surface(color = MaterialTheme.colorScheme.background) { - SettingsScreen(appSettings = DummyAppSettings(), onItemClick = {}, getSelectedSetting = { null }) + SettingsScreen( + theme = GetSetCallbacks(get = { Theme.SYSTEM }, set = {}), + validityPeriod = GetSetCallbacks(get = { ValidityPeriod.THIRTY }, set = {}), + downloadLimit = GetSetCallbacks(get = { DownloadLimit.TWOHUNDREDFIFTY }, set = {}), + emailLanguage = GetSetCallbacks(get = { EmailLanguage.ENGLISH }, set = {}), + onItemClick = {}, + getSelectedSetting = { null }, + ) } } } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/SettingsScreenWrapper.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/SettingsScreenWrapper.kt index 235a81b07..395d59c36 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/SettingsScreenWrapper.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/settings/SettingsScreenWrapper.kt @@ -27,47 +27,75 @@ import androidx.compose.material3.adaptive.WindowAdaptiveInfo import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.infomaniak.multiplatform_swisstransfer.common.interfaces.appSettings.AppSettings +import com.infomaniak.multiplatform_swisstransfer.common.models.DownloadLimit +import com.infomaniak.multiplatform_swisstransfer.common.models.EmailLanguage +import com.infomaniak.multiplatform_swisstransfer.common.models.Theme +import com.infomaniak.multiplatform_swisstransfer.common.models.ValidityPeriod import com.infomaniak.swisstransfer.R import com.infomaniak.swisstransfer.ui.components.TwoPaneScaffold import com.infomaniak.swisstransfer.ui.screen.main.settings.SettingsOptionScreens.* import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.* -@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun SettingsScreenWrapper( settingsViewModel: SettingsViewModel = hiltViewModel(), ) { val appSettings by settingsViewModel.appSettingsFlow.collectAsStateWithLifecycle(null) + appSettings?.let { safeAppSettings -> - TwoPaneScaffold( - listPane = { ListPane(this, safeAppSettings) }, - detailPane = { DetailPane(safeAppSettings, settingsViewModel, navigator = this) }, - ) + val theme = GetSetCallbacks(get = { safeAppSettings.theme }, set = { settingsViewModel.setTheme(it) }) + val validityPeriod = + GetSetCallbacks(get = { safeAppSettings.validityPeriod }, set = { settingsViewModel.setValidityPeriod(it) }) + val downloadLimit = + GetSetCallbacks(get = { safeAppSettings.downloadLimit }, set = { settingsViewModel.setDownloadLimit(it) }) + val emailLanguage = + GetSetCallbacks(get = { safeAppSettings.emailLanguage }, set = { settingsViewModel.setEmailLanguage(it) }) + + SettingsScreenWrapper(theme, validityPeriod, downloadLimit, emailLanguage) } } @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable -private fun ListPane(navigator: ThreePaneScaffoldNavigator, appSettings: AppSettings) { +fun SettingsScreenWrapper( + theme: GetSetCallbacks, + validityPeriod: GetSetCallbacks, + downloadLimit: GetSetCallbacks, + emailLanguage: GetSetCallbacks, +) { + TwoPaneScaffold( + listPane = { ListPane(navigator = this, theme, validityPeriod, downloadLimit, emailLanguage) }, + detailPane = { DetailPane(navigator = this, theme, validityPeriod, downloadLimit, emailLanguage) }, + ) +} + +@OptIn(ExperimentalMaterial3AdaptiveApi::class) +@Composable +private fun ListPane( + navigator: ThreePaneScaffoldNavigator, + theme: GetSetCallbacks, + validityPeriod: GetSetCallbacks, + downloadLimit: GetSetCallbacks, + emailLanguage: GetSetCallbacks, +) { val context = LocalContext.current val aboutURL = stringResource(R.string.urlAbout) val userReportURL = stringResource(R.string.urlUserReportAndroid) SettingsScreen( - appSettings, + theme, + validityPeriod, + downloadLimit, + emailLanguage, onItemClick = { item -> when (item) { NOTIFICATIONS -> context.openAppNotificationSettings() @@ -87,9 +115,11 @@ private fun ListPane(navigator: ThreePaneScaffoldNavigator, + theme: GetSetCallbacks, + validityPeriod: GetSetCallbacks, + downloadLimit: GetSetCallbacks, + emailLanguage: GetSetCallbacks, ) { var lastSelectedScreen by rememberSaveable { mutableStateOf(null) } @@ -101,24 +131,24 @@ private fun DetailPane( when (destination) { THEME -> SettingsThemeScreen( - theme = appSettings.theme, + theme = theme.get(), navigateBack = navigateBack, - onThemeUpdate = settingsViewModel::setTheme, + onThemeUpdate = { theme.set(it) }, ) VALIDITY_PERIOD -> SettingsValidityPeriodScreen( - validityPeriod = appSettings.validityPeriod, + validityPeriod = validityPeriod.get(), navigateBack = navigateBack, - onValidityPeriodChange = settingsViewModel::setValidityPeriod, + onValidityPeriodChange = { validityPeriod.set(it) }, ) DOWNLOAD_LIMIT -> SettingsDownloadsLimitScreen( - downloadLimit = appSettings.downloadLimit, + downloadLimit = downloadLimit.get(), navigateBack = navigateBack, - onDownloadLimitChange = settingsViewModel::setDownloadLimit, + onDownloadLimitChange = { downloadLimit.set(it) }, ) EMAIL_LANGUAGE -> SettingsEmailLanguageScreen( - emailLanguage = appSettings.emailLanguage, + emailLanguage = emailLanguage.get(), navigateBack = navigateBack, - onEmailLanguageChange = settingsViewModel::setEmailLanguage, + onEmailLanguageChange = { emailLanguage.set(it) }, ) NOTIFICATIONS, DISCOVER_INFOMANIAK, @@ -142,7 +172,12 @@ private fun NoSelectionEmptyState() { private fun SettingsScreenWrapperPreview() { SwissTransferTheme { Surface(color = MaterialTheme.colorScheme.background) { - SettingsScreenWrapper() + SettingsScreenWrapper( + theme = GetSetCallbacks(get = { Theme.SYSTEM }, set = {}), + validityPeriod = GetSetCallbacks(get = { ValidityPeriod.THIRTY }, set = {}), + downloadLimit = GetSetCallbacks(get = { DownloadLimit.TWOHUNDREDFIFTY }, set = {}), + emailLanguage = GetSetCallbacks(get = { EmailLanguage.ENGLISH }, set = {}), + ) } } } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt index 777b01c6f..a9b995fa4 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt @@ -32,10 +32,10 @@ val LocalWindowAdaptiveInfo = staticCompositionLocalOf { err @Composable fun SwissTransferTheme( - darkTheme: Boolean = isDarkTheme(), + isDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit, ) { - val customColors = if (darkTheme) CustomDarkColorScheme else CustomLightColorScheme + val customColors = if (isDarkTheme) CustomDarkColorScheme else CustomLightColorScheme CompositionLocalProvider( LocalCustomTypography provides Typography, LocalTextStyle provides Typography.bodyRegular, @@ -43,20 +43,13 @@ fun SwissTransferTheme( LocalWindowAdaptiveInfo provides currentWindowAdaptiveInfo(), ) { MaterialTheme( - colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme, + colorScheme = if (isDarkTheme) DarkColorScheme else LightColorScheme, shapes = Shapes, content = content, ) } } -@Composable -fun isDarkTheme(): Boolean { - // rememberMutableStateOf - // TODO check in realm. If system, isSystemDark, otherwise, - return isSystemInDarkTheme() -} - object SwissTransferTheme { val typography: CustomTypography @Composable diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/GetSetCallbacks.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/GetSetCallbacks.kt new file mode 100644 index 000000000..28ed3b914 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/GetSetCallbacks.kt @@ -0,0 +1,26 @@ +/* + * Infomaniak SwissTransfer - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.swisstransfer.ui.utils + +import androidx.compose.runtime.Immutable + +@Immutable +class GetSetCallbacks( + val get: () -> T, + val set: (T) -> Unit, +)