Updated on 2026-08-14

This commit is contained in:
Tangem 2025-02-21 16:03:19 +05:00
parent 054a7f982f
commit a7ab7abbfb
23 changed files with 165 additions and 30 deletions

View file

@ -1,6 +1,7 @@
package com.tangem.core.ui.components.stories
import android.content.res.Configuration
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -46,6 +47,7 @@ inline fun <reified T : StoryConfig> StoriesContainer(
isPauseStories: Boolean = false,
crossinline currentStoryContent: @Composable BoxScope.(T, Boolean) -> Unit,
) {
var watchedCounter by remember { mutableIntStateOf(1) }
var isPressed by remember { mutableStateOf(value = false) }
val storyState by remember(config) {
mutableStateOf(
@ -55,18 +57,23 @@ inline fun <reified T : StoryConfig> StoriesContainer(
),
)
}
BackHandler(onBack = { config.onClose(watchedCounter) })
val isPaused = isPressed || isPauseStories
val onNextClick = {
storyState.nextStory()
watchedCounter = (watchedCounter + 1).coerceAtMost(config.stories.size)
if (!storyState.hasNext()) { // Finish stories if nothing left to show
config.onClose(watchedCounter)
}
}
Box(modifier = modifier) {
StoriesClickableArea(
onPress = { isPressed = it },
onPreviousStory = storyState::prevStory,
onNextStory = {
if (storyState.nextStory()) {
config.onClose()
}
},
onNextStory = onNextClick,
)
currentStoryContent(storyState.currentStory, isPaused)
@ -79,11 +86,7 @@ inline fun <reified T : StoryConfig> StoriesContainer(
currentStep = storyState.currentIndex.intValue,
stepDuration = storyState.currentStory.duration,
paused = isPaused,
onStepFinish = {
if (storyState.nextStory()) {
config.onClose()
}
},
onStepFinish = onNextClick,
)
Icon(
painter = rememberVectorPainter(
@ -97,7 +100,7 @@ inline fun <reified T : StoryConfig> StoriesContainer(
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = LocalIndication.current,
onClick = config.onClose,
onClick = { config.onClose(watchedCounter) },
),
)
}
@ -133,7 +136,7 @@ private data class StoryContainerPreviewProviderData(
StoryConfigPreviewProviderData(title = "Wallet"),
),
override val isRestartable: Boolean = true,
override val onClose: () -> Unit = {},
override val onClose: (Int) -> Unit = {},
) : StoriesContentConfig<StoryConfigPreviewProviderData>
private data class StoryConfigPreviewProviderData(

View file

@ -19,20 +19,22 @@ class StoriesStepStateMachine<T>(
val currentStory
get() = stories[currentIndex.intValue.coerceIn(FIRST_INDEX, steps)]
fun nextStory(): Boolean {
fun nextStory() {
_currentIndex.intValue = if (currentIndex.intValue == steps && isRepeatable) {
FIRST_INDEX
} else {
currentIndex.intValue.inc().coerceAtMost(stories.size)
}
return currentIndex.intValue > steps
}
fun prevStory() {
_currentIndex.intValue = currentIndex.intValue.dec().coerceAtLeast(FIRST_INDEX)
}
fun hasNext(): Boolean {
return currentIndex.intValue <= steps
}
private companion object {
const val FIRST_INDEX = 0
}

View file

@ -11,7 +11,7 @@ import kotlinx.collections.immutable.ImmutableList
interface StoriesContentConfig<T : StoryConfig> {
val stories: ImmutableList<T>
val isRestartable: Boolean
val onClose: () -> Unit
val onClose: (Int) -> Unit
}
interface StoryConfig {