feat: Enhance screen transition animations and preserve state during navigation for improved user experience
This commit is contained in:
@@ -6,6 +6,8 @@ import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -19,6 +21,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.rosetta.messenger.data.AccountManager
|
||||
@@ -231,22 +234,124 @@ fun MainScreen(
|
||||
var selectedUser by remember { mutableStateOf<SearchUser?>(null) }
|
||||
var showSearchScreen by remember { mutableStateOf(false) }
|
||||
|
||||
// Анимированный переход между экранами
|
||||
// Анимированный переход между экранами - Telegram-style
|
||||
AnimatedContent(
|
||||
targetState = Triple(selectedUser, showSearchScreen, Unit),
|
||||
transitionSpec = {
|
||||
// Только плавный fade без смещения - чтобы header не прыгал
|
||||
fadeIn(
|
||||
animationSpec = tween(
|
||||
durationMillis = 200,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) togetherWith fadeOut(
|
||||
animationSpec = tween(
|
||||
durationMillis = 150,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) using SizeTransform(clip = false)
|
||||
val isEnteringChat = targetState.first != null && initialState.first == null
|
||||
val isExitingChat = targetState.first == null && initialState.first != null
|
||||
val isEnteringSearch = targetState.second && !initialState.second
|
||||
val isExitingSearch = !targetState.second && initialState.second
|
||||
|
||||
when {
|
||||
// 🚀 Вход в чат - slide справа + fade (как Telegram)
|
||||
isEnteringChat -> {
|
||||
slideInHorizontally(
|
||||
initialOffsetX = { fullWidth -> fullWidth / 3 }, // Начинаем на 1/3 экрана справа
|
||||
animationSpec = tween(
|
||||
durationMillis = 250,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) + fadeIn(
|
||||
initialAlpha = 0.3f,
|
||||
animationSpec = tween(
|
||||
durationMillis = 200,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) togetherWith slideOutHorizontally(
|
||||
targetOffsetX = { fullWidth -> -fullWidth / 6 }, // Список уходит немного влево
|
||||
animationSpec = tween(
|
||||
durationMillis = 250,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) + fadeOut(
|
||||
targetAlpha = 0.5f,
|
||||
animationSpec = tween(
|
||||
durationMillis = 200,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 🔙 Выход из чата - slide вправо + fade (быстрее)
|
||||
isExitingChat -> {
|
||||
slideInHorizontally(
|
||||
initialOffsetX = { fullWidth -> -fullWidth / 6 }, // Список возвращается слева
|
||||
animationSpec = tween(
|
||||
durationMillis = 200,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) + fadeIn(
|
||||
initialAlpha = 0.5f,
|
||||
animationSpec = tween(
|
||||
durationMillis = 180,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) togetherWith slideOutHorizontally(
|
||||
targetOffsetX = { fullWidth -> fullWidth / 2 }, // Чат уходит вправо
|
||||
animationSpec = tween(
|
||||
durationMillis = 200,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) + fadeOut(
|
||||
animationSpec = tween(
|
||||
durationMillis = 180,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 🔍 Вход в поиск - slide снизу
|
||||
isEnteringSearch -> {
|
||||
slideInVertically(
|
||||
initialOffsetY = { fullHeight -> fullHeight / 4 },
|
||||
animationSpec = tween(
|
||||
durationMillis = 220,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) + fadeIn(
|
||||
animationSpec = tween(
|
||||
durationMillis = 200,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) togetherWith fadeOut(
|
||||
animationSpec = tween(
|
||||
durationMillis = 150,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// ❌ Выход из поиска - slide вниз
|
||||
isExitingSearch -> {
|
||||
fadeIn(
|
||||
animationSpec = tween(
|
||||
durationMillis = 180,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) togetherWith slideOutVertically(
|
||||
targetOffsetY = { fullHeight -> fullHeight / 4 },
|
||||
animationSpec = tween(
|
||||
durationMillis = 200,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
) + fadeOut(
|
||||
animationSpec = tween(
|
||||
durationMillis = 150,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Default fade
|
||||
else -> {
|
||||
fadeIn(
|
||||
animationSpec = tween(durationMillis = 200)
|
||||
) togetherWith fadeOut(
|
||||
animationSpec = tween(durationMillis = 150)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
label = "screenNavigation"
|
||||
) { (user, isSearchOpen, _) ->
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -194,9 +195,9 @@ fun ChatsListScreen(
|
||||
// Status dialog state
|
||||
var showStatusDialog by remember { mutableStateOf(false) }
|
||||
|
||||
var visible by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) { visible = true }
|
||||
// 🔥 Используем rememberSaveable чтобы сохранить состояние при навигации
|
||||
// Header сразу visible = true, без анимации при возврате из чата
|
||||
var visible by rememberSaveable { mutableStateOf(true) }
|
||||
|
||||
// Dev console dialog - commented out for now
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user