Updated on 2026-08-14
This commit is contained in:
commit
d994b7840a
150 changed files with 971 additions and 4621 deletions
|
|
@ -9,7 +9,6 @@ import com.tangem.core.decompose.model.getOrCreateModel
|
|||
import com.tangem.features.home.api.HomeComponent
|
||||
import com.tangem.features.home.impl.model.HomeModel
|
||||
import com.tangem.features.home.impl.ui.Home
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -17,7 +16,6 @@ import dagger.assisted.AssistedInject
|
|||
internal class DefaultHomeComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: HomeComponent.Params,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
) : HomeComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: HomeModel = getOrCreateModel(params)
|
||||
|
|
@ -26,11 +24,7 @@ internal class DefaultHomeComponent @AssistedInject constructor(
|
|||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
Home(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
isV2StoriesEnabled = hotWalletFeatureToggles.isHotWalletEnabled,
|
||||
)
|
||||
Home(state = state, modifier = modifier)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -35,14 +35,12 @@ import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
|
|||
import com.tangem.domain.settings.usercountry.models.UserCountry
|
||||
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
|
||||
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.usecase.GenerateBuyTangemCardLinkUseCase
|
||||
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
|
||||
import com.tangem.features.home.api.HomeComponent
|
||||
import com.tangem.features.home.impl.ui.state.HomeUM
|
||||
import com.tangem.features.home.impl.ui.state.Stories
|
||||
import com.tangem.features.home.impl.ui.state.getRestrictedStories
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -70,8 +68,6 @@ internal class HomeModel @Inject constructor(
|
|||
private val saveWalletUseCase: SaveWalletUseCase,
|
||||
private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
|
||||
|
|
@ -219,7 +215,7 @@ internal class HomeModel @Inject constructor(
|
|||
currency = currency,
|
||||
batch = scanResponse.card.batchId,
|
||||
signInType = SignInType.Card,
|
||||
walletsCount = getWalletsCount().toString(),
|
||||
walletsCount = userWalletsListRepository.userWalletsSync().size.toString(),
|
||||
isImported = isImported,
|
||||
hasBackup = scanResponse.card.backupStatus?.isActive,
|
||||
),
|
||||
|
|
@ -227,14 +223,6 @@ internal class HomeModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getWalletsCount(): Int {
|
||||
return if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
||||
userWalletsListRepository.userWalletsSync().size
|
||||
} else {
|
||||
userWalletsListManager.walletsCount
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLoading(isLoading: Boolean) {
|
||||
_uiState.update { it.copy(scanInProgress = isLoading) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,29 +5,18 @@ import androidx.compose.ui.Modifier
|
|||
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.utils.ChangeRootBackgroundColorEffect
|
||||
import com.tangem.features.home.impl.ui.compose.StoriesScreen
|
||||
import com.tangem.features.home.impl.ui.compose.StoriesScreenV2
|
||||
import com.tangem.features.home.impl.ui.state.HomeUM
|
||||
|
||||
@Composable
|
||||
internal fun Home(state: HomeUM, isV2StoriesEnabled: Boolean, modifier: Modifier = Modifier) {
|
||||
internal fun Home(state: HomeUM, modifier: Modifier = Modifier) {
|
||||
SystemBarsIconsDisposable(darkIcons = false)
|
||||
|
||||
if (isV2StoriesEnabled) {
|
||||
StoriesScreenV2(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onGetStartedClick = state.onGetStartedClick,
|
||||
)
|
||||
} else {
|
||||
StoriesScreen(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onScanButtonClick = state.onScanClick,
|
||||
onShopButtonClick = state.onShopClick,
|
||||
onSearchTokensClick = state.onSearchTokensClick,
|
||||
)
|
||||
}
|
||||
StoriesScreenV2(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onGetStartedClick = state.onGetStartedClick,
|
||||
)
|
||||
|
||||
ChangeRootBackgroundColorEffect(TangemColorPalette.Black)
|
||||
}
|
||||
|
|
@ -1,271 +0,0 @@
|
|||
@file:Suppress("MagicNumber")
|
||||
|
||||
package com.tangem.features.home.impl.ui.compose
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.StoriesScreenTestTags
|
||||
import com.tangem.features.home.impl.ui.compose.content.*
|
||||
import com.tangem.features.home.impl.ui.compose.views.HomeButtons
|
||||
import com.tangem.features.home.impl.ui.compose.views.SearchCurrenciesButton
|
||||
import com.tangem.features.home.impl.ui.compose.views.StoriesProgressBar
|
||||
import com.tangem.features.home.impl.ui.state.Stories
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.features.home.impl.ui.state.HomeUM
|
||||
import kotlin.math.max
|
||||
|
||||
@Composable
|
||||
internal fun StoriesScreen(
|
||||
state: HomeUM,
|
||||
onScanButtonClick: () -> Unit,
|
||||
onShopButtonClick: () -> Unit,
|
||||
onSearchTokensClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var currentStory by remember { mutableStateOf(state.firstStory) }
|
||||
val currentStoryIndex by rememberUpdatedState(newValue = state.stepOf(currentStory))
|
||||
|
||||
LaunchedEffect(currentStoryIndex) {
|
||||
if (currentStoryIndex < 0) {
|
||||
currentStory = state.firstStory
|
||||
}
|
||||
}
|
||||
|
||||
val goToPreviousStory = remember(currentStory, currentStoryIndex) {
|
||||
{ currentStory = state.stories[max(0, currentStoryIndex - 1)] }
|
||||
}
|
||||
val goToNextStory = remember(currentStory, currentStoryIndex) {
|
||||
{
|
||||
currentStory = if (currentStoryIndex >= 0 && currentStoryIndex < state.stories.lastIndex) {
|
||||
state.stories[currentStoryIndex + 1]
|
||||
} else {
|
||||
state.firstStory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo refactor [REDACTED_TASK_KEY]
|
||||
StoriesScreenContent(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(StoriesScreenTestTags.SCREEN_CONTAINER),
|
||||
config = StoriesScreenContentConfig(
|
||||
storiesSize = state.stories.lastIndex,
|
||||
currentStoryIndex = currentStoryIndex,
|
||||
currentStory = currentStory,
|
||||
isScanInProgress = state.scanInProgress,
|
||||
onGoToPreviousStory = goToPreviousStory,
|
||||
onGoToNextStory = goToNextStory,
|
||||
onSearchTokensClick = onSearchTokensClick,
|
||||
onScanButtonClick = onScanButtonClick,
|
||||
onShopButtonClick = onShopButtonClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("Use StoriesContainer from core/ui")
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: Modifier = Modifier) {
|
||||
var isPressed by remember { mutableStateOf(value = false) }
|
||||
|
||||
val isPaused = isPressed || config.isScanInProgress
|
||||
val currentStoryDuration = config.currentStory.duration
|
||||
|
||||
Box(
|
||||
modifier = modifier.background(Color(0xFF010101)),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.fillMaxHeight()
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onPress = {
|
||||
val pressStartTime = System.currentTimeMillis()
|
||||
isPressed = true
|
||||
this.tryAwaitRelease()
|
||||
val pressEndTime = System.currentTimeMillis()
|
||||
val totalPressTime = pressEndTime - pressStartTime
|
||||
if (totalPressTime < 200) config.onGoToPreviousStory()
|
||||
isPressed = false
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
Box(
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.fillMaxHeight()
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onPress = {
|
||||
val pressStartTime = System.currentTimeMillis()
|
||||
isPressed = true
|
||||
this.tryAwaitRelease()
|
||||
val pressEndTime = System.currentTimeMillis()
|
||||
val totalPressTime = pressEndTime - pressStartTime
|
||||
if (totalPressTime < 200) config.onGoToNextStory()
|
||||
isPressed = false
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.statusBarsPadding()
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
StoriesProgressBar(
|
||||
steps = config.storiesSize,
|
||||
currentStep = config.currentStoryIndex,
|
||||
stepDuration = currentStoryDuration,
|
||||
paused = isPaused,
|
||||
onStepFinish = config.onGoToNextStory,
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_tangem_logo),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillHeight,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
.height(TangemTheme.dimens.size18)
|
||||
.align(Alignment.Start),
|
||||
)
|
||||
when (config.currentStory) {
|
||||
Stories.TangemIntro -> FirstStoriesContent(
|
||||
isPaused = isPaused,
|
||||
duration = currentStoryDuration,
|
||||
)
|
||||
Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet()
|
||||
Stories.UltraSecureBackup -> StoriesUltraSecureBackup(
|
||||
isPaused = isPaused,
|
||||
stepDuration = currentStoryDuration,
|
||||
)
|
||||
Stories.Currencies -> StoriesCurrencies(isPaused, currentStoryDuration)
|
||||
Stories.Web3 -> StoriesWeb3(isPaused, currentStoryDuration)
|
||||
Stories.WalletForEveryone -> StoriesWalletForEveryone(currentStoryDuration)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.navigationBarsPadding()
|
||||
.padding(bottom = TangemTheme.dimens.spacing16)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.align(Alignment.BottomCenter)
|
||||
.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = config.currentStory == Stories.Currencies,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
SearchCurrenciesButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = config.onSearchTokensClick,
|
||||
)
|
||||
}
|
||||
|
||||
HomeButtons(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
btnScanStateInProgress = config.isScanInProgress,
|
||||
onScanButtonClick = config.onScanButtonClick,
|
||||
onShopButtonClick = config.onShopButtonClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class StoriesScreenContentConfig(
|
||||
val storiesSize: Int,
|
||||
val currentStoryIndex: Int,
|
||||
val currentStory: Stories,
|
||||
val isScanInProgress: Boolean,
|
||||
val onGoToPreviousStory: () -> Unit = {},
|
||||
val onGoToNextStory: () -> Unit = {},
|
||||
val onSearchTokensClick: () -> Unit = {},
|
||||
val onScanButtonClick: () -> Unit = {},
|
||||
val onShopButtonClick: () -> Unit = {},
|
||||
)
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun StoriesScreenContentPreview(
|
||||
@PreviewParameter(StoriesScreenContentConfigProvider::class) config: StoriesScreenContentConfig,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
StoriesScreenContent(config = config)
|
||||
}
|
||||
}
|
||||
|
||||
private class StoriesScreenContentConfigProvider : CollectionPreviewParameterProvider<StoriesScreenContentConfig>(
|
||||
collection = listOf(
|
||||
StoriesScreenContentConfig(
|
||||
storiesSize = 6,
|
||||
currentStoryIndex = 0,
|
||||
currentStory = Stories.TangemIntro,
|
||||
isScanInProgress = true,
|
||||
),
|
||||
StoriesScreenContentConfig(
|
||||
storiesSize = 6,
|
||||
currentStoryIndex = 1,
|
||||
currentStory = Stories.RevolutionaryWallet,
|
||||
isScanInProgress = false,
|
||||
),
|
||||
StoriesScreenContentConfig(
|
||||
storiesSize = 6,
|
||||
currentStoryIndex = 2,
|
||||
currentStory = Stories.UltraSecureBackup,
|
||||
isScanInProgress = false,
|
||||
),
|
||||
StoriesScreenContentConfig(
|
||||
storiesSize = 6,
|
||||
currentStoryIndex = 3,
|
||||
currentStory = Stories.Currencies,
|
||||
isScanInProgress = false,
|
||||
),
|
||||
StoriesScreenContentConfig(
|
||||
storiesSize = 6,
|
||||
currentStoryIndex = 4,
|
||||
currentStory = Stories.Web3,
|
||||
isScanInProgress = false,
|
||||
),
|
||||
StoriesScreenContentConfig(
|
||||
storiesSize = 6,
|
||||
currentStoryIndex = 5,
|
||||
currentStory = Stories.WalletForEveryone,
|
||||
isScanInProgress = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
// endregion Preview
|
||||
Loading…
Add table
Add a link
Reference in a new issue