diff --git a/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitch.kt b/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitch.kt index c039ec0d..ef1e97f6 100644 --- a/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitch.kt +++ b/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitch.kt @@ -2,19 +2,26 @@ package com.moscow.tudee.presentation.component.tudeeSwitch import androidx.compose.animation.Crossfade import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.EaseOut import androidx.compose.animation.core.animateDp import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition +import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.BiasAlignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview @@ -31,6 +38,7 @@ fun TudeeSwitch( ) { val themeState = Theme.state val isLightTheme = !themeState.isDark + var isClickable by remember { mutableStateOf(true) } val transition = updateTransition( targetState = isLightTheme, @@ -38,18 +46,16 @@ fun TudeeSwitch( ) val transitionFloatAnimationSpec = remember { - tween(800, easing = EaseOut) + tween(600, easing = EaseOut) } val transitionDpAnimationSpec = remember { - tween(800, easing = EaseOut) + tween(600, easing = EaseOut) } val movingCloudySize by transition.animateDp( - transitionSpec = { - transitionDpAnimationSpec - }, + transitionSpec = { transitionDpAnimationSpec }, label = "movingCloudySize" ) { if (it) 29.dp else 8.dp @@ -57,37 +63,28 @@ fun TudeeSwitch( val outerTopCloudSize by transition.animateDp( - transitionSpec = { - transitionDpAnimationSpec - }, + transitionSpec = { transitionDpAnimationSpec }, label = "cloudyOutlierTopDp" ) { - if (it) 32.dp - else 0.dp + if (it) 32.dp else 0.dp } val cloudyOutlierBottomDp by transition.animateDp( - transitionSpec = { - transitionDpAnimationSpec - }, + transitionSpec = { transitionDpAnimationSpec }, label = "cloudyOutlierBottomDp" ) { if (it) 0.dp else -(8).dp } val movingCloudyPositionX by transition.animateDp( - transitionSpec = { - transitionDpAnimationSpec - }, + transitionSpec = { transitionDpAnimationSpec }, label = "movingCloudyPositionX" ) { if (it) 13.5.dp else (-17).dp } val movingCloudyPositionY by transition.animateDp( - transitionSpec = { - transitionDpAnimationSpec - }, + transitionSpec = { transitionDpAnimationSpec }, label = "movingCloudyPositionY" ) { if (it) 0.dp else 4.dp @@ -95,50 +92,68 @@ fun TudeeSwitch( val movingSmallCloudySize by transition.animateDp( - transitionSpec = { - transitionDpAnimationSpec - }, + transitionSpec = { transitionDpAnimationSpec }, label = "movingSmallCloudySize" ) { if (it) 16.dp else 0.dp } val circleHorizontalBias by transition.animateFloat( - transitionSpec = { - transitionFloatAnimationSpec - }, + transitionSpec = { transitionFloatAnimationSpec }, label = "horizontalBias" ) { - if (it) 1f - else -1f + if (it) 1f else -1f } + val circleAlignment by remember { derivedStateOf { BiasAlignment(circleHorizontalBias, 1f) } } - //400 val circlePositionX by transition.animateDp( - transitionSpec = { - transitionDpAnimationSpec - }, - label = "circleSize" + transitionSpec = { transitionDpAnimationSpec }, + label = "circleSizeX" ) { - if (it) -(14.5).dp else -14.5.dp + if (it) -(14.5).dp else -(14.5).dp } val circlePositionY by transition.animateDp( - transitionSpec = { - transitionDpAnimationSpec - }, - label = "circleSize" + transitionSpec = { transitionDpAnimationSpec }, + label = "circleSizeY" ) { if (it) 4.dp else 26.dp } + val sunBiasAlignment = remember { + Animatable(if (isLightTheme) -1f else 1f) + } + + val moonBiasAlignment = remember { + Animatable(if (isLightTheme) 1f else -1f) + } - //dark + + LaunchedEffect(isLightTheme) { + val startSunBiasAlignment = -1f + val startMoonBiasAlignment = 1f + isClickable = false + + if (!isLightTheme) { + moonBiasAlignment.snapTo(startMoonBiasAlignment) + sunBiasAlignment.animateTo( + targetValue = -startSunBiasAlignment, + animationSpec = transitionFloatAnimationSpec + ) + } else { + sunBiasAlignment.snapTo(startSunBiasAlignment) + moonBiasAlignment.animateTo( + targetValue = -startMoonBiasAlignment, + animationSpec = transitionFloatAnimationSpec + ) + } + isClickable = true + } @@ -149,11 +164,8 @@ fun TudeeSwitch( ) { if (it) { TudeeSwitchLightTheme( - transitionFloatAnimationSpec = transitionFloatAnimationSpec, - isClickable = isLightTheme, - onToggleState = { - themeState.onThemeChanged(isLightTheme) - }, + isClickable = isClickable, + onToggleState = { themeState.onThemeChanged(isLightTheme) }, movingCloudySize = movingCloudySize, outerTopCloudSize = outerTopCloudSize, cloudyOutlierBottomDp = cloudyOutlierBottomDp, @@ -162,17 +174,15 @@ fun TudeeSwitch( movingSmallCloudySize = movingSmallCloudySize, circleAlignment = circleAlignment, circlePositionX = circlePositionX, - circlePositionY = circlePositionY + circlePositionY = circlePositionY, + sunAlignment = BiasAlignment(sunBiasAlignment.value, 0f) ) } else { TudeeSwitchDarkTheme( - isClickable = !isLightTheme, - onToggleState = { - themeState.onThemeChanged(isLightTheme) - }, - movingCloudySize = movingCloudySize, - transitionFloatAnimationSpec = transitionFloatAnimationSpec - + moonAlignment = BiasAlignment(moonBiasAlignment.value, 0f), + isClickable = isClickable, + onToggleState = { themeState.onThemeChanged(isLightTheme) }, + movingCloudySize = movingCloudySize ) } } @@ -195,11 +205,14 @@ private fun TudeeSwitchPreview() { } TudeeTheme(themeState) { - val localState = Theme.state - - Column(modifier = Modifier) { - TudeeSwitch( - ) + Column( + modifier = Modifier + .fillMaxSize() + .background(Theme.colors.surface), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + TudeeSwitch() } } } \ No newline at end of file diff --git a/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitchDarkTheme.kt b/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitchDarkTheme.kt index 7286e1db..d1d14145 100644 --- a/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitchDarkTheme.kt +++ b/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitchDarkTheme.kt @@ -1,8 +1,6 @@ package com.moscow.tudee.presentation.component.tudeeSwitch import androidx.compose.animation.animateContentSize -import androidx.compose.animation.core.Animatable -import androidx.compose.animation.core.TweenSpec import androidx.compose.animation.core.tween import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -18,10 +16,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.BiasAlignment import androidx.compose.ui.Modifier @@ -37,28 +31,15 @@ import androidx.compose.ui.unit.dp import com.moscow.tudee.R import com.moscow.tudee.presentation.designSystem.shadow.innerShadow import com.moscow.tudee.presentation.designSystem.theme.Theme -import kotlinx.coroutines.launch @Stable @Composable fun TudeeSwitchDarkTheme( onToggleState: () -> Unit, isClickable: Boolean, - transitionFloatAnimationSpec: TweenSpec, - movingCloudySize: Dp + movingCloudySize: Dp, + moonAlignment: BiasAlignment, ) { - val coroutineScope = rememberCoroutineScope() - val moonBiasAlignment = remember { - Animatable(1f) - } - - - val moonAlignment by remember { - derivedStateOf { - BiasAlignment(moonBiasAlignment.value, 0f) - } - } - Box( modifier = Modifier .requiredSize(width = 64.dp, height = 36.dp) @@ -105,15 +86,10 @@ fun TudeeSwitchDarkTheme( .padding(end = 2.dp) .size(32.dp) .clip(CircleShape) - .clickable(isClickable) { - coroutineScope.launch { - moonBiasAlignment.animateTo( - targetValue = -1f, - animationSpec = transitionFloatAnimationSpec - ) - } - onToggleState() - } + .clickable( + enabled = isClickable, + onClick = onToggleState + ) .align(moonAlignment) ) { Box( diff --git a/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitchLightTheme.kt b/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitchLightTheme.kt index a1d01bc2..7ff9e8df 100644 --- a/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitchLightTheme.kt +++ b/app/src/main/java/com/moscow/tudee/presentation/component/tudeeSwitch/TudeeSwitchLightTheme.kt @@ -1,8 +1,6 @@ package com.moscow.tudee.presentation.component.tudeeSwitch import androidx.compose.animation.animateContentSize -import androidx.compose.animation.core.Animatable -import androidx.compose.animation.core.TweenSpec import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -15,10 +13,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.BiasAlignment import androidx.compose.ui.Modifier @@ -32,15 +26,13 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import com.moscow.tudee.presentation.designSystem.theme.Theme -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch @Stable @Composable fun TudeeSwitchLightTheme( onToggleState: () -> Unit, isClickable: Boolean, - transitionFloatAnimationSpec: TweenSpec, + sunAlignment: BiasAlignment, movingCloudySize: Dp, outerTopCloudSize: Dp, cloudyOutlierBottomDp: Dp, @@ -52,19 +44,6 @@ fun TudeeSwitchLightTheme( circlePositionY: Dp, surfaceLow: Color = Color(0xFFF0F0F0) ) { - - val coroutineScope = rememberCoroutineScope() - - val sunBiasAlignment = remember { - Animatable(-1f) - } - - val sunAlignment by remember { - derivedStateOf { - BiasAlignment(sunBiasAlignment.value, 0f) - } - } - Box( modifier = Modifier .requiredSize(width = 64.dp, height = 36.dp) @@ -151,15 +130,10 @@ fun TudeeSwitchLightTheme( edgeTreatment = BlurredEdgeTreatment(CircleShape) ) .clip(CircleShape) - .clickable(isClickable) { - coroutineScope.launch(Dispatchers.Main.immediate) { - sunBiasAlignment.animateTo( - targetValue = 1f, - animationSpec = transitionFloatAnimationSpec - ) - } - onToggleState() - } + .clickable( + enabled = isClickable, + onClick = onToggleState + ) .align(sunAlignment) )