diff --git a/app/src/main/kotlin/io/element/android/x/MainActivity.kt b/app/src/main/kotlin/io/element/android/x/MainActivity.kt index eb3f9450f5..b36f93f1dc 100644 --- a/app/src/main/kotlin/io/element/android/x/MainActivity.kt +++ b/app/src/main/kotlin/io/element/android/x/MainActivity.kt @@ -26,9 +26,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen @@ -38,16 +35,13 @@ import androidx.lifecycle.repeatOnLifecycle import com.bumble.appyx.core.integration.NodeHost import com.bumble.appyx.core.integrationpoint.NodeActivity import com.bumble.appyx.core.plugin.NodeReadyObserver -import io.element.android.compound.theme.ElementTheme -import io.element.android.compound.theme.Theme -import io.element.android.compound.theme.isDark -import io.element.android.compound.theme.mapToTheme import io.element.android.features.lockscreen.api.LockScreenEntryPoint import io.element.android.features.lockscreen.api.LockScreenLockState import io.element.android.features.lockscreen.api.LockScreenService import io.element.android.features.lockscreen.api.handleSecureFlag import io.element.android.libraries.architecture.bindings import io.element.android.libraries.core.log.logger.LoggerTag +import io.element.android.libraries.designsystem.theme.ElementThemeApp import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher import io.element.android.x.di.AppBindings import io.element.android.x.intent.SafeUriHandler @@ -74,14 +68,8 @@ class MainActivity : NodeActivity() { @Composable private fun MainContent(appBindings: AppBindings) { - val theme by remember { - appBindings.preferencesStore().getThemeFlow().mapToTheme() - } - .collectAsState(initial = Theme.System) val migrationState = appBindings.migrationEntryPoint().present() - ElementTheme( - darkTheme = theme.isDark() - ) { + ElementThemeApp(appBindings.preferencesStore()) { CompositionLocalProvider( LocalSnackbarDispatcher provides appBindings.snackbarDispatcher(), LocalUriHandler provides SafeUriHandler(this), diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt index b8f10f15ed..b0d41efe9e 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt @@ -30,15 +30,8 @@ import androidx.activity.compose.setContent import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.core.content.IntentCompat -import io.element.android.compound.theme.ElementTheme -import io.element.android.compound.theme.Theme -import io.element.android.compound.theme.isDark -import io.element.android.compound.theme.mapToTheme import io.element.android.features.call.api.CallType import io.element.android.features.call.impl.DefaultElementCallEntryPoint import io.element.android.features.call.impl.di.CallBindings @@ -46,6 +39,7 @@ import io.element.android.features.call.impl.pip.PictureInPicturePresenter import io.element.android.features.call.impl.services.CallForegroundService import io.element.android.features.call.impl.utils.CallIntentDataParser import io.element.android.libraries.architecture.bindings +import io.element.android.libraries.designsystem.theme.ElementThemeApp import io.element.android.libraries.preferences.api.store.AppPreferencesStore import javax.inject.Inject @@ -94,14 +88,8 @@ class ElementCallActivity : AppCompatActivity(), CallScreenNavigator { requestAudioFocus() setContent { - val theme by remember { - appPreferencesStore.getThemeFlow().mapToTheme() - } - .collectAsState(initial = Theme.System) val pipState = pictureInPicturePresenter.present() - ElementTheme( - darkTheme = theme.isDark() - ) { + ElementThemeApp(appPreferencesStore) { val state = presenter.present() CallScreenView( state = state, diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt index cbbeaef47c..05d36434cc 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt @@ -20,15 +20,8 @@ import android.os.Bundle import android.view.WindowManager import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.core.content.IntentCompat import androidx.lifecycle.lifecycleScope -import io.element.android.compound.theme.ElementTheme -import io.element.android.compound.theme.Theme -import io.element.android.compound.theme.isDark -import io.element.android.compound.theme.mapToTheme import io.element.android.features.call.api.CallType import io.element.android.features.call.api.ElementCallEntryPoint import io.element.android.features.call.impl.di.CallBindings @@ -36,6 +29,7 @@ import io.element.android.features.call.impl.notifications.CallNotificationData import io.element.android.features.call.impl.utils.ActiveCallManager import io.element.android.features.call.impl.utils.CallState import io.element.android.libraries.architecture.bindings +import io.element.android.libraries.designsystem.theme.ElementThemeApp import io.element.android.libraries.preferences.api.store.AppPreferencesStore import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn @@ -79,13 +73,7 @@ class IncomingCallActivity : AppCompatActivity() { val notificationData = intent?.let { IntentCompat.getParcelableExtra(it, EXTRA_NOTIFICATION_DATA, CallNotificationData::class.java) } if (notificationData != null) { setContent { - val theme by remember { - appPreferencesStore.getThemeFlow().mapToTheme() - } - .collectAsState(initial = Theme.System) - ElementTheme( - darkTheme = theme.isDark() - ) { + ElementThemeApp(appPreferencesStore) { IncomingCallScreen( notificationData = notificationData, onAnswer = ::onAnswer, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt index ce87613c24..7b7b16790f 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt @@ -23,20 +23,14 @@ import androidx.activity.OnBackPressedCallback import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.lifecycle.lifecycleScope -import io.element.android.compound.theme.ElementTheme -import io.element.android.compound.theme.Theme -import io.element.android.compound.theme.isDark -import io.element.android.compound.theme.mapToTheme import io.element.android.features.lockscreen.api.LockScreenLockState import io.element.android.features.lockscreen.api.LockScreenService import io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter import io.element.android.features.lockscreen.impl.unlock.PinUnlockView import io.element.android.features.lockscreen.impl.unlock.di.PinUnlockBindings import io.element.android.libraries.architecture.bindings +import io.element.android.libraries.designsystem.theme.ElementThemeApp import io.element.android.libraries.preferences.api.store.AppPreferencesStore import kotlinx.coroutines.launch import javax.inject.Inject @@ -57,13 +51,7 @@ class PinUnlockActivity : AppCompatActivity() { super.onCreate(savedInstanceState) bindings().inject(this) setContent { - val theme by remember { - appPreferencesStore.getThemeFlow().mapToTheme() - } - .collectAsState(initial = Theme.System) - ElementTheme( - darkTheme = theme.isDark() - ) { + ElementThemeApp(appPreferencesStore) { val state = presenter.present() PinUnlockView(state = state, isInAppUnlock = false) } diff --git a/libraries/designsystem/build.gradle.kts b/libraries/designsystem/build.gradle.kts index 9934da3e13..e737220961 100644 --- a/libraries/designsystem/build.gradle.kts +++ b/libraries/designsystem/build.gradle.kts @@ -42,6 +42,7 @@ android { implementation(libs.coil.compose) implementation(libs.vanniktech.blurhash) implementation(projects.libraries.architecture) + implementation(projects.libraries.preferences.api) implementation(projects.libraries.testtags) implementation(projects.libraries.uiStrings) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ElementThemeApp.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ElementThemeApp.kt new file mode 100644 index 0000000000..4c20c02e9b --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ElementThemeApp.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.designsystem.theme + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.theme.Theme +import io.element.android.compound.theme.isDark +import io.element.android.compound.theme.mapToTheme +import io.element.android.libraries.preferences.api.store.AppPreferencesStore + +/** + * Theme to use for all the regular screens of the application. + * Will manage the light / dark theme based on the user preference. + */ +@Composable +fun ElementThemeApp( + appPreferencesStore: AppPreferencesStore, + content: @Composable () -> Unit, +) { + val theme by remember { + appPreferencesStore.getThemeFlow().mapToTheme() + } + .collectAsState(initial = Theme.System) + ElementTheme( + darkTheme = theme.isDark(), + content = content, + ) +}