Updated on 2026-08-14
This commit is contained in:
parent
ba28cf5b6d
commit
7bbab0a40b
14 changed files with 212 additions and 4 deletions
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.core.ui
|
||||
|
||||
interface DesignFeatureToggles {
|
||||
val isRedesignEnabled: Boolean
|
||||
}
|
||||
|
|
@ -16,4 +16,6 @@ interface UiDependencies {
|
|||
val globalSnackbarHostState: SnackbarHostState
|
||||
|
||||
val eventMessageHandler: EventMessageHandler
|
||||
|
||||
val designFeatureToggles: DesignFeatureToggles
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.tangem.core.ui.components.haze
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.res.LocalHazeState
|
||||
import com.tangem.core.ui.res.LocalPowerSavingState
|
||||
import com.tangem.core.ui.res.LocalRootBackgroundColor
|
||||
import dev.chrisbanes.haze.*
|
||||
import dev.chrisbanes.haze.materials.CupertinoMaterials
|
||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||
|
||||
@OptIn(ExperimentalHazeMaterialsApi::class)
|
||||
@Composable
|
||||
internal fun ProvideHaze(content: @Composable () -> Unit) {
|
||||
val hazeState = rememberHazeState()
|
||||
CompositionLocalProvider(
|
||||
LocalHazeState provides hazeState,
|
||||
LocalHazeStyle provides CupertinoMaterials.ultraThin(),
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a haze effect to the [Modifier] with consideration of global haze settings and power saving mode.
|
||||
*
|
||||
* @param configure A lambda to configure the [HazeEffectScope].
|
||||
* @return A [Modifier] with the configured haze effect applied.
|
||||
*/
|
||||
@Composable
|
||||
fun Modifier.hazeEffectTangem(
|
||||
style: HazeStyle = HazeStyle.Unspecified,
|
||||
configure: HazeEffectScope.() -> Unit = {},
|
||||
): Modifier {
|
||||
val powerSavingEnabled = LocalPowerSavingState.current.isPowerSavingModeEnabled.collectAsState()
|
||||
val hazeState = LocalHazeState.current
|
||||
val isGlobalBlurEnabled = hazeState.blurEnabled && !powerSavingEnabled.value
|
||||
val rootBackground by LocalRootBackgroundColor.current
|
||||
|
||||
return hazeEffect(hazeState, style) {
|
||||
fallbackTint = HazeTint(rootBackground)
|
||||
if (isGlobalBlurEnabled) {
|
||||
configure()
|
||||
}
|
||||
blurEnabled = isGlobalBlurEnabled
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a haze source to the [Modifier] using the current global haze state.
|
||||
*/
|
||||
@Composable
|
||||
fun Modifier.hazeSourceTangem(zIndex: Float = 0f, key: Any? = null) =
|
||||
this.hazeSource(LocalHazeState.current, zIndex, key)
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.core.ui.components.powersaving
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.PowerManager
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class PowerSavingState(
|
||||
appContext: Context,
|
||||
lifecycle: androidx.lifecycle.Lifecycle,
|
||||
) {
|
||||
|
||||
private val powerManager =
|
||||
appContext.getSystemService(Context.POWER_SERVICE) as? PowerManager ?: error("PowerManager not available")
|
||||
|
||||
val isPowerSavingModeEnabled: StateFlow<Boolean>
|
||||
field = MutableStateFlow(powerManager.isPowerSaveMode)
|
||||
|
||||
init {
|
||||
val intentFilter = IntentFilter().apply {
|
||||
addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
|
||||
}
|
||||
|
||||
val receiver = PowerSavingModeReceiver()
|
||||
|
||||
ContextCompat.registerReceiver(
|
||||
appContext,
|
||||
receiver,
|
||||
intentFilter,
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED,
|
||||
)
|
||||
|
||||
lifecycle.addObserver(object : DefaultLifecycleObserver {
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
appContext.unregisterReceiver(receiver)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
inner class PowerSavingModeReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.action == PowerManager.ACTION_POWER_SAVE_MODE_CHANGED) {
|
||||
isPowerSavingModeEnabled.value = powerManager.isPowerSaveMode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun rememberPowerSavingState(): PowerSavingState {
|
||||
val appContext = LocalContext.current.applicationContext
|
||||
val lifecycle = LocalLifecycleOwner.current.lifecycle
|
||||
return remember(appContext, lifecycle) {
|
||||
PowerSavingState(appContext = appContext, lifecycle = lifecycle)
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ import com.tangem.core.ui.UiDependencies
|
|||
import com.tangem.core.ui.components.LocalSystemBarsIconsController
|
||||
import com.tangem.core.ui.components.SystemBarsIconsController
|
||||
import com.tangem.core.ui.components.TangemShimmer
|
||||
import com.tangem.core.ui.components.powersaving.PowerSavingState
|
||||
import com.tangem.core.ui.components.powersaving.rememberPowerSavingState
|
||||
import com.tangem.core.ui.components.text.BladeAnimation
|
||||
import com.tangem.core.ui.components.text.rememberBladeAnimation
|
||||
import com.tangem.core.ui.haptic.DefaultHapticManager
|
||||
|
|
@ -28,6 +30,7 @@ import com.tangem.core.ui.windowsize.WindowSize
|
|||
import com.tangem.core.ui.windowsize.rememberWindowSize
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.valentinilk.shimmer.Shimmer
|
||||
import dev.chrisbanes.haze.HazeState
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
|
|
@ -54,7 +57,13 @@ fun TangemTheme(
|
|||
overrideSystemBarColors = overrideSystemBarColors,
|
||||
typography = typography,
|
||||
dimens = dimens,
|
||||
content = content,
|
||||
content = {
|
||||
if (uiDependencies.designFeatureToggles.isRedesignEnabled) {
|
||||
TangemThemeRedesign { content() }
|
||||
} else {
|
||||
content()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -114,6 +123,7 @@ fun TangemTheme(
|
|||
LocalWindowSize provides windowSize,
|
||||
LocalBladeAnimation provides rememberBladeAnimation(),
|
||||
LocalSystemBarsIconsController provides systemBarsIconsController,
|
||||
LocalPowerSavingState provides rememberPowerSavingState(),
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalTangemShimmer provides TangemShimmer,
|
||||
|
|
@ -403,6 +413,18 @@ val LocalBladeAnimation = staticCompositionLocalOf<BladeAnimation> {
|
|||
error("No MainBottomSheetColor provided")
|
||||
}
|
||||
|
||||
val LocalHazeState = staticCompositionLocalOf<HazeState> {
|
||||
error("No HazeState provided")
|
||||
}
|
||||
|
||||
val LocalRedesignEnabled = staticCompositionLocalOf<Boolean> {
|
||||
false
|
||||
}
|
||||
|
||||
val LocalPowerSavingState = compositionLocalOf<PowerSavingState> {
|
||||
error("No PowerSavingState provided")
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the dark theme should be used based on the given [AppThemeMode].
|
||||
*
|
||||
|
|
|
|||
|
|
@ -2,8 +2,12 @@
|
|||
|
||||
package com.tangem.core.ui.res
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.haze.ProvideHaze
|
||||
import com.tangem.core.ui.components.haze.hazeSourceTangem
|
||||
|
||||
/**
|
||||
* Provides additional theming for redesigned components.
|
||||
|
|
@ -21,12 +25,17 @@ fun TangemThemeRedesign(content: @Composable () -> Unit) {
|
|||
colorScheme = tangemColorScheme(colors = themeColors),
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalRedesignEnabled provides true,
|
||||
LocalTangemColors provides themeColors,
|
||||
LocalTangemColors2 provides if (LocalIsInDarkTheme.current) darkThemeColors2() else lightThemeColors2(),
|
||||
LocalTangemTypography2 provides TangemTypography2(InterFamily),
|
||||
LocalRootBackgroundColor provides remember(rootBackgroundColor) { mutableStateOf(rootBackgroundColor) },
|
||||
) {
|
||||
content()
|
||||
ProvideHaze {
|
||||
Box(Modifier.hazeSourceTangem(zIndex = 1f)) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue