Skip to content

Commit

Permalink
Merge pull request #64 from Infomaniak/use-theme-realm
Browse files Browse the repository at this point in the history
Use theme stored in realm
  • Loading branch information
tevincent authored Sep 26, 2024
2 parents f6eeb36 + b4d5ea1 commit e902b8e
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<SettingsViewModel>()
val appSettings by settingsViewModel.appSettingsFlow.collectAsStateWithLifecycle(null)

return getTheme()?.let {
if (it == Theme.SYSTEM) isSystemInDarkTheme() else it== Theme.DARK
} ?: isSystemInDarkTheme()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<Theme>,
validityPeriod: GetSetCallbacks<ValidityPeriod>,
downloadLimit: GetSetCallbacks<DownloadLimit>,
emailLanguage: GetSetCallbacks<EmailLanguage>,
onItemClick: (SettingsOptionScreens) -> Unit,
getSelectedSetting: () -> SettingsOptionScreens?,
) {
Expand All @@ -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) },
)
Expand All @@ -93,23 +96,23 @@ 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) },
)
SettingItem(
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) },
)
SettingItem(
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) },
)
Expand Down Expand Up @@ -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 },
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<SettingsViewModel>(),
) {
val appSettings by settingsViewModel.appSettingsFlow.collectAsStateWithLifecycle(null)

appSettings?.let { safeAppSettings ->
TwoPaneScaffold<SettingsOptionScreens>(
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<SettingsOptionScreens>, appSettings: AppSettings) {
fun SettingsScreenWrapper(
theme: GetSetCallbacks<Theme>,
validityPeriod: GetSetCallbacks<ValidityPeriod>,
downloadLimit: GetSetCallbacks<DownloadLimit>,
emailLanguage: GetSetCallbacks<EmailLanguage>,
) {
TwoPaneScaffold<SettingsOptionScreens>(
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<SettingsOptionScreens>,
theme: GetSetCallbacks<Theme>,
validityPeriod: GetSetCallbacks<ValidityPeriod>,
downloadLimit: GetSetCallbacks<DownloadLimit>,
emailLanguage: GetSetCallbacks<EmailLanguage>,
) {
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()
Expand All @@ -87,9 +115,11 @@ private fun ListPane(navigator: ThreePaneScaffoldNavigator<SettingsOptionScreens
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
private fun DetailPane(
appSettings: AppSettings,
settingsViewModel: SettingsViewModel,
navigator: ThreePaneScaffoldNavigator<SettingsOptionScreens>,
theme: GetSetCallbacks<Theme>,
validityPeriod: GetSetCallbacks<ValidityPeriod>,
downloadLimit: GetSetCallbacks<DownloadLimit>,
emailLanguage: GetSetCallbacks<EmailLanguage>,
) {
var lastSelectedScreen by rememberSaveable { mutableStateOf<SettingsOptionScreens?>(null) }

Expand All @@ -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,
Expand All @@ -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 = {}),
)
}
}
}
13 changes: 3 additions & 10 deletions app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,24 @@ val LocalWindowAdaptiveInfo = staticCompositionLocalOf<WindowAdaptiveInfo> { 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,
LocalCustomColorScheme provides customColors,
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/
package com.infomaniak.swisstransfer.ui.utils

import androidx.compose.runtime.Immutable

@Immutable
class GetSetCallbacks<T>(
val get: () -> T,
val set: (T) -> Unit,
)

0 comments on commit e902b8e

Please sign in to comment.