From 38ee16725ef0da5e7782820cd1e9281c3afaf2b1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 21 Sep 2023 18:39:45 +0200 Subject: [PATCH] Add animation on the timeline content, to avoid glitch (#1323) --- .../messages/impl/timeline/TimelineView.kt | 13 +++-- .../designsystem/animation/AlphaAnimation.kt | 49 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/animation/AlphaAnimation.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt index 83ba252569..42f529a899 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt @@ -47,6 +47,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.rotate import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.pluralStringResource @@ -63,8 +64,9 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentProvider import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent import io.element.android.features.messages.impl.timeline.model.event.canBeRepliedTo -import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.animation.alphaAnimation import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.FloatingActionButton import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.utils.CommonDrawables @@ -105,7 +107,10 @@ fun TimelineView( state.eventSink(TimelineEvents.PollAnswerSelected(pollStartId, answerId)) } - Box(modifier = modifier) { + // Animate alpha when timeline is first displayed, to avoid flashes or glitching when viewing rooms + val alpha by alphaAnimation(label = "alpha for timeline") + + Box(modifier = modifier.alpha(alpha)) { LazyColumn( modifier = Modifier.fillMaxSize(), state = lazyListState, @@ -315,7 +320,9 @@ private fun JumpToBottomButton( contentColor = ElementTheme.colors.iconSecondary ) { Icon( - modifier = Modifier.size(24.dp).rotate(90f), + modifier = Modifier + .size(24.dp) + .rotate(90f), resourceId = CommonDrawables.ic_compound_arrow_right, contentDescription = "", ) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/animation/AlphaAnimation.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/animation/AlphaAnimation.kt new file mode 100644 index 0000000000..bfcfc9ff32 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/animation/AlphaAnimation.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 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 + * + * http://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.animation + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalInspectionMode + +@Composable +fun alphaAnimation( + fromAlpha: Float = 0f, + toAlpha: Float = 1f, + delayMillis: Int = 150, + durationMillis: Int = 150, + label: String = "AlphaAnimation", +): State { + val firstAlpha = if (LocalInspectionMode.current) 1f else fromAlpha + var alpha by remember { mutableFloatStateOf(firstAlpha) } + LaunchedEffect(Unit) { alpha = toAlpha } + return animateFloatAsState( + targetValue = alpha, + animationSpec = tween( + delayMillis = delayMillis, + durationMillis = durationMillis, + ), + label = label + ) +}