From 8c6a582d4ace2aad7eff60ff47c89bc8ca04642d Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 23 Jan 2025 11:50:39 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../ui/walletconnect/WalletConnectScreen.kt | 10 +- .../res/drawable/progress_rounded_shape.xml | 17 ++ .../res/layout/view_onboarding_progress.xml | 7 +- ...or.kt => TangemLinearProgressIndicator.kt} | 146 ++++++++++++++++-- .../ui/components/PricePerformanceBlock.kt | 4 +- .../v2/stepper/impl/ui/OnboardingStepper.kt | 10 +- .../api/OnboardingSeedPhraseScreen.kt | 39 ++--- .../tangem/feature/swap/ui/ProviderItem.kt | 6 +- .../express/exchange/ExchangeStatusBlock.kt | 4 +- 9 files changed, 195 insertions(+), 48 deletions(-) create mode 100644 app/src/main/res/drawable/progress_rounded_shape.xml rename core/ui/src/main/java/com/tangem/core/ui/components/progressbar/{LinearProgressIndicator.kt => TangemLinearProgressIndicator.kt} (51%) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt index b25fe77799..252fc23b51 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt @@ -5,7 +5,10 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.* +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -15,6 +18,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.tangem.core.analytics.Analytics +import com.tangem.core.ui.components.progressbar.TangemLinearProgressIndicator import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.common.analytics.events.Settings @@ -71,7 +75,7 @@ private fun AddSessionFab(onAddSession: () -> Unit, modifier: Modifier = Modifie @Composable private fun EmptyScreen(state: WalletConnectScreenState) { if (state.isLoading) { - LinearProgressIndicator( + TangemLinearProgressIndicator( modifier = Modifier.fillMaxWidth(), color = TangemTheme.colors.icon.accent, ) @@ -102,7 +106,7 @@ private fun EmptyScreen(state: WalletConnectScreenState) { @Composable private fun WalletConnectSessions(state: WalletConnectScreenState) { if (state.isLoading) { - LinearProgressIndicator( + TangemLinearProgressIndicator( modifier = Modifier .fillMaxWidth() .height(2.dp), diff --git a/app/src/main/res/drawable/progress_rounded_shape.xml b/app/src/main/res/drawable/progress_rounded_shape.xml new file mode 100644 index 0000000000..7be741d331 --- /dev/null +++ b/app/src/main/res/drawable/progress_rounded_shape.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_onboarding_progress.xml b/app/src/main/res/layout/view_onboarding_progress.xml index 696a282eda..83dcb3354b 100644 --- a/app/src/main/res/layout/view_onboarding_progress.xml +++ b/app/src/main/res/layout/view_onboarding_progress.xml @@ -4,9 +4,10 @@ android:id="@+id/pb_state" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="20dp" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" - android:progressBackgroundTint="@color/icon_informative" - android:progressTint="@color/icon_primary_1" /> + android:paddingVertical="8dp" + android:indeterminate="false" + android:progressDrawable="@drawable/progress_rounded_shape" /> diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/progressbar/LinearProgressIndicator.kt b/core/ui/src/main/java/com/tangem/core/ui/components/progressbar/TangemLinearProgressIndicator.kt similarity index 51% rename from core/ui/src/main/java/com/tangem/core/ui/components/progressbar/LinearProgressIndicator.kt rename to core/ui/src/main/java/com/tangem/core/ui/components/progressbar/TangemLinearProgressIndicator.kt index 05cbf5db85..e9fddfa79e 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/progressbar/LinearProgressIndicator.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/progressbar/TangemLinearProgressIndicator.kt @@ -3,11 +3,11 @@ package com.tangem.core.ui.components.progressbar import android.content.res.Configuration +import androidx.compose.animation.core.* import androidx.compose.foundation.Canvas -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.runtime.Composable +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color @@ -39,7 +39,7 @@ import kotlin.math.abs * @param strokeCap stroke cap to use for the ends of this progress indicator */ @Composable -fun LinearProgressIndicator( +fun TangemLinearProgressIndicator( progress: () -> Float, modifier: Modifier = Modifier, color: Color = TangemTheme.colors.text.accent, @@ -61,6 +61,99 @@ fun LinearProgressIndicator( } } +/** + * Progress indicators loading status with infinite animation + * + * @param modifier the [Modifier] to be applied to this progress indicator + * @param color The color of the progress indicator. + * @param backgroundColor The color of the background behind the indicator, visible when the + * progress has not reached that area of the overall indicator yet. + * @param strokeCap stroke cap to use for the ends of this progress indicator + */ +@Suppress("LongMethod") +@Composable +fun TangemLinearProgressIndicator( + modifier: Modifier = Modifier, + color: Color = TangemTheme.colors.text.accent, + backgroundColor: Color = TangemTheme.colors.background.tertiary, + strokeCap: StrokeCap = StrokeCap.Round, +) { + val infiniteTransition = rememberInfiniteTransition() + val firstLineHead by infiniteTransition.animateFloat( + 0f, + 1f, + infiniteRepeatable( + animation = keyframes { + durationMillis = LINEAR_ANIMATION_DURATION + 0f at FIRST_LINE_HEAD_DELAY using FIRST_LINE_HEAD_EASING + 1f at FIRST_LINE_HEAD_DURATION + FIRST_LINE_HEAD_DELAY + }, + ), + ) + val firstLineTail by infiniteTransition.animateFloat( + 0f, + 1f, + infiniteRepeatable( + animation = keyframes { + durationMillis = LINEAR_ANIMATION_DURATION + 0f at FIRST_LINE_TAIL_DELAY using FIRST_LINE_TAIL_EASING + 1f at FIRST_LINE_TAIL_DURATION + FIRST_LINE_TAIL_DELAY + }, + ), + ) + val secondLineHead by infiniteTransition.animateFloat( + 0f, + 1f, + infiniteRepeatable( + animation = keyframes { + durationMillis = LINEAR_ANIMATION_DURATION + 0f at SECOND_LINE_HEAD_DELAY using SECOND_LINE_HEAD_EASING + 1f at SECOND_LINE_HEAD_DURATION + SECOND_LINE_HEAD_DELAY + }, + ), + ) + val secondLineTail by infiniteTransition.animateFloat( + 0f, + 1f, + infiniteRepeatable( + animation = keyframes { + durationMillis = LINEAR_ANIMATION_DURATION + 0f at SECOND_LINE_TAIL_DELAY using SECOND_LINE_TAIL_EASING + 1f at SECOND_LINE_TAIL_DURATION + SECOND_LINE_TAIL_DELAY + }, + ), + ) + Canvas( + modifier + .increaseSemanticsBounds() + .semantics(mergeDescendants = true) { + progressBarRangeInfo = ProgressBarRangeInfo.Indeterminate + } + .size(height = 4.dp, width = 24.dp), + ) { + val strokeWidth = size.height + drawLinearIndicatorBackground(backgroundColor, strokeWidth, strokeCap) + if (firstLineHead - firstLineTail > 0) { + drawLinearIndicator( + firstLineHead, + firstLineTail, + color, + strokeWidth, + strokeCap, + ) + } + if ((secondLineHead - secondLineTail) > 0) { + drawLinearIndicator( + secondLineHead, + secondLineTail, + color, + strokeWidth, + strokeCap, + ) + } + } +} + internal fun Modifier.increaseSemanticsBounds(): Modifier { val padding = 10.dp return this @@ -129,16 +222,51 @@ private fun DrawScope.drawLinearIndicator( private fun DrawScope.drawLinearIndicatorBackground(color: Color, strokeWidth: Float, strokeCap: StrokeCap) = drawLinearIndicator(0f, 1f, color, strokeWidth, strokeCap) +// Indeterminate linear indicator transition specs +// Total duration for one cycle +private const val LINEAR_ANIMATION_DURATION = 1800 + +// Duration of the head and tail animations for both lines +private const val FIRST_LINE_HEAD_DURATION = 750 +private const val FIRST_LINE_TAIL_DURATION = 850 +private const val SECOND_LINE_HEAD_DURATION = 567 +private const val SECOND_LINE_TAIL_DURATION = 533 + +// Delay before the start of the head and tail animations for both lines +private const val FIRST_LINE_HEAD_DELAY = 0 +private const val FIRST_LINE_TAIL_DELAY = 333 +private const val SECOND_LINE_HEAD_DELAY = 1000 +private const val SECOND_LINE_TAIL_DELAY = 1267 + +private val FIRST_LINE_HEAD_EASING = CubicBezierEasing(0.2f, 0f, 0.8f, 1f) +private val FIRST_LINE_TAIL_EASING = CubicBezierEasing(0.4f, 0f, 1f, 1f) +private val SECOND_LINE_HEAD_EASING = CubicBezierEasing(0f, 0f, 0.65f, 1f) +private val SECOND_LINE_TAIL_EASING = CubicBezierEasing(0.1f, 0f, 0.45f, 1f) + // region Preview @Preview(showBackground = true, widthDp = 360) @Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable private fun LinearProgressIndicator_Preview() { TangemThemePreview { - LinearProgressIndicator( - progress = { 0.5f }, - modifier = Modifier.fillMaxWidth(), - ) + Column( + modifier = Modifier + .background(TangemTheme.colors.background.secondary) + .padding(12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + TangemLinearProgressIndicator( + progress = { 0.6f }, + modifier = Modifier.fillMaxWidth(), + color = TangemTheme.colors.icon.primary1, + backgroundColor = TangemTheme.colors.background.tertiary, + ) + TangemLinearProgressIndicator( + modifier = Modifier.fillMaxWidth(), + color = TangemTheme.colors.icon.primary1, + backgroundColor = TangemTheme.colors.background.tertiary, + ) + } } } // endregion \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/PricePerformanceBlock.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/PricePerformanceBlock.kt index 1c63ecd0b4..4486732b67 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/PricePerformanceBlock.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/ui/components/PricePerformanceBlock.kt @@ -17,7 +17,7 @@ import com.tangem.core.ui.components.SpacerW8 import com.tangem.core.ui.components.TextShimmer import com.tangem.core.ui.components.block.information.InformationBlock import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons -import com.tangem.core.ui.components.progressbar.LinearProgressIndicator +import com.tangem.core.ui.components.progressbar.TangemLinearProgressIndicator import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemAnimations @@ -116,7 +116,7 @@ private fun Content(state: PricePerformanceUM.Value, modifier: Modifier = Modifi color = TangemTheme.colors.text.tertiary, ) } - LinearProgressIndicator( + TangemLinearProgressIndicator( modifier = Modifier .height(TangemTheme.dimens.size6) .fillMaxWidth(), diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/stepper/impl/ui/OnboardingStepper.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/stepper/impl/ui/OnboardingStepper.kt index a22c50812e..50136e9d10 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/stepper/impl/ui/OnboardingStepper.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/stepper/impl/ui/OnboardingStepper.kt @@ -1,5 +1,6 @@ package com.tangem.features.onboarding.v2.stepper.impl.ui +import android.content.res.Configuration import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween @@ -15,7 +16,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.appbar.TangemTopAppBar import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM -import com.tangem.core.ui.components.progressbar.LinearProgressIndicator +import com.tangem.core.ui.components.progressbar.TangemLinearProgressIndicator import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.res.TangemAnimations import com.tangem.core.ui.res.TangemTheme @@ -59,7 +60,7 @@ internal fun OnboardingStepper( modifier = modifier, ) - LinearProgressIndicator( + TangemLinearProgressIndicator( modifier = Modifier .alpha(progressAlpha) .padding(horizontal = 16.dp) @@ -67,15 +68,16 @@ internal fun OnboardingStepper( .fillMaxWidth(), progress = { animatedIndicatorFraction }, color = TangemTheme.colors.icon.primary1, - backgroundColor = TangemTheme.colors.background.tertiary, + backgroundColor = TangemTheme.colors.icon.primary1.copy(alpha = 0.4f), strokeCap = StrokeCap.Round, ) } } @Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable -private fun Preview() { +private fun OnboardingStepper_Preview() { TangemThemePreview { Box( Modifier diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseScreen.kt index 6db1217109..51d9740d8c 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseScreen.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/api/OnboardingSeedPhraseScreen.kt @@ -1,10 +1,14 @@ package com.tangem.feature.onboarding.api import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.* -import androidx.compose.material.LinearProgressIndicator +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.StrokeCap +import com.tangem.core.ui.components.progressbar.TangemLinearProgressIndicator import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.onboarding.presentation.wallet2.model.OnboardingSeedPhraseState import com.tangem.feature.onboarding.presentation.wallet2.ui.* @@ -19,31 +23,22 @@ class OnboardingSeedPhraseScreen : OnboardingSeedPhraseApi { override fun ScreenContent(uiState: OnboardingSeedPhraseState, subScreen: SeedPhraseScreen, progress: Float) { BackHandler(onBack = uiState.onBackClick) Column { - ProgressIndicator(progress) + TangemLinearProgressIndicator( + progress = { progress }, + color = TangemTheme.colors.icon.primary1, + backgroundColor = TangemTheme.colors.icon.primary1.copy(alpha = 0.4f), + strokeCap = StrokeCap.Round, + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(top = TangemTheme.dimens.size8) + .padding(horizontal = TangemTheme.dimens.size16), + ) Content(subScreen, uiState) } } } -@Composable -private fun ProgressIndicator(progress: Float) { - Box( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(top = TangemTheme.dimens.size8), - ) { - LinearProgressIndicator( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = TangemTheme.dimens.size16), - color = TangemTheme.colors.background.action, - backgroundColor = TangemTheme.colors.background.action.copy(alpha = 0.081f), - progress = progress, - ) - } -} - @Composable private fun Content(screen: SeedPhraseScreen, uiState: OnboardingSeedPhraseState) { when (screen) { diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt index 7e1c08759d..d743a4ebda 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt @@ -5,9 +5,9 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* -import androidx.compose.material.CircularProgressIndicator -import androidx.compose.material.Icon -import androidx.compose.material.Text +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBlock.kt index 7e0091568c..33fcbc4cf8 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBlock.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBlock.kt @@ -8,8 +8,8 @@ import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.CircularProgressIndicator -import androidx.compose.material.Icon +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment