From 552e8cc7526ce547aa72068acf3fec3f40a006f1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 5 Apr 2023 15:06:54 +0800 Subject: [PATCH 01/30] Updated on 2026-08-14 --- app/build.gradle.kts | 1 + .../tokens/presentation/ui/AddTokensScreen.kt | 223 +++++++++++++ .../presentation/ui/AddTokensToolbar.kt | 207 +++++++++++++ .../presentation/ui/BriefNetworksList.kt | 82 +++++ .../presentation/ui/DetailedNetworksList.kt | 168 ++++++++++ .../presentation/ui/NetworkItemArrow.kt | 60 ++++ .../tokens/presentation/ui/TokenItem.kt | 292 ++++++++++++++++++ .../compose/currencyItem/CurrencyItemArrow.kt | 89 ------ .../ui/compose/currencyItem/NetworkItem.kt | 7 +- app/src/main/res/drawable/ic_back_24.xml | 9 + .../com/tangem/core/ui/res/TangemDimens.kt | 4 + plugins/configuration/detekt.yml | 2 +- 12 files changed, 1051 insertions(+), 93 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/NetworkItemArrow.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemArrow.kt create mode 100644 app/src/main/res/drawable/ic_back_24.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3e26bcc1f8..85f77c58ce 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -45,6 +45,7 @@ dependencies { implementation(deps.lifecycle.viewModel.ktx) /** Compose libraries */ + implementation(deps.compose.constraintLayout) implementation(deps.compose.material) implementation(deps.compose.animation) implementation(deps.compose.foundation) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt new file mode 100644 index 0000000000..e2098944a0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt @@ -0,0 +1,223 @@ +package com.tangem.tap.features.tokens.presentation.ui + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.PrimaryButton +import com.tangem.core.ui.res.TangemColorPalette +import com.tangem.core.ui.res.TangemTheme +import com.tangem.tap.common.compose.extensions.OnBottomReached +import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemState +import com.tangem.tap.features.tokens.presentation.states.AddTokensStateHolder +import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState +import com.tangem.tap.features.tokens.presentation.states.TokenItemModel +import com.tangem.tap.features.tokens.presentation.states.TokensListVisibility +import com.tangem.tap.features.tokens.redux.TokensAction +import com.tangem.tap.store +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +@Composable +internal fun AddTokensScreen(stateHolder: AddTokensStateHolder) { + BackHandler(onBack = stateHolder.toolbarState.onBackButtonClick) + + Scaffold( + topBar = { AddTokensToolbar(state = stateHolder.toolbarState) }, + floatingActionButton = { + if (stateHolder is AddTokensStateHolder.ManageAccess) { + SaveChangesButton(onClick = stateHolder.onSaveButtonClick) + } + }, + ) { + when (stateHolder) { + is AddTokensStateHolder.Loading -> LoadingContent() + is TokensListVisibility -> TokensListContent(stateHolder = stateHolder, scaffoldPadding = it) + } + } +} + +@Composable +private fun LoadingContent() { + Box( + modifier = Modifier + .fillMaxSize() + .background(color = TangemColorPalette.White), + contentAlignment = Alignment.Center, + ) { + CircularProgressIndicator(color = TangemColorPalette.Meadow) + } +} + +@Composable +private fun TokensListContent(stateHolder: TokensListVisibility, scaffoldPadding: PaddingValues) { + val state = rememberLazyListState() + state.OnBottomReached(loadMoreThreshold = 40) { + store.dispatch(TokensAction.LoadMore(scanResponse = store.state.globalState.scanResponse)) + } + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(scaffoldPadding), + state, + ) { + items( + items = stateHolder.tokens, + key = TokenItemModel::name, + itemContent = { TokenItem(model = it) }, + ) + } +} + +@Composable +private fun SaveChangesButton(onClick: () -> Unit) { + PrimaryButton( + modifier = Modifier + .imePadding() + .padding(horizontal = TangemTheme.dimens.spacing16) + .fillMaxWidth(), + text = stringResource(id = R.string.common_save_changes), + onClick = onClick, + ) +} + +@Preview +@Composable +private fun Preview_AddTokensScreen_Loading() { + TangemTheme { + AddTokensScreen( + stateHolder = AddTokensStateHolder.Loading( + toolbarState = AddTokensToolbarState.Title.EditAccess( + titleResId = R.string.main_manage_tokens, + onBackButtonClick = {}, + onSearchButtonClick = {}, + onAddCustomTokenClick = {}, + ), + ), + ) + } +} + +@Preview +@Composable +private fun Preview_AddTokensScreen_ManageAccess() { + TangemTheme { + AddTokensScreen( + stateHolder = AddTokensStateHolder.ManageAccess( + toolbarState = AddTokensToolbarState.Title.EditAccess( + titleResId = R.string.main_manage_tokens, + onBackButtonClick = {}, + onSearchButtonClick = {}, + onAddCustomTokenClick = {}, + ), + tokens = listOf( + TokenItemModel( + name = "ETHEREUM (ETH)", + iconUrl = "", + networks = listOf( + AddTokensNetworkItemState.EditAccess( + name = "ETHEREUM", + protocolName = "MAIN", + iconResId = R.drawable.img_btc_22, + isMainNetwork = true, + isAdded = true, + networkId = "", + onToggleClick = {}, + ), + ), + ), + TokenItemModel( + name = "Tether (USDT)", + iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", + networks = listOf( + AddTokensNetworkItemState.EditAccess( + name = "ETHEREUM", + protocolName = "MAIN", + iconResId = R.drawable.img_eth_22, + isMainNetwork = false, + isAdded = true, + networkId = "", + onToggleClick = {}, + ), + AddTokensNetworkItemState.EditAccess( + name = "BNB SMART CHAIN", + protocolName = "BEP20", + iconResId = R.drawable.ic_bsc_no_color, + isMainNetwork = false, + isAdded = false, + networkId = "", + onToggleClick = {}, + ), + ), + ), + ), + onSaveButtonClick = {}, + ), + ) + } +} + +@Preview +@Composable +private fun Preview_AddTokensScreen_ReadAccess() { + TangemTheme { + AddTokensScreen( + stateHolder = AddTokensStateHolder.ReadAccess( + toolbarState = AddTokensToolbarState.Title.EditAccess( + titleResId = R.string.search_tokens_title, + onBackButtonClick = {}, + onSearchButtonClick = {}, + onAddCustomTokenClick = {}, + ), + tokens = listOf( + TokenItemModel( + name = "ETHEREUM (ETH)", + iconUrl = "", + networks = listOf( + AddTokensNetworkItemState.ReadAccess( + name = "ETHEREUM", + protocolName = "MAIN", + iconResId = R.drawable.img_btc_22, + isMainNetwork = true, + ), + ), + ), + TokenItemModel( + name = "Tether (USDT)", + iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", + networks = listOf( + AddTokensNetworkItemState.ReadAccess( + name = "ETHEREUM", + protocolName = "MAIN", + iconResId = R.drawable.img_eth_22, + isMainNetwork = false, + ), + AddTokensNetworkItemState.ReadAccess( + name = "BNB SMART CHAIN", + protocolName = "BEP20", + iconResId = R.drawable.ic_bsc_no_color, + isMainNetwork = false, + ), + ), + ), + ), + ), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt new file mode 100644 index 0000000000..b8c160fa6e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt @@ -0,0 +1,207 @@ +package com.tangem.tap.features.tokens.presentation.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.sp +import com.tangem.core.ui.res.TangemTheme +import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState +import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState.SearchInputField +import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState.Title +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +@Composable +internal fun AddTokensToolbar(state: AddTokensToolbarState) { + TopAppBar(backgroundColor = TangemTheme.colors.background.secondary) { + IconButton(onClick = state.onBackButtonClick) { + Icon( + painter = painterResource(id = R.drawable.ic_back_24), + contentDescription = "Go back", + tint = TangemTheme.colors.icon.secondary, + ) + } + + val contentModifier = Modifier + .weight(1f) + .padding(horizontal = TangemTheme.dimens.spacing16) + .padding(bottom = TangemTheme.dimens.spacing4) + + when (state) { + is Title -> TitleContent(state = state, modifier = contentModifier) + is SearchInputField -> InputContent(state = state, modifier = contentModifier) + } + } +} + +@Composable +private fun TitleContent(state: Title, modifier: Modifier = Modifier) { + Text( + text = stringResource(id = state.titleResId), + modifier = modifier, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + style = TangemTheme.typography.h3, + ) + + IconButton(onClick = state.onSearchButtonClick) { + Icon( + painter = painterResource(id = R.drawable.ic_search_24), + contentDescription = "Search", + tint = TangemTheme.colors.icon.secondary, + ) + } + + if (state is Title.EditAccess) { + IconButton(onClick = state.onAddCustomTokenClick) { + Icon( + painter = painterResource(id = R.drawable.ic_plus_24), + contentDescription = "Add custom token", + tint = TangemTheme.colors.icon.secondary, + ) + } + } +} + +@Composable +fun InputContent(state: SearchInputField, modifier: Modifier = Modifier) { + BasicTextField( + value = state.value, + onValueChange = state.onValueChange, + modifier = modifier, + textStyle = TangemTheme.typography.subtitle1.copy(fontWeight = FontWeight.Normal), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Search), + keyboardActions = KeyboardActions(onSearch = { state.onSearchButtonClick() }), + singleLine = true, + maxLines = 1, + cursorBrush = SolidColor(value = TangemTheme.colors.stroke.secondary), + ) { innerTextField -> + Column(modifier = Modifier.padding(top = TangemTheme.dimens.spacing6)) { + Row(verticalAlignment = Alignment.CenterVertically) { + Box( + modifier = Modifier + .weight(1f) + .padding(start = TangemTheme.dimens.spacing6), + ) { + Hint(value = state.value) + innerTextField() + } + + IconButton(onClick = state.onCleanButtonClick) { + Icon( + painter = painterResource(id = R.drawable.ic_cross_rounded_24), + contentDescription = "Clean entered value", + tint = TangemTheme.colors.icon.secondary, + ) + } + } + + Box( + modifier = Modifier + .fillMaxWidth() + .height(height = TangemTheme.dimens.size1) + .background(color = TangemTheme.colors.stroke.primary), + ) + } + } +} + +@Composable +private fun Hint(value: String) { + if (value.isBlank()) { + Row( + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4), + horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing4), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + painter = painterResource(id = R.drawable.ic_search_24), + contentDescription = null, + tint = TangemTheme.colors.icon.secondary, + ) + Text( + text = stringResource(id = R.string.common_search), + modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing2), + color = TangemTheme.colors.text.tertiary, + maxLines = 1, + // FIXME("Incorrect typography. Replace with typography from design system") + style = TangemTheme.typography.subtitle1.copy(fontSize = 18.sp, fontWeight = FontWeight.Normal), + ) + } + } +} + +@Preview +@Composable +private fun Preview_AddTokensToolbar_EditAccess() { + TangemTheme { + AddTokensToolbar( + state = Title.EditAccess( + titleResId = R.string.main_manage_tokens, + onBackButtonClick = {}, + onSearchButtonClick = {}, + onAddCustomTokenClick = {}, + ), + ) + } +} + +@Preview +@Composable +private fun Preview_AddTokensToolbar_ReadAccess() { + TangemTheme { + AddTokensToolbar( + state = Title.ReadAccess( + titleResId = R.string.search_tokens_title, + onBackButtonClick = {}, + onSearchButtonClick = {}, + ), + ) + } +} + +@Preview +@Composable +private fun Preview_AddTokensToolbar_SearchInputField() { + var value by remember { mutableStateOf("") } + + TangemTheme { + AddTokensToolbar( + state = SearchInputField( + onBackButtonClick = {}, + onSearchButtonClick = {}, + value = value, + onValueChange = { value = it }, + onCleanButtonClick = { value = "" }, + ), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt new file mode 100644 index 0000000000..868395a094 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt @@ -0,0 +1,82 @@ +package com.tangem.tap.features.tokens.presentation.ui + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.key +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import com.tangem.core.ui.res.TangemColorPalette +import com.tangem.core.ui.res.TangemTheme +import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemState + +/** +[REDACTED_AUTHOR] + */ +@Composable +internal fun BriefNetworksList( + isCollapsed: Boolean, + networks: List, + modifier: Modifier = Modifier, +) { + AnimatedVisibility( + visible = isCollapsed, + modifier = modifier, + enter = fadeIn() + expandVertically(), + exit = shrinkVertically() + fadeOut(), + ) { + if (isCollapsed) { + Row(horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4)) { + networks.forEach { + key(it.name) { + BriefNetworkItem(model = it) + } + } + } + } + } +} + +/** +[REDACTED_AUTHOR] + */ +@Composable +internal fun BriefNetworkItem(model: AddTokensNetworkItemState) { + Box(modifier = Modifier.size(size = TangemTheme.dimens.size20)) { + Image( + painter = painterResource(id = model.iconResId), + contentDescription = null, + modifier = Modifier.size(size = TangemTheme.dimens.size20), + ) + + if (model.isMainNetwork) { + Box( + modifier = Modifier + .align(Alignment.TopEnd) + .size(TangemTheme.dimens.size7) + .clip(CircleShape) + .background(TangemColorPalette.White), + contentAlignment = Alignment.Center, + ) { + Box( + modifier = Modifier + .size(TangemTheme.dimens.size5) + .clip(CircleShape) + .background(TangemColorPalette.Meadow), + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt new file mode 100644 index 0000000000..1ad714408f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt @@ -0,0 +1,168 @@ +package com.tangem.tap.features.tokens.presentation.ui + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material.Switch +import androidx.compose.material.SwitchDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.key +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.sp +import com.tangem.core.ui.res.TangemColorPalette +import com.tangem.core.ui.res.TangemTheme +import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemState +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +@Composable +internal fun DetailedNetworksList( + isExpanded: Boolean, + networks: List, + modifier: Modifier = Modifier, +) { + AnimatedVisibility( + visible = isExpanded, + modifier = modifier, + enter = fadeIn() + expandVertically(), + exit = shrinkVertically() + fadeOut(), + ) { + if (isExpanded) { + Column { + networks.forEachIndexed { index, network -> + key(network.name) { + DetailedNetworkItem(model = network, isLastItem = networks.lastIndex == index) + } + } + } + } + } +} + +@Composable +private fun DetailedNetworkItem(model: AddTokensNetworkItemState, isLastItem: Boolean) { + val itemHeight = TangemTheme.dimens.size50 + Row( + modifier = Modifier + .fillMaxWidth() + .heightIn(min = itemHeight) + .padding(start = TangemTheme.dimens.spacing38), + verticalAlignment = Alignment.CenterVertically, + ) { + NetworkItemArrow(itemHeight = itemHeight, isLastItem = isLastItem) + Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing14)) + BriefNetworkItem(model = model) + Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing6)) + NetworkTitle(model = model) + + if (model is AddTokensNetworkItemState.EditAccess) { + Switch( + checked = model.isAdded, + onCheckedChange = { model.onToggleClick(model.networkId) }, + modifier = Modifier.padding(start = TangemTheme.dimens.spacing16, end = TangemTheme.dimens.spacing8), + colors = SwitchDefaults.colors( + checkedThumbColor = TangemColorPalette.Meadow, + ), + ) + } + } +} + +@Composable +private fun RowScope.NetworkTitle(model: AddTokensNetworkItemState) { + Text( + modifier = Modifier.weight(1f), + text = buildAnnotatedString { + append(text = model.name) + append(text = " ") + withStyle( + style = SpanStyle( + fontWeight = FontWeight.Normal, + color = if (model.isMainNetwork) TangemColorPalette.Meadow else TangemColorPalette.Dark2, + ), + ) { + append(text = model.protocolName) + } + }, + fontWeight = FontWeight.SemiBold, + fontSize = 13.sp, + color = if (model is AddTokensNetworkItemState.EditAccess && model.isAdded) { + TangemColorPalette.Black + } else { + TangemColorPalette.Dark2 + }, + ) +} + +@Preview +@Composable +private fun Preview_DetailedNetworksList_EditAccess() { + TangemTheme { + DetailedNetworksList( + networks = listOf( + AddTokensNetworkItemState.EditAccess( + name = "ETHEREUM", + protocolName = "MAIN", + iconResId = R.drawable.ic_eth_no_color, + isMainNetwork = true, + isAdded = true, + networkId = "", + onToggleClick = {}, + ), + AddTokensNetworkItemState.EditAccess( + name = "BNB SMART CHAIN", + protocolName = "BEP20", + iconResId = R.drawable.ic_bsc_no_color, + isMainNetwork = false, + isAdded = false, + networkId = "", + onToggleClick = {}, + ), + ), + isExpanded = false, + ) + } +} + +@Preview +@Composable +private fun Preview_DetailedNetworksList_ReadAccess() { + TangemTheme { + DetailedNetworksList( + networks = listOf( + AddTokensNetworkItemState.ReadAccess( + name = "ETHEREUM", + protocolName = "MAIN", + iconResId = R.drawable.ic_eth_no_color, + isMainNetwork = true, + ), + AddTokensNetworkItemState.ReadAccess( + name = "BNB SMART CHAIN", + protocolName = "BEP20", + iconResId = R.drawable.ic_bsc_no_color, + isMainNetwork = false, + ), + ), + isExpanded = false, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/NetworkItemArrow.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/NetworkItemArrow.kt new file mode 100644 index 0000000000..5aadb66fa1 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/NetworkItemArrow.kt @@ -0,0 +1,60 @@ +package com.tangem.tap.features.tokens.presentation.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.res.TangemTheme +import com.tangem.wallet.R + +private const val SPECIAL_HEIGHT_3_5 = 3.5 + +/** +[REDACTED_AUTHOR] + */ +@Composable +internal fun NetworkItemArrow(itemHeight: Dp, isLastItem: Boolean) { + Box(modifier = Modifier.height(height = itemHeight)) { + if (!isLastItem) { + Box( + modifier = Modifier + .padding(start = TangemTheme.dimens.spacing0_5) + .background(color = TangemTheme.colors.stroke.primary) + .size(width = TangemTheme.dimens.size1, height = itemHeight), + ) + } + + Icon( + painter = painterResource(id = R.drawable.ic_link), + contentDescription = null, + modifier = Modifier.height(height = itemHeight / 2 + SPECIAL_HEIGHT_3_5.dp), + tint = TangemTheme.colors.stroke.primary, + ) + } +} + +@Preview +@Composable +private fun Preview_NetworkItemArrow_Column() { + TangemTheme { + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = TangemTheme.colors.background.primary) + .padding(start = TangemTheme.dimens.size36), + ) { + NetworkItemArrow(itemHeight = TangemTheme.dimens.size62, isLastItem = false) + NetworkItemArrow(itemHeight = TangemTheme.dimens.size62, isLastItem = true) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt new file mode 100644 index 0000000000..10b261d68b --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt @@ -0,0 +1,292 @@ +package com.tangem.tap.features.tokens.presentation.ui + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.animation.with +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.constraintlayout.compose.ConstraintLayout +import androidx.constraintlayout.compose.Dimension +import coil.compose.SubcomposeAsyncImage +import coil.request.ImageRequest +import com.tangem.core.ui.res.TangemTheme +import com.tangem.tap.common.compose.extensions.toPx +import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemState +import com.tangem.tap.features.tokens.presentation.states.TokenItemModel +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +@Composable +internal fun TokenItem(model: TokenItemModel) { + var isExpanded by remember { mutableStateOf(false) } + + ConstraintLayout( + modifier = Modifier + .fillMaxWidth() + .padding(top = TangemTheme.dimens.spacing16), + ) { + val (icon, title, availableNetworksText) = createRefs() + val (briefNetworksList, detailedNetworksList, changeNetworksViewButton) = createRefs() + + val spacing16 = TangemTheme.dimens.spacing16 + val spacing6 = TangemTheme.dimens.spacing6 + + Icon( + name = model.name, + iconUrl = model.iconUrl, + modifier = Modifier.constrainAs(icon) { + top.linkTo(parent.top) + start.linkTo(anchor = parent.start, margin = spacing16) + }, + ) + + Title( + title = model.name, + modifier = Modifier.constrainAs(title) { + top.linkTo(parent.top) + start.linkTo(icon.end, margin = spacing16) + end.linkTo(anchor = changeNetworksViewButton.start, margin = spacing16) + width = Dimension.fillToConstraints + }, + ) + + Subtitle( + isExpanded = isExpanded, + modifier = Modifier.constrainAs(availableNetworksText) { + top.linkTo(title.bottom, margin = spacing6) + start.linkTo(icon.end, margin = spacing16) + end.linkTo(anchor = changeNetworksViewButton.start, margin = spacing16) + width = Dimension.fillToConstraints + }, + ) + + BriefNetworksList( + isCollapsed = !isExpanded, + networks = model.networks, + modifier = Modifier.constrainAs(briefNetworksList) { + top.linkTo(title.bottom, margin = spacing6) + start.linkTo(icon.end, margin = spacing16) + end.linkTo(anchor = changeNetworksViewButton.start, margin = spacing16) + width = Dimension.fillToConstraints + }, + ) + + DetailedNetworksList( + isExpanded = isExpanded, + networks = model.networks, + modifier = Modifier.constrainAs(detailedNetworksList) { + top.linkTo(anchor = availableNetworksText.bottom, margin = spacing16) + centerHorizontallyTo(parent) + width = Dimension.fillToConstraints + }, + ) + + ChangeNetworksViewButton( + isExpanded = isExpanded, + onClick = { isExpanded = !isExpanded }, + modifier = Modifier.constrainAs(changeNetworksViewButton) { + top.linkTo(parent.top) + end.linkTo(anchor = parent.end, margin = spacing16) + if (!isExpanded) bottom.linkTo(parent.bottom) + }, + ) + } +} + +@Composable +private fun Icon(name: String, iconUrl: String, modifier: Modifier = Modifier) { + val iconModifier = modifier.size(size = TangemTheme.dimens.size46) + + SubcomposeAsyncImage( + modifier = iconModifier, + model = ImageRequest.Builder(context = LocalContext.current) + .size(size = TangemTheme.dimens.size46.toPx().toInt()) + .data(data = iconUrl) + .crossfade(enable = true) + .build(), + contentDescription = null, + loading = { PlaceholderIcon(name = name, modifier = iconModifier) }, + error = { PlaceholderIcon(name = name, modifier = iconModifier) }, + ) +} + +@Composable +private fun PlaceholderIcon(name: String, modifier: Modifier = Modifier) { + Box( + contentAlignment = Alignment.Center, + modifier = modifier.background(TangemTheme.colors.icon.primary1, shape = CircleShape), + ) { + Text( + text = name.firstOrNull()?.titlecase() ?: "", + color = TangemTheme.colors.icon.primary2, + maxLines = 1, + // FIXME("Incorrect typography. Replace with typography from design system") + style = TangemTheme.typography.h3.copy(fontWeight = FontWeight.Bold), + ) + } +} + +@Composable +private fun Title(title: String, modifier: Modifier = Modifier) { + Text( + text = title, + modifier = modifier, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Start, + maxLines = 1, + style = TangemTheme.typography.body1, + ) +} + +@Composable +private fun Subtitle(isExpanded: Boolean, modifier: Modifier = Modifier) { + AnimatedVisibility( + visible = isExpanded, + modifier = modifier, + enter = fadeIn() + expandVertically(), + exit = shrinkVertically() + fadeOut(), + ) { + Text( + text = stringResource(id = R.string.currency_subtitle_expanded), + color = TangemTheme.colors.text.secondary, + maxLines = 1, + style = TangemTheme.typography.body2, + ) + } +} + +@OptIn(ExperimentalAnimationApi::class) +@Composable +private fun ChangeNetworksViewButton( + isExpanded: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + IconButton(onClick = onClick, modifier = modifier.size(size = TangemTheme.dimens.size46)) { + AnimatedContent( + targetState = isExpanded, + transitionSpec = { fadeIn() + scaleIn() with scaleOut() + fadeOut() }, + ) { isExpanded -> + Icon( + painter = painterResource( + id = if (isExpanded) R.drawable.ic_arrow_extended else R.drawable.ic_arrow_collapsed, + ), + contentDescription = null, + tint = TangemTheme.colors.icon.secondary, + ) + } + } +} + +@Preview +@Composable +private fun Preview_TokenItem_EditAccess() { + TangemTheme { + TokenItem( + TokenItemModel( + name = "Tether (USDT)", + iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", + networks = listOf( + AddTokensNetworkItemState.EditAccess( + name = "Ethereum", + protocolName = "MAIN", + iconResId = R.drawable.ic_eth_no_color, + isMainNetwork = true, + isAdded = true, + networkId = "", + onToggleClick = {}, + ), + AddTokensNetworkItemState.EditAccess( + name = "BNB SMART CHAIN", + protocolName = "BEP20", + iconResId = R.drawable.ic_bsc_no_color, + isMainNetwork = false, + isAdded = false, + networkId = "", + onToggleClick = {}, + ), + ), + ), + ) + } +} + +@Preview +@Composable +private fun Preview_TokenItem_ReadAccess() { + TangemTheme { + TokenItem( + TokenItemModel( + name = "Tether (USDT)", + iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", + networks = listOf( + AddTokensNetworkItemState.ReadAccess( + name = "Ethereum", + protocolName = "MAIN", + iconResId = R.drawable.ic_eth_no_color, + isMainNetwork = true, + ), + AddTokensNetworkItemState.ReadAccess( + name = "BNB SMART CHAIN", + protocolName = "BEP20", + iconResId = R.drawable.ic_bsc_no_color, + isMainNetwork = false, + ), + ), + ), + ) + } +} + +@Preview +@Composable +private fun Preview_TokenItem_EditAccess_LargeNetworkList() { + TangemTheme { + TokenItem( + TokenItemModel( + name = "Tether (USDT)", + iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", + networks = List( + size = 15, + init = { + AddTokensNetworkItemState.ReadAccess( + name = if (it % 2 != 0) "Ethereum" else "BNB SMART CHAIN", + protocolName = if (it % 2 != 0) "MAIN" else "BEP20", + iconResId = if (it % 2 != 0) R.drawable.ic_eth_no_color else R.drawable.ic_bsc_no_color, + isMainNetwork = it % 2 != 0, + ) + }, + ), + ), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemArrow.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemArrow.kt deleted file mode 100644 index 3c0c5655cc..0000000000 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemArrow.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.tangem.tap.features.tokens.ui.compose.currencyItem - -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import com.tangem.wallet.R - -/** -[REDACTED_AUTHOR] - */ -@Composable -fun CurrencyItemArrow( - rowHeight: Dp, - isLastArrow: Boolean, -) { - Box(Modifier.height(rowHeight)) { - if (!isLastArrow) { - MiddleArrowView(rowHeight) - } else { - LastArrowView(rowHeight) - } - } -} - -@Suppress("MagicNumber") -@Composable -private fun MiddleArrowView(rowHeight: Dp) { - Box { - Box( - modifier = Modifier - .padding(start = 0.5.dp), - ) { - Box( - modifier = Modifier - .background(color = Color(0xFFDEDEDE)) - .width(0.8.dp) - .fillMaxHeight(), - ) - } - - LastArrowView(rowHeight) - } -} - -@Composable -private fun LastArrowView(rowHeight: Dp) { - Image( - modifier = Modifier - .height(rowHeight / 2 + 3.5.dp), - painter = painterResource(id = R.drawable.ic_link), - contentDescription = null, - ) -} - -@Preview -@Composable -private fun ArrowViewPreview() { - Box(Modifier.background(color = Color.White)) { - Column( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(start = 37.dp), - ) { - CurrencyItemArrow( - rowHeight = 62.dp, - isLastArrow = false, - ) - CurrencyItemArrow( - rowHeight = 62.dp, - isLastArrow = true, - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt index cf744085ba..bff5cc2247 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt @@ -37,6 +37,7 @@ import com.tangem.tap.common.extensions.getGreyedOutIconRes import com.tangem.tap.common.extensions.getNetworkName import com.tangem.tap.domain.tokens.Contract import com.tangem.tap.domain.tokens.Currency +import com.tangem.tap.features.tokens.presentation.ui.NetworkItemArrow import com.tangem.tap.features.tokens.redux.ContractAddress import com.tangem.tap.features.tokens.redux.TokenWithBlockchain import com.tangem.tap.features.tokens.ui.compose.CurrencyPlaceholderIcon @@ -76,9 +77,9 @@ fun NetworkItem( .width(78.dp) .padding(start = 38.dp), ) { - CurrencyItemArrow( - rowHeight = rowHeight, - isLastArrow = index == size - 1, + NetworkItemArrow( + itemHeight = rowHeight, + isLastItem = index == size - 1, ) } Box( diff --git a/app/src/main/res/drawable/ic_back_24.xml b/app/src/main/res/drawable/ic_back_24.xml new file mode 100644 index 0000000000..fd06de4ca4 --- /dev/null +++ b/app/src/main/res/drawable/ic_back_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt index a681a0239b..26189619df 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt @@ -32,8 +32,11 @@ data class TangemDimens internal constructor( // region Size val size0: Dp = 0.dp, val size0_5: Dp = 0.5.dp, + val size1: Dp = 1.dp, val size2: Dp = 2.dp, val size4: Dp = 4.dp, + val size5: Dp = 5.dp, + val size7: Dp = 7.dp, val size8: Dp = 8.dp, val size11: Dp = 11.dp, val size12: Dp = 12.dp, @@ -80,6 +83,7 @@ data class TangemDimens internal constructor( val spacing28: Dp = 28.dp, val spacing32: Dp = 32.dp, val spacing34: Dp = 34.dp, + val spacing38: Dp = 38.dp, val spacing44: Dp = 44.dp, val spacing50: Dp = 50.dp, val spacing52: Dp = 52.dp, diff --git a/plugins/configuration/detekt.yml b/plugins/configuration/detekt.yml index f26f48c71c..434aed89be 100644 --- a/plugins/configuration/detekt.yml +++ b/plugins/configuration/detekt.yml @@ -84,7 +84,7 @@ complexity: threshold: 300 LongMethod: active: true - threshold: 60 + threshold: 70 LongParameterList: active: true functionThreshold: 6 From 069605e151f23f15d3a82749e378c0f7e972a599 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 6 Apr 2023 22:57:30 +0800 Subject: [PATCH 02/30] Updated on 2026-08-14 --- app/build.gradle.kts | 7 ++- .../java/com/tangem/tap/TapApplication.kt | 5 ++ .../tap/common/extensions/Navigation.kt | 10 +++- .../TokensListFeatureToggles.kt | 12 +++++ .../di/TokensListFeatureTogglesModule.kt | 24 +++++++++ .../DefaultTokensListFeatureToggles.kt | 19 +++++++ .../tokens/presentation/TokensListFragment.kt | 49 +++++++++++++++++++ .../tap/proxy/redux/DaggerGraphAction.kt | 2 + .../tap/proxy/redux/DaggerGraphReducer.kt | 1 + .../tap/proxy/redux/DaggerGraphState.kt | 2 + .../configs/feature_toggles_config.json | 4 ++ 11 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/api/featuretoggles/TokensListFeatureToggles.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/di/TokensListFeatureTogglesModule.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/featuretoggles/DefaultTokensListFeatureToggles.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 85f77c58ce..9d6381ca2f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,11 +48,14 @@ dependencies { implementation(deps.compose.constraintLayout) implementation(deps.compose.material) implementation(deps.compose.animation) + implementation(deps.compose.coil) + implementation(deps.compose.constraintLayout) implementation(deps.compose.foundation) + implementation(deps.compose.material) + implementation(deps.compose.navigation.hilt) + implementation(deps.compose.shimmer) implementation(deps.compose.ui) implementation(deps.compose.ui.tooling) - implementation(deps.compose.coil) - implementation(deps.compose.shimmer) /** Firebase libraries */ implementation(platform(deps.firebase.bom)) diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index de10af7d92..87f540fc6b 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -49,6 +49,7 @@ import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository import com.tangem.tap.domain.walletStores.repository.di.provideDefaultImplementation import com.tangem.tap.domain.walletconnect.WalletConnectRepository +import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles import com.tangem.tap.persistence.PreferencesStorage import com.tangem.tap.proxy.AppStateHolder import com.tangem.tap.proxy.redux.DaggerGraphAction @@ -126,6 +127,9 @@ class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var networkConnectionManager: NetworkConnectionManager + @Inject + lateinit var tokensListFeatureToggles: TokensListFeatureToggles + override fun onCreate() { super.onCreate() @@ -174,6 +178,7 @@ class TapApplication : Application(), ImageLoaderFactory { action = DaggerGraphAction.SetApplicationDependencies( assetReader = assetReader, networkConnectionManager = networkConnectionManager, + tokensListFeatureToggles = tokensListFeatureToggles, ), ) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index 0755764b78..f6e77e9af9 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -27,10 +27,13 @@ import com.tangem.tap.features.send.ui.SendFragment import com.tangem.tap.features.shop.ui.ShopFragment import com.tangem.tap.features.tokens.addCustomToken.AddCustomTokenFragment import com.tangem.tap.features.tokens.presentation.AddTokensFragment +import com.tangem.tap.features.tokens.presentation.TokensListFragment import com.tangem.tap.features.wallet.ui.WalletDetailsFragment import com.tangem.tap.features.wallet.ui.WalletFragment import com.tangem.tap.features.walletSelector.ui.WalletSelectorBottomSheetFragment import com.tangem.tap.features.welcome.ui.WelcomeFragment +import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.store import com.tangem.wallet.R import timber.log.Timber @@ -107,7 +110,12 @@ private fun fragmentFactory(screen: AppScreen): Fragment { AppScreen.AppSettings -> AppSettingsFragment() AppScreen.ResetToFactory -> ResetCardFragment() AppScreen.Disclaimer -> DisclaimerFragment() - AppScreen.AddTokens -> AddTokensFragment() + AppScreen.AddTokens -> { + val featureToggles = store.state.daggerGraphState.get( + getDependency = DaggerGraphState::tokensListFeatureToggles, + ) + if (featureToggles.isRedesignedScreenEnabled) TokensListFragment() else AddTokensFragment() + } AppScreen.AddCustomToken -> AddCustomTokenFragment() AppScreen.WalletDetails -> WalletDetailsFragment() AppScreen.WalletConnectSessions -> WalletConnectFragment() diff --git a/app/src/main/java/com/tangem/tap/features/tokens/api/featuretoggles/TokensListFeatureToggles.kt b/app/src/main/java/com/tangem/tap/features/tokens/api/featuretoggles/TokensListFeatureToggles.kt new file mode 100644 index 0000000000..286eb6d0e0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/api/featuretoggles/TokensListFeatureToggles.kt @@ -0,0 +1,12 @@ +package com.tangem.tap.features.tokens.api.featuretoggles + +/** + * TokensList feature toggles + * +[REDACTED_AUTHOR] + */ +interface TokensListFeatureToggles { + + /** Availability of redesigned screen (internal feature) */ + val isRedesignedScreenEnabled: Boolean +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListFeatureTogglesModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListFeatureTogglesModule.kt new file mode 100644 index 0000000000..be1a69cc5b --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListFeatureTogglesModule.kt @@ -0,0 +1,24 @@ +package com.tangem.tap.features.tokens.di + +import com.tangem.core.featuretoggle.manager.FeatureTogglesManager +import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles +import com.tangem.tap.features.tokens.featuretoggles.DefaultTokensListFeatureToggles +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +/** +[REDACTED_AUTHOR] + */ +@Module +@InstallIn(SingletonComponent::class) +internal object TokensListFeatureTogglesModule { + + @Provides + @Singleton + fun providesTokensListFeatureToggles(featureTogglesManager: FeatureTogglesManager): TokensListFeatureToggles { + return DefaultTokensListFeatureToggles(featureTogglesManager) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/featuretoggles/DefaultTokensListFeatureToggles.kt b/app/src/main/java/com/tangem/tap/features/tokens/featuretoggles/DefaultTokensListFeatureToggles.kt new file mode 100644 index 0000000000..eedb10b4a9 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/featuretoggles/DefaultTokensListFeatureToggles.kt @@ -0,0 +1,19 @@ +package com.tangem.tap.features.tokens.featuretoggles + +import com.tangem.core.featuretoggle.manager.FeatureTogglesManager +import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles + +/** + * Default implementation of TokensList feature toggles + * + * @property featureTogglesManager manager for getting information about the availability of feature toggles + * +[REDACTED_AUTHOR] + */ +internal class DefaultTokensListFeatureToggles( + private val featureTogglesManager: FeatureTogglesManager, +) : TokensListFeatureToggles { + + override val isRedesignedScreenEnabled: Boolean + get() = featureTogglesManager.isFeatureEnabled(name = "REDESIGNED_TOKEN_LIST_SCREEN_ENABLED") +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt new file mode 100644 index 0000000000..85bb563548 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt @@ -0,0 +1,49 @@ +package com.tangem.tap.features.tokens.presentation + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.ui.platform.ComposeView +import androidx.core.view.WindowCompat +import androidx.fragment.app.Fragment +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.transition.TransitionInflater +import com.tangem.core.ui.res.TangemTheme +import com.tangem.tap.features.tokens.presentation.ui.AddTokensScreen +import com.tangem.tap.features.tokens.presentation.viewmodels.AddTokensViewModel +import com.tangem.wallet.R +import dagger.hilt.android.AndroidEntryPoint + +/** + * Fragment with list of tokens + * +[REDACTED_AUTHOR] + */ +@AndroidEntryPoint +internal class TokensListFragment : Fragment() { + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } + + with(TransitionInflater.from(requireContext())) { + enterTransition = inflateTransition(R.transition.fade) + exitTransition = inflateTransition(R.transition.fade) + } + + return ComposeView(inflater.context).apply { + setContent { + isTransitionGroup = true + + val viewModel = hiltViewModel().apply { + // TODO("[REDACTED_TASK_KEY] subscribe on Redux events") + // subscribeOnReduxEvents(lifecycle = LocalLifecycleOwner.current.lifecycle) + } + + TangemTheme { + AddTokensScreen(stateHolder = viewModel.uiState) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt index cd392ae831..57cdad3cf3 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt @@ -3,6 +3,7 @@ package com.tangem.tap.proxy.redux import com.tangem.datasource.asset.AssetReader import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.features.tester.api.TesterRouter +import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles import org.rekotlin.Action sealed interface DaggerGraphAction : Action { @@ -10,6 +11,7 @@ sealed interface DaggerGraphAction : Action { data class SetApplicationDependencies( val assetReader: AssetReader, val networkConnectionManager: NetworkConnectionManager, + val tokensListFeatureToggles: TokensListFeatureToggles, ) : DaggerGraphAction data class SetActivityDependencies(val testerRouter: TesterRouter) : DaggerGraphAction diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt index 34564599ac..65cfee1cf5 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt @@ -15,6 +15,7 @@ object DaggerGraphReducer { is DaggerGraphAction.SetApplicationDependencies -> state.daggerGraphState.copy( assetReader = action.assetReader, networkConnectionManager = action.networkConnectionManager, + tokensListFeatureToggles = action.tokensListFeatureToggles, ) is DaggerGraphAction.SetActivityDependencies -> state.daggerGraphState.copy( testerRouter = action.testerRouter, diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index 800182a67c..792009c602 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -3,12 +3,14 @@ package com.tangem.tap.proxy.redux import com.tangem.datasource.asset.AssetReader import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.features.tester.api.TesterRouter +import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles import org.rekotlin.StateType data class DaggerGraphState( val assetReader: AssetReader? = null, val testerRouter: TesterRouter? = null, val networkConnectionManager: NetworkConnectionManager? = null, + val tokensListFeatureToggles: TokensListFeatureToggles? = null, ) : StateType { inline fun get(getDependency: DaggerGraphState.() -> T?): T { diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json index 74e4d91915..b7661838a4 100644 --- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json @@ -2,5 +2,9 @@ { "name": "OPTIMISM_SWAP_FEATURE_ENABLED", "version": "4.3.1" + }, + { + "name": "REDESIGNED_TOKEN_LIST_SCREEN_ENABLED", + "version": "4.5.0" } ] \ No newline at end of file From 36516c900fb7b2e68cd799ea0bce90cd04643695 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 7 Apr 2023 20:39:24 +0800 Subject: [PATCH 03/30] Updated on 2026-08-14 --- .../tangem/tap/ForegroundActivityObserver.kt | 4 +- .../NavBarInsetsFragmentLifecycleCallback.kt | 7 +- .../tangem/tap/common/CompositionCounter.kt | 4 +- .../tangem/tap/common/CurrencyConverter.kt | 2 +- .../tangem/tap/common/CustomTabsManager.kt | 2 +- .../tap/common/GlobalLayoutStateHandler.kt | 2 +- .../common/analytics/TangemSdkErrorMapper.kt | 6 +- .../tap/common/analytics/events/Token.kt | 2 +- .../common/analytics/topup/TopUpController.kt | 5 +- .../com/tangem/tap/common/compose/Button.kt | 5 +- .../common/compose/ComposeDialogManager.kt | 48 +++-- .../tangem/tap/common/compose/ErrorViews.kt | 6 +- .../common/compose/OutlinedTextFieldWidget.kt | 5 +- .../tap/common/compose/PinCodeWidget.kt | 5 +- .../common/compose/TangemTextFieldsDefault.kt | 6 +- .../tangem/tap/common/compose/Undefined.kt | 7 +- .../com/tangem/tap/common/compose/Warning.kt | 10 +- .../compose/extensions/AnimatedValue.kt | 10 +- .../com/tangem/tap/common/entities/Button.kt | 2 +- .../tangem/tap/common/extensions/Activity.kt | 2 +- .../tangem/tap/common/extensions/Context.kt | 3 +- .../com/tangem/tap/common/extensions/Map.kt | 3 +- .../tangem/tap/common/extensions/Specific.kt | 9 +- .../tangem/tap/common/extensions/String.kt | 7 +- .../tap/common/extensions/Transition.kt | 2 +- .../com/tangem/tap/common/extensions/UI.kt | 11 +- .../java/com/tangem/tap/common/images/Coil.kt | 7 +- .../common/qrCodeScan/ScanQrCodeActivity.kt | 4 +- .../recyclerView/SpaceItemDecoration.kt | 9 +- .../tap/common/shop/TangemShopService.kt | 8 +- .../tap/common/shop/data/ProductType.kt | 3 +- .../tap/common/shop/data/TangemProduct.kt | 2 +- .../common/shop/googlepay/GooglePayUtil.kt | 6 +- .../tap/common/shop/shopify/ShopifyService.kt | 34 ++- .../common/shop/shopify/data/CheckoutItem.kt | 2 +- .../tap/common/snackBar/MaxAmountSnackbar.kt | 6 +- .../com/tangem/tap/domain/PayIdManager.kt | 22 +- .../com/tangem/tap/domain/TangemSdkManager.kt | 23 +- .../com/tangem/tap/domain/TangemSigner.kt | 5 +- .../warningMessage/WarningMessage.kt | 8 +- .../warningMessage/WarningMessagesManager.kt | 2 +- .../domain/extensions/WalletManagerFactory.kt | 9 +- .../model/builders/UserWalletIdBuilder.kt | 8 +- .../model/builders/WalletStoreBuilder.kt | 10 +- .../tap/domain/scanCard/ScanCardProcessor.kt | 10 +- .../tap/domain/tasks/CreateWalletsTask.kt | 2 +- .../tangem/tap/domain/tasks/SignHashTask.kt | 14 +- .../tangem/tap/domain/tasks/SignHashesTask.kt | 14 +- .../tasks/product/CreateProductWalletTask.kt | 5 +- .../domain/tasks/product/CreateWalletsTask.kt | 4 +- .../tasks/product/ProductCommandProcessor.kt | 6 +- .../product/ResetToFactorySettingsTask.kt | 10 +- .../domain/tasks/product/ScanProductTask.kt | 5 +- .../tap/domain/tokens/CurrenciesRepository.kt | 7 +- .../com/tangem/tap/domain/tokens/Currency.kt | 16 +- .../tokens/converters/CurrencyConverter.kt | 2 +- .../domain/tokens/models/ObsoleteTokenDao.kt | 2 +- .../tap/domain/tokens/models/TokenDao.kt | 2 +- .../domain/twins/CreateFirstTwinWalletTask.kt | 5 +- .../tap/domain/twins/FinalizeTwinTask.kt | 5 +- .../twins/WriteProtectedIssuerDataTask.kt | 5 +- .../DefaultSelectedUserWalletRepository.kt | 2 +- ...tUserWalletsPublicInformationRepository.kt | 6 +- ...erWalletsSensitiveInformationRepository.kt | 5 +- .../tap/domain/userWalletList/utils/Mapper.kt | 4 +- .../utils/json/ByteArrayKeyAdapter.kt | 11 +- .../utils/json/CardBackupStatusAdapter.kt | 11 +- .../WalletCurrenciesManager.kt | 20 +- .../DefaultWalletCurrenciesManager.kt | 45 ++-- .../walletStores/WalletStoresManager.kt | 14 +- .../DefaultWalletStoresManager.kt | 55 +++-- .../repository/WalletAmountsRepository.kt | 5 +- .../repository/WalletManagersRepository.kt | 5 +- .../repository/WalletStoresRepository.kt | 5 +- .../DefaultWalletAmountsRepository.kt | 201 +++++++++--------- .../DefaultWalletManagersRepository.kt | 5 +- .../utils/WalletDataOperations.kt | 30 +-- .../utils/WalletStoreOperations.kt | 25 +-- .../walletconnect/WalletConnectManager.kt | 12 +- .../com/tangem/tap/features/BaseFragment.kt | 13 +- .../details/redux/DetailsMiddleware.kt | 5 +- .../features/details/redux/DetailsReducer.kt | 22 +- .../walletconnect/WalletConnectMiddleware.kt | 6 +- .../walletconnect/WalletConnectReducer.kt | 5 +- .../redux/walletconnect/WalletConnectState.kt | 4 +- .../ui/appsettings/AppSettingsFragment.kt | 6 +- .../ui/appsettings/AppSettingsScreen.kt | 8 +- .../components/EnrollBiometricsCard.kt | 4 +- .../components/SettingsAlertDialog.kt | 4 +- .../ui/cardsettings/CardSettingsFragment.kt | 6 +- .../ui/common/DetailsComposeElements.kt | 12 +- .../details/ui/details/DetailsFragment.kt | 6 +- .../details/ui/details/DetailsScreen.kt | 5 +- .../details/ui/details/DetailsScreenState.kt | 2 +- .../details/ui/resetcard/ResetCardFragment.kt | 6 +- .../details/ui/resetcard/ResetCardScreen.kt | 4 +- .../ui/securitymode/SecurityModeFragment.kt | 6 +- .../ui/walletconnect/QrScanFragment.kt | 25 +-- .../ui/walletconnect/WalletConnectFragment.kt | 6 +- .../ui/walletconnect/WalletConnectScreen.kt | 5 +- .../dialogs/ChooseNetworkDialog.kt | 6 +- .../tap/features/disclaimer/DisclaimerType.kt | 3 +- .../disclaimer/ui/DisclaimerWebViewClient.kt | 6 +- .../tangem/tap/features/home/HomeFragment.kt | 6 +- .../tap/features/home/RegionProvider.kt | 2 +- .../features/home/compose/content/Content.kt | 22 +- .../compose/content/CurrenciesWeb3Content.kt | 10 +- .../compose/content/FirstStoriesContent.kt | 6 +- .../compose/content/FloatingCardsContent.kt | 12 +- .../home/compose/views/StoriesProgressBar.kt | 6 +- .../onboarding/OnboardingSaltPayHelper.kt | 17 +- .../products/note/OnboardingNoteFragment.kt | 41 ++-- .../redux/OnboardingWalletMiddleware.kt | 10 +- .../saltPay/SaltPayActivationManager.kt | 17 +- .../wallet/saltPay/SaltPayRegistrationTask.kt | 5 +- .../products/wallet/ui/BackupAnimator.kt | 8 +- .../products/wallet/ui/BackupInfoAdapter.kt | 32 ++- .../wallet/ui/OnboardingWalletFragment.kt | 6 +- .../products/wallet/ui/WalletCardsWidget.kt | 27 +-- .../saveWallet/redux/SaveWalletReducer.kt | 4 +- .../ui/SaveWalletBottomSheetFragment.kt | 5 +- .../EnrollBiometricsDialogConent.kt | 4 +- .../ui/components/SaveWalletScreenContent.kt | 29 +-- .../features/send/redux/SendScreenAction.kt | 2 +- .../send/redux/reducers/AmountReducer.kt | 6 +- .../reducers/TransactionExtrasReducer.kt | 6 +- .../send/redux/states/AddressPayIdState.kt | 2 +- .../features/send/redux/states/FeeState.kt | 2 +- .../send/redux/states/ReceiptState.kt | 12 +- .../stateSubscribers/SendStateSubscriber.kt | 169 ++++++++------- .../sprinklr/redux/SprinklrReducer.kt | 4 +- .../features/sprinklr/ui/SprinklrActivity.kt | 5 +- .../sprinklr/ui/SprinklrScreenContent.kt | 5 +- .../features/sprinklr/ui/SprinklrViewModel.kt | 8 +- .../compose/AddCustomTokenScreen.kt | 15 +- .../compose/HangingOverKeyboardView.kt | 2 +- .../compose/test/ContractAddressTests.kt | 29 +-- .../tokens/presentation/ui/TokenItem.kt | 6 +- .../tap/features/tokens/redux/TokensAction.kt | 8 +- .../ui/compose/CurrencyPlaceholderIcon.kt | 2 +- .../ui/compose/currencyItem/NetworkItem.kt | 5 +- .../tap/features/wallet/models/Currency.kt | 5 +- .../tap/features/wallet/redux/WalletState.kt | 4 +- .../middlewares/AppCurrencyMiddleware.kt | 6 +- .../middlewares/MultiWalletMiddleware.kt | 53 +++-- .../middlewares/TradeCryptoMiddleware.kt | 7 +- .../redux/middlewares/WarningsMiddleware.kt | 4 +- .../redux/reducers/AppCurrencyReducer.kt | 8 +- .../wallet/redux/reducers/WalletReducer.kt | 5 +- .../tap/features/wallet/ui/BalanceWidget.kt | 17 +- .../wallet/ui/WalletDetailsFragment.kt | 9 +- .../ui/adapters/PendingTransactionsAdapter.kt | 12 +- .../wallet/ui/adapters/WalletAdapter.kt | 10 +- .../WalletDetailWarningMessagesAdapter.kt | 2 +- .../ui/adapters/WarningMessagesAdapter.kt | 6 +- .../dialogs/AmountToSendBottomSheetDialog.kt | 15 +- .../wallet/ui/images/CurrencyIconView.kt | 5 +- .../wallet/ui/view/TotalBalanceCard.kt | 23 +- .../wallet/ui/view/WalletDetailsButtonsRow.kt | 2 +- .../ui/wallet/CurrencySelectionDialog.kt | 9 +- .../wallet/ui/wallet/MultiWalletView.kt | 72 +++---- .../ui/wallet/saltPay/SaltPayWalletView.kt | 32 ++- .../redux/WalletSelectorMiddleware.kt | 4 +- .../redux/WalletSelectorReducer.kt | 4 +- .../tap/features/walletSelector/ui/Mapper.kt | 4 +- .../ui/WalletSelectorBottomSheetFragment.kt | 5 +- .../ui/WalletSelectorViewModel.kt | 5 +- .../BiometricsLockoutWarningContent.kt | 12 +- .../KeyInvalidatedWarningContent.kt | 8 +- .../components/RenameWalletDialogContent.kt | 4 +- .../WallectSelectorScreenContent.kt | 8 +- .../ui/components/WalletItem.kt | 30 +-- .../welcome/redux/WelcomeMiddleware.kt | 4 +- .../features/welcome/redux/WelcomeReducer.kt | 4 +- .../features/welcome/ui/WelcomeFragment.kt | 5 +- .../welcome/ui/components/WarningDialog.kt | 16 +- .../ui/components/WelcomeScreenContent.kt | 4 +- .../exchangeServices/mercuryo/MercuryoApi.kt | 4 +- .../mercuryo/MercuryoEnvironment.kt | 6 +- .../mercuryo/MercuryoService.kt | 5 +- .../exchangeServices/moonpay/MoonPayApi.kt | 8 +- .../utorg/UtorgEnvironment.kt | 16 +- .../exchangeServices/utorg/api/UtorgApi.kt | 9 +- .../tap/network/payid/PayIdVerifyApi.kt | 3 +- .../tap/persistence/PreferencesStorage.kt | 6 +- .../tangem/tap/proxy/DerivationManagerImpl.kt | 4 +- .../tap/proxy/TransactionManagerImpl.kt | 12 +- .../com/tangem/core/analytics/Analytics.kt | 3 +- .../tangem/core/analytics/api/ClientApi.kt | 10 +- .../core/analytics/api/EventHandlerApi.kt | 5 +- .../api/tangemTech/TangemTechApi.kt | 5 +- .../datasource/config/ConfigManagerImpl.kt | 10 +- .../tangem/datasource/utils/RequestHeader.kt | 2 +- .../com/tangem/core/ui/components/Buttons.kt | 33 +-- .../com/tangem/core/ui/components/Cards.kt | 27 +-- .../com/tangem/core/ui/components/Dialogs.kt | 19 +- .../core/ui/components/MiddleEllipsisText.kt | 26 ++- .../core/ui/components/SuccessScreen.kt | 5 +- .../core/ui/components/SystemBarsEffect.kt | 4 +- .../tangem/core/ui/components/TextFields.kt | 12 +- .../com/tangem/core/ui/components/Warnings.kt | 11 +- .../tangem/core/ui/components/atoms/Hand.kt | 8 +- .../fragments/ComposeBottomSheetFragment.kt | 6 +- .../core/ui/fragments/ComposeFragment.kt | 6 +- .../tangem/core/ui/fragments/ComposeScreen.kt | 5 +- .../com/tangem/core/ui/res/ButtonColorType.kt | 2 +- .../com/tangem/core/ui/res/IconColorType.kt | 2 +- .../com/tangem/core/ui/res/TangemTheme.kt | 5 +- .../com/tangem/core/ui/res/TextColorType.kt | 2 +- .../tangem/utils/coroutines/CoroutineExt.kt | 6 +- .../utils/detekt/UnusedRequiredComponent.kt | 2 +- .../com/tangem/domain/DomainModuleMessage.kt | 8 +- .../java/com/tangem/domain/DomainWrapped.kt | 4 +- .../java/com/tangem/domain/common/CardDTO.kt | 3 +- .../domain/common/TangemCardTypesResolver.kt | 6 +- .../com/tangem/domain/common/Throttling.kt | 2 +- .../com/tangem/domain/common/form/Form.kt | 2 +- .../addCustomToken/redux/AddCustomTokenHub.kt | 6 +- .../features/addCustomToken/redux/Models.kt | 4 +- .../com/tangem/domain/redux/ReStoreHub.kt | 12 +- .../referral/domain/ReferralRepository.kt | 7 +- .../tangem/feature/swap/SwapRepositoryImpl.kt | 7 +- .../feature/swap/domain/SwapInteractorImpl.kt | 11 +- .../feature/swap/domain/SwapRepository.kt | 6 +- .../swap/domain/di/SwapDomainModule.kt | 4 +- .../feature/swap/domain/models/DataError.kt | 8 +- .../tangem/feature/swap/ui/StateBuilder.kt | 6 +- .../feature/swap/ui/SwapScreenContent.kt | 4 +- .../feature/swap/ui/SwapSelectTokenScreen.kt | 9 +- .../tangem/feature/swap/ui/TransactionCard.kt | 10 +- .../feature/swap/viewmodels/SwapViewModel.kt | 6 +- .../actions/TesterActionsScreen.kt | 15 +- gradle/dependencies.toml | 4 +- plugins/configuration/detekt.yml | 14 +- 234 files changed, 902 insertions(+), 1618 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/ForegroundActivityObserver.kt b/app/src/main/java/com/tangem/tap/ForegroundActivityObserver.kt index 9664f38966..ecfb707001 100644 --- a/app/src/main/java/com/tangem/tap/ForegroundActivityObserver.kt +++ b/app/src/main/java/com/tangem/tap/ForegroundActivityObserver.kt @@ -59,8 +59,6 @@ class ForegroundActivityObserver : ActivityResultCaller { } } -fun ForegroundActivityObserver.withForegroundActivity( - block: (Activity) -> Unit -) { +fun ForegroundActivityObserver.withForegroundActivity(block: (Activity) -> Unit) { foregroundActivity?.let { block(it) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/NavBarInsetsFragmentLifecycleCallback.kt b/app/src/main/java/com/tangem/tap/NavBarInsetsFragmentLifecycleCallback.kt index 6e620bd0bc..cef921c1d6 100644 --- a/app/src/main/java/com/tangem/tap/NavBarInsetsFragmentLifecycleCallback.kt +++ b/app/src/main/java/com/tangem/tap/NavBarInsetsFragmentLifecycleCallback.kt @@ -11,12 +11,7 @@ import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks class NavBarInsetsFragmentLifecycleCallback : FragmentLifecycleCallbacks() { - override fun onFragmentViewCreated( - fm: FragmentManager, - f: Fragment, - v: View, - savedInstanceState: Bundle?, - ) { + override fun onFragmentViewCreated(fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?) { if (v is ComposeView) return ViewCompat.setOnApplyWindowInsetsListener(v) { view, windowInsets -> diff --git a/app/src/main/java/com/tangem/tap/common/CompositionCounter.kt b/app/src/main/java/com/tangem/tap/common/CompositionCounter.kt index 4e80061209..b09112d39f 100644 --- a/app/src/main/java/com/tangem/tap/common/CompositionCounter.kt +++ b/app/src/main/java/com/tangem/tap/common/CompositionCounter.kt @@ -4,7 +4,7 @@ import timber.log.Timber class CompositionCounter( val id: String, - count: Int = 0 + count: Int = 0, ) { var count: Int = count private set @@ -20,7 +20,7 @@ class CompositionCounter( class CompositionLogger( private val recomposeViewId: String, private val tag: String = recomposeViewId, - private var turnOnForIds: List = listOf(recomposeViewId) + private var turnOnForIds: List = listOf(recomposeViewId), ) { val count: Int get() = compositionCounter.count diff --git a/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt index 2f3e688532..3f6b858b3b 100644 --- a/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt @@ -10,7 +10,7 @@ import java.math.RoundingMode */ class CurrencyConverter( private val rateValue: BigDecimal, - private val decimals: Int + private val decimals: Int, ) { private val roundingMode = RoundingMode.HALF_UP diff --git a/app/src/main/java/com/tangem/tap/common/CustomTabsManager.kt b/app/src/main/java/com/tangem/tap/common/CustomTabsManager.kt index a30af0f5d6..b66ed0a3ad 100644 --- a/app/src/main/java/com/tangem/tap/common/CustomTabsManager.kt +++ b/app/src/main/java/com/tangem/tap/common/CustomTabsManager.kt @@ -13,7 +13,7 @@ class CustomTabsManager { .setDefaultColorSchemeParams( CustomTabColorSchemeParams.Builder() .setNavigationBarColor(context.getColorCompat(R.color.toolbarColor)) - .build() + .build(), ) .build() customTabsIntent.launchUrl(context, Uri.parse(url)) diff --git a/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt b/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt index a716d772fe..298bc14995 100644 --- a/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt @@ -9,7 +9,7 @@ import timber.log.Timber */ class GlobalLayoutStateHandler( private val view: T, - attachImmediately: Boolean = true + attachImmediately: Boolean = true, ) : ViewTreeObserver.OnGlobalLayoutListener { var onStateChanged: ((T) -> Unit)? = null diff --git a/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt b/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt index 56262664e7..0cfa1388be 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt @@ -14,14 +14,14 @@ object TangemSdkErrorMapper { is TangemSdkError.SerializeCommandError -> TangemSdkError.SerializeCommandError() is TangemSdkError.DeserializeApduFailed -> TangemSdkError.DeserializeApduFailed() is TangemSdkError.EncodingFailedTypeMismatch -> TangemSdkError.EncodingFailedTypeMismatch( - error.customMessage + error.customMessage, ) is TangemSdkError.EncodingFailed -> TangemSdkError.EncodingFailed(error.customMessage) is TangemSdkError.DecodingFailedMissingTag -> TangemSdkError.DecodingFailedMissingTag( - error.customMessage + error.customMessage, ) is TangemSdkError.DecodingFailedTypeMismatch -> TangemSdkError.DecodingFailedTypeMismatch( - error.customMessage + error.customMessage, ) is TangemSdkError.DecodingFailed -> TangemSdkError.DecodingFailed(error.customMessage) is TangemSdkError.InvalidResponse -> TangemSdkError.InvalidResponse() diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt index 874338b33b..46e02683ae 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt @@ -54,7 +54,7 @@ sealed class Token( object ShowWalletAddress : Token( category = "Token", - event = "Button - Show the Wallet Address" + event = "Button - Show the Wallet Address", ) sealed class Receive( diff --git a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt index e17985be26..42d9e80686 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt @@ -116,10 +116,7 @@ class TopUpController( } } - fun send( - scanResponse: ScanResponse, - cardBalanceState: AnalyticsParam.CardBalanceState, - ) { + fun send(scanResponse: ScanResponse, cardBalanceState: AnalyticsParam.CardBalanceState) { UserWalletIdBuilder.scanResponse(scanResponse).build()?.let { send(it, cardBalanceState, scanResponse.cardTypesResolver) } diff --git a/app/src/main/java/com/tangem/tap/common/compose/Button.kt b/app/src/main/java/com/tangem/tap/common/compose/Button.kt index c536af17bd..ee94c8b15b 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/Button.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/Button.kt @@ -8,10 +8,7 @@ import androidx.compose.runtime.CompositionLocalProvider * Used for disable ripple if button is enable = false */ @Composable -fun ToggledRippleTheme( - isEnabled: Boolean, - content: @Composable () -> Unit, -) { +fun ToggledRippleTheme(isEnabled: Boolean, content: @Composable () -> Unit) { val theme = LocalRippleTheme provides if (isEnabled) LocalRippleTheme.current else NoRippleTheme() CompositionLocalProvider(theme) { content() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt b/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt index 8d0de7df69..7afe67bf43 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt @@ -53,16 +53,22 @@ fun ComposeDialogManager() { ShowTheDialog(dialogSate) - LaunchedEffect(key1 = Unit, block = { - domainStore.subscribe(subscriber) { state -> - state.skipRepeats { oldState, newState -> - oldState.globalState == newState.globalState - }.select { it.globalState } - } - }) - DisposableEffect(key1 = Unit, effect = { - onDispose { domainStore.unsubscribe(subscriber) } - }) + LaunchedEffect( + key1 = Unit, + block = { + domainStore.subscribe(subscriber) { state -> + state.skipRepeats { oldState, newState -> + oldState.globalState == newState.globalState + }.select { it.globalState } + } + }, + ) + DisposableEffect( + key1 = Unit, + effect = { + onDispose { domainStore.unsubscribe(subscriber) } + }, + ) } @Composable @@ -77,7 +83,7 @@ private fun ShowTheDialog(dialogState: MutableState) { is DomainDialog.DialogError -> ErrorDialog( title = stringResource(id = R.string.common_error), body = errorConverter.convert(dialog.error).message, - onDismissRequest + onDismissRequest, ) is DomainDialog.SelectTokenDialog -> SelectTokenNetworkDialog(dialog, onDismissRequest) else -> {} @@ -97,14 +103,14 @@ fun SimpleDialog( ) { Dialog( properties = DialogProperties(false, false), - onDismissRequest = { } + onDismissRequest = { }, ) { Surface( modifier = Modifier.fillMaxWidth(), - shape = MaterialTheme.shapes.medium + shape = MaterialTheme.shapes.medium, ) { Column( - modifier = Modifier.padding(22.dp) + modifier = Modifier.padding(22.dp), ) { DialogTitle(title = title) LazyColumn { @@ -133,19 +139,15 @@ private fun DialogTitle(title: String) { style = LocalTextStyle.provides( TextStyle( fontWeight = FontWeight.Bold, - fontSize = 20.sp - ) - ).value + fontSize = 20.sp, + ), + ).value, ) SpacerH16() } @Composable -fun ErrorDialog( - title: String, - body: String, - onDismissRequest: () -> Unit, -) { +fun ErrorDialog(title: String, body: String, onDismissRequest: () -> Unit) { AlertDialog( title = { DialogTitle(title) }, text = { Text(body) }, @@ -154,6 +156,6 @@ fun ErrorDialog( Button(onClick = onDismissRequest) { Text(text = stringResource(id = R.string.common_ok)) } - } + }, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/compose/ErrorViews.kt b/app/src/main/java/com/tangem/tap/common/compose/ErrorViews.kt index c8d0701b2e..90928c9d15 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/ErrorViews.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/ErrorViews.kt @@ -15,11 +15,7 @@ import androidx.compose.ui.unit.dp [REDACTED_AUTHOR] */ @Composable -fun ErrorView( - text: String, - modifier: Modifier = Modifier, - style: TextStyle = LocalTextStyle.current, -) { +fun ErrorView(text: String, modifier: Modifier = Modifier, style: TextStyle = LocalTextStyle.current) { Text( text, color = MaterialTheme.colors.error, diff --git a/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt b/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt index 113dbfb809..59cf01d88c 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt @@ -213,10 +213,7 @@ private fun OutlinedProgressTextField( } @Composable -private fun AnimatedErrorView( - errorConverter: ModuleMessageConverter, - error: ModuleError? = null, -) { +private fun AnimatedErrorView(errorConverter: ModuleMessageConverter, error: ModuleError? = null) { AnimatedVisibility( visible = error != null, enter = fadeIn() + slideInVertically(), diff --git a/app/src/main/java/com/tangem/tap/common/compose/PinCodeWidget.kt b/app/src/main/java/com/tangem/tap/common/compose/PinCodeWidget.kt index f742bb5731..41e5637ba1 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/PinCodeWidget.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/PinCodeWidget.kt @@ -110,10 +110,7 @@ fun PinCodeWidget( } @Composable -private fun PinElement( - config: PinViewConfig, - pinSymbol: String, -) { +private fun PinElement(config: PinViewConfig, pinSymbol: String) { Box(Modifier.padding(config.pinBoxPadding)) { Box(config.pinBoxModifier) { Text( diff --git a/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt b/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt index 694fd8c376..945ffc182f 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt @@ -128,11 +128,7 @@ internal data class TangemTextFieldColors( } @Composable - override fun labelColor( - enabled: Boolean, - error: Boolean, - interactionSource: InteractionSource, - ): State { + override fun labelColor(enabled: Boolean, error: Boolean, interactionSource: InteractionSource): State { val focused by interactionSource.collectIsFocusedAsState() val targetValue = when { diff --git a/app/src/main/java/com/tangem/tap/common/compose/Undefined.kt b/app/src/main/java/com/tangem/tap/common/compose/Undefined.kt index 10e2ec9956..d5e5168be3 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/Undefined.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/Undefined.kt @@ -12,16 +12,13 @@ import androidx.compose.ui.unit.sp */ @Composable -fun TitleSubtitle( - title: String, - subtitle: String -) { +fun TitleSubtitle(title: String, subtitle: String) { Column { Text(text = title) Text( text = subtitle, fontSize = 12.sp, - color = Color.Gray + color = Color.Gray, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/compose/Warning.kt b/app/src/main/java/com/tangem/tap/common/compose/Warning.kt index ea4d150e51..6d4a79d192 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/Warning.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/Warning.kt @@ -21,11 +21,7 @@ import com.tangem.wallet.R [REDACTED_AUTHOR] */ @Composable -fun AddCustomTokenWarning( - warning: ModuleMessage, - converter: ModuleMessageConverter, - modifier: Modifier = Modifier, -) { +fun AddCustomTokenWarning(warning: ModuleMessage, converter: ModuleMessageConverter, modifier: Modifier = Modifier) { Surface( modifier = modifier, shape = MaterialTheme.shapes.small, @@ -39,14 +35,14 @@ fun AddCustomTokenWarning( text = stringResource(id = R.string.common_warning), color = colorResource(id = R.color.white), fontSize = 14.sp, - fontWeight = FontWeight.Bold + fontWeight = FontWeight.Bold, ) SpacerH8() Text( text = converter.convert(warning).message, color = colorResource(id = R.color.white), fontSize = 13.sp, - lineHeight = 18.sp + lineHeight = 18.sp, ) } } diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/AnimatedValue.kt b/app/src/main/java/com/tangem/tap/common/compose/extensions/AnimatedValue.kt index 1952c6a058..b21726c8e7 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/extensions/AnimatedValue.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/extensions/AnimatedValue.kt @@ -1,6 +1,10 @@ package com.tangem.tap.common.compose.extensions -import androidx.compose.animation.core.* +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.animation.core.Easing +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.tween import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember @@ -41,8 +45,8 @@ fun animatable( targetValue = values.second, animationSpec = tween( durationMillis = duration, - easing = easing - ) + easing = easing, + ), ) } } diff --git a/app/src/main/java/com/tangem/tap/common/entities/Button.kt b/app/src/main/java/com/tangem/tap/common/entities/Button.kt index d9ff2b27f8..b873b7ef3e 100644 --- a/app/src/main/java/com/tangem/tap/common/entities/Button.kt +++ b/app/src/main/java/com/tangem/tap/common/entities/Button.kt @@ -6,7 +6,7 @@ import com.tangem.tap.features.wallet.redux.ProgressState open class Button(val enabled: Boolean) open class IndeterminateProgressButton( - val state: ButtonState + val state: ButtonState, ) : Button(state != ButtonState.DISABLED) { val progressState: ProgressState diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Activity.kt b/app/src/main/java/com/tangem/tap/common/extensions/Activity.kt index 5f531a9bc8..adf3e19fed 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Activity.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Activity.kt @@ -22,7 +22,7 @@ fun Activity.sendEmail( subject: String, message: String, file: File? = null, - onFail: ((Exception) -> Unit)? = null + onFail: ((Exception) -> Unit)? = null, ) { fun createEmailShareIntent(recipient: String, subject: String, text: String, file: File? = null): Intent { val builder = ShareCompat.IntentBuilder.from(this) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Context.kt b/app/src/main/java/com/tangem/tap/common/extensions/Context.kt index 556f261f46..db544c0297 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Context.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Context.kt @@ -8,8 +8,7 @@ import android.net.Uri import androidx.annotation.AnyRes import androidx.core.content.ContextCompat -fun Context.readFile(fileName: String): String = - this.openFileInput(fileName).bufferedReader().readText() +fun Context.readFile(fileName: String): String = this.openFileInput(fileName).bufferedReader().readText() fun Context.rewriteFile(content: String, fileName: String) { this.openFileOutput(fileName, Context.MODE_PRIVATE).use { diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Map.kt b/app/src/main/java/com/tangem/tap/common/extensions/Map.kt index e970306219..313c83ff03 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Map.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Map.kt @@ -1,4 +1,3 @@ package com.tangem.tap.common.extensions -fun Map.filterNotNull(): Map = - filter { it.key != null && it.value != null } as Map \ No newline at end of file +fun Map.filterNotNull(): Map = filter { it.key != null && it.value != null } as Map \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index ff4f898d8d..632a28fe81 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -46,9 +46,7 @@ fun BigDecimal.toFormattedCurrencyString( return "$formattedAmount $currency" } -fun BigDecimal.toFiatRateString( - fiatCurrencyName: String, -): String { +fun BigDecimal.toFiatRateString(fiatCurrencyName: String): String { val value = this .setScale(2, RoundingMode.HALF_UP) .formatWithSpaces() @@ -69,10 +67,7 @@ fun BigDecimal.toFiatValue(rateValue: BigDecimal): BigDecimal { return fiatValue.setScale(2, RoundingMode.HALF_UP) } -fun BigDecimal.toFormattedFiatValue( - fiatCurrencyName: String, - formatWithSpaces: Boolean = false, -): String { +fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: String, formatWithSpaces: Boolean = false): String { val fiatValue = this.setScale(2, RoundingMode.HALF_UP) .let { if (formatWithSpaces) it.formatWithSpaces() else it } return " $fiatValue $fiatCurrencyName" diff --git a/app/src/main/java/com/tangem/tap/common/extensions/String.kt b/app/src/main/java/com/tangem/tap/common/extensions/String.kt index 3c4125d422..911bd470a1 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/String.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/String.kt @@ -25,12 +25,7 @@ fun String?.ellipsizeBeforeSpace(allowedSize: Int): String { newString.substring(startIndex until newString.length) } -fun String.colorSegment( - context: Context, - color: Int, - startIndex: Int = 0, - endIndex: Int = this.length, -): Spannable { +fun String.colorSegment(context: Context, color: Int, startIndex: Int = 0, endIndex: Int = this.length): Spannable { return this.toSpannable() .also { spannable -> spannable.setSpan( diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Transition.kt b/app/src/main/java/com/tangem/tap/common/extensions/Transition.kt index 69fbba97b6..d1e6b742f5 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Transition.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Transition.kt @@ -10,7 +10,7 @@ inline fun Transition.addListener( crossinline onEnd: (animator: Transition) -> Unit = {}, crossinline onCancel: (animator: Transition) -> Unit = {}, crossinline onPause: (animator: Transition) -> Unit = {}, - crossinline onRepeat: (animator: Transition) -> Unit = {} + crossinline onRepeat: (animator: Transition) -> Unit = {}, ): Transition.TransitionListener { val listener = object : Transition.TransitionListener { override fun onTransitionStart(transition: Transition) = onStart(transition) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt index 807d2baa56..980f206701 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt @@ -83,12 +83,11 @@ fun View.invisible(invisible: Boolean = true, invokeBeforeStateChanged: (() -> U } } -fun Context.dpToPixels(dp: Int): Int = - TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, - dp.toFloat(), - this.resources.displayMetrics, - ).toInt() +fun Context.dpToPixels(dp: Int): Int = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + dp.toFloat(), + this.resources.displayMetrics, +).toInt() tailrec fun Context?.getActivity(): Activity? = this as? Activity ?: (this as? ContextWrapper)?.baseContext?.getActivity() diff --git a/app/src/main/java/com/tangem/tap/common/images/Coil.kt b/app/src/main/java/com/tangem/tap/common/images/Coil.kt index 4e5a88d6e0..b7305e86dc 100644 --- a/app/src/main/java/com/tangem/tap/common/images/Coil.kt +++ b/app/src/main/java/com/tangem/tap/common/images/Coil.kt @@ -10,10 +10,7 @@ import timber.log.Timber private const val COIL_LOG_TAG = "COIL" -fun createCoilImageLoader( - context: Context, - logEnabled: Boolean = false, -): ImageLoader { +fun createCoilImageLoader(context: Context, logEnabled: Boolean = false): ImageLoader { return ImageLoader.Builder(context) .apply { if (!logEnabled) return@apply @@ -27,7 +24,7 @@ fun createCoilImageLoader( } .apply { level = HttpLoggingInterceptor.Level.BODY - } + }, ) .build() } diff --git a/app/src/main/java/com/tangem/tap/common/qrCodeScan/ScanQrCodeActivity.kt b/app/src/main/java/com/tangem/tap/common/qrCodeScan/ScanQrCodeActivity.kt index 4a86caa20d..f132cd319b 100644 --- a/app/src/main/java/com/tangem/tap/common/qrCodeScan/ScanQrCodeActivity.kt +++ b/app/src/main/java/com/tangem/tap/common/qrCodeScan/ScanQrCodeActivity.kt @@ -54,7 +54,9 @@ class ScanQrCodeActivity : AppCompatActivity(), ZXingScannerView.ResultHandler { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) cameraPermission == PackageManager.PERMISSION_GRANTED - } else true + } else { + true + } } private fun requestPermission() { diff --git a/app/src/main/java/com/tangem/tap/common/recyclerView/SpaceItemDecoration.kt b/app/src/main/java/com/tangem/tap/common/recyclerView/SpaceItemDecoration.kt index cb8ea5186f..4ea08ea19e 100644 --- a/app/src/main/java/com/tangem/tap/common/recyclerView/SpaceItemDecoration.kt +++ b/app/src/main/java/com/tangem/tap/common/recyclerView/SpaceItemDecoration.kt @@ -12,17 +12,12 @@ class SpaceItemDecoration( private lateinit var space: Space - override fun getItemOffsets( - outRect: Rect, - view: View, - parent: RecyclerView, - state: RecyclerView.State - ) { + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { if (state.itemCount == 0) return if (!::space.isInitialized) { space = Space( view.dpToPx(horizontalSpaceDp).toInt(), - view.dpToPx(verticalSpaceDp).toInt() + view.dpToPx(verticalSpaceDp).toInt(), ) } diff --git a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt index 9685dd54b7..335228e10f 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt @@ -5,6 +5,7 @@ import android.content.Intent import com.google.android.gms.wallet.PaymentData import com.shopify.buy3.Storefront import com.tangem.core.analytics.Analytics +import com.tangem.datasource.config.models.ShopifyShop import com.tangem.tap.common.analytics.converters.ShopOrderToEventConverter import com.tangem.tap.common.extensions.filterNotNull import com.tangem.tap.common.shop.data.ProductType @@ -12,7 +13,6 @@ import com.tangem.tap.common.shop.data.TangemProduct import com.tangem.tap.common.shop.data.TotalSum import com.tangem.tap.common.shop.googlepay.GooglePayService import com.tangem.tap.common.shop.shopify.ShopifyService -import com.tangem.datasource.config.models.ShopifyShop import com.tangem.tap.common.shop.shopify.data.CheckoutItem import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -106,11 +106,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { // } // } - suspend fun handleGooglePayResult( - resultCode: Int, - data: Intent?, - productType: ProductType, - ): Result { + suspend fun handleGooglePayResult(resultCode: Int, data: Intent?, productType: ProductType): Result { val result = googlePayService.handleResponseFromGooglePay(resultCode, data) result.onSuccess { val finalizePaymentResult = completeTokenizedPayment(it, productType) diff --git a/app/src/main/java/com/tangem/tap/common/shop/data/ProductType.kt b/app/src/main/java/com/tangem/tap/common/shop/data/ProductType.kt index d8db451147..4238b4d883 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/data/ProductType.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/data/ProductType.kt @@ -4,7 +4,8 @@ import com.tangem.tap.common.shop.TangemShopService enum class ProductType(val sku: String) { WALLET_2_CARDS(TangemShopService.TANGEM_WALLET_2_CARDS_SKU), - WALLET_3_CARDS(TangemShopService.TANGEM_WALLET_3_CARDS_SKU); + WALLET_3_CARDS(TangemShopService.TANGEM_WALLET_3_CARDS_SKU), + ; companion object { fun fromSku(sku: String): ProductType? { diff --git a/app/src/main/java/com/tangem/tap/common/shop/data/TangemProduct.kt b/app/src/main/java/com/tangem/tap/common/shop/data/TangemProduct.kt index 022af2b4ea..79eb72e1f1 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/data/TangemProduct.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/data/TangemProduct.kt @@ -3,5 +3,5 @@ package com.tangem.tap.common.shop.data data class TangemProduct( val type: ProductType, val totalSum: TotalSum? = null, - val appliedDiscount: String? = null + val appliedDiscount: String? = null, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayUtil.kt b/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayUtil.kt index 82509e1180..1e5cfba714 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayUtil.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayUtil.kt @@ -94,11 +94,7 @@ object GooglePayUtil { } } - private fun getTransactionInfo( - price: String, - countryCode: String, - currencyCode: String, - ): JSONObject { + private fun getTransactionInfo(price: String, countryCode: String, currencyCode: String): JSONObject { return JSONObject().apply { put("totalPrice", price) put("totalPriceStatus", "FINAL") diff --git a/app/src/main/java/com/tangem/tap/common/shop/shopify/ShopifyService.kt b/app/src/main/java/com/tangem/tap/common/shop/shopify/ShopifyService.kt index 71081fc7b1..0f7cfdf42b 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/shopify/ShopifyService.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/shopify/ShopifyService.kt @@ -106,10 +106,7 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop } } - suspend fun createCheckout( - checkoutItems: List, - checkoutID: ID? = null, - ): Result { + suspend fun createCheckout(checkoutItems: List, checkoutID: ID? = null): Result { val storefrontLineItems: MutableList = checkoutItems .map { CheckoutLineItemInput(it.quantity, it.id) }.toMutableList() @@ -197,10 +194,7 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop return runCheckoutMutation(query) } - suspend fun completeWithTokenizedPayment( - payment: TokenizedPaymentInputV3, - checkoutID: ID, - ): Result { + suspend fun completeWithTokenizedPayment(payment: TokenizedPaymentInputV3, checkoutID: ID): Result { val query = mutation { mutationQuery: MutationQuery -> mutationQuery .checkoutCompleteWithTokenizedPaymentV3( @@ -247,25 +241,21 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop private suspend fun queryAsync( query: QueryRootQuery, retryHandler: RetryHandler, - ): GraphCallResult = - withContext(Dispatchers.IO) { - suspendCoroutine { continuation -> - client.queryGraph(query).enqueue(retryHandler = retryHandler) { result -> - continuation.resume(result) - } + ): GraphCallResult = withContext(Dispatchers.IO) { + suspendCoroutine { continuation -> + client.queryGraph(query).enqueue(retryHandler = retryHandler) { result -> + continuation.resume(result) } } + } - private suspend fun queryAsync( - query: QueryRootQuery, - ): GraphCallResult = - withContext(Dispatchers.IO) { - suspendCoroutine { continuation -> - client.queryGraph(query).enqueue { result -> - continuation.resume(result) - } + private suspend fun queryAsync(query: QueryRootQuery): GraphCallResult = withContext(Dispatchers.IO) { + suspendCoroutine { continuation -> + client.queryGraph(query).enqueue { result -> + continuation.resume(result) } } + } private suspend fun mutationQueryAsync(query: MutationQuery): GraphCallResult = withContext(Dispatchers.IO) { diff --git a/app/src/main/java/com/tangem/tap/common/shop/shopify/data/CheckoutItem.kt b/app/src/main/java/com/tangem/tap/common/shop/shopify/data/CheckoutItem.kt index 5dc508df40..6d16e66908 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/shopify/data/CheckoutItem.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/shopify/data/CheckoutItem.kt @@ -4,5 +4,5 @@ import com.shopify.graphql.support.ID data class CheckoutItem( val id: ID, - val quantity: Int + val quantity: Int, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/snackBar/MaxAmountSnackbar.kt b/app/src/main/java/com/tangem/tap/common/snackBar/MaxAmountSnackbar.kt index d224143c98..b540a9d7c2 100644 --- a/app/src/main/java/com/tangem/tap/common/snackBar/MaxAmountSnackbar.kt +++ b/app/src/main/java/com/tangem/tap/common/snackBar/MaxAmountSnackbar.kt @@ -18,14 +18,14 @@ import com.tangem.wallet.R */ class MaxAmountSnackbar( parent: ViewGroup, - content: MaxAmountSnackbarView + content: MaxAmountSnackbarView, ) : BaseTransientBottomBar(parent, content, content) { companion object { fun make(view: View, onClick: () -> Unit): MaxAmountSnackbar { val parent = view.findSuitableParent() ?: throw IllegalArgumentException( - "No suitable parent found from the given view. Please provide a valid view." + "No suitable parent found from the given view. Please provide a valid view.", ) val inflater = LayoutInflater.from(view.context) val customView = inflater.inflate(R.layout.view_snackbar_max_amount, parent, false) as MaxAmountSnackbarView @@ -63,7 +63,7 @@ class MaxAmountSnackbar( class MaxAmountSnackbarView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0 + defStyleAttr: Int = 0, ) : ConstraintLayout(context, attrs, defStyleAttr), ContentViewCallback { init { diff --git a/app/src/main/java/com/tangem/tap/domain/PayIdManager.kt b/app/src/main/java/com/tangem/tap/domain/PayIdManager.kt index d66ac2ed73..16565ff5a6 100644 --- a/app/src/main/java/com/tangem/tap/domain/PayIdManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/PayIdManager.kt @@ -11,15 +11,13 @@ import java.util.* class PayIdManager { @Suppress("MagicNumber") - suspend fun verifyPayId( - payId: String, - blockchain: Blockchain, - ): Result = withContext(Dispatchers.IO) { - val splitPayId = payId.split("\$") - val user = splitPayId[0] - val baseUrl = "https://${splitPayId[1]}/" - return@withContext PayIdVerifyService(baseUrl).verifyAddress(user, blockchain.getPayIdNetwork()) - } + suspend fun verifyPayId(payId: String, blockchain: Blockchain): Result = + withContext(Dispatchers.IO) { + val splitPayId = payId.split("\$") + val user = splitPayId[0] + val baseUrl = "https://${splitPayId[1]}/" + return@withContext PayIdVerifyService(baseUrl).verifyAddress(user, blockchain.getPayIdNetwork()) + } private fun Blockchain.getPayIdNetwork(): String { return when (this) { @@ -30,8 +28,10 @@ class PayIdManager { } companion object { - private val payIdRegExp = ("^[a-z0-9!#@%&*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#@%&*+/=?^_`{|}~-]+)*\\\$(?:(?:[a-z0-9]" + - "(?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z-]*[a-z0-9])?|(?:[0-9]{1,3}\\.){3}[0-9]{1,3})\$").toRegex() + private val payIdRegExp = ( + "^[a-z0-9!#@%&*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#@%&*+/=?^_`{|}~-]+)*\\\$(?:(?:[a-z0-9]" + + "(?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z-]*[a-z0-9])?|(?:[0-9]{1,3}\\.){3}[0-9]{1,3})\$" + ).toRegex() val payIdSupported: EnumSet = EnumSet.of( Blockchain.XRP, diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 3b13e7243e..36e5dcebdf 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -82,9 +82,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co ).also { sendScanResultsToAnalytics(it) } } - suspend fun createProductWallet( - scanResponse: ScanResponse, - ): CompletionResult { + suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult { return runTaskAsync( CreateProductWalletTask(scanResponse.cardTypesResolver), scanResponse.card.cardId, @@ -92,9 +90,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co ) } - private fun sendScanResultsToAnalytics( - result: CompletionResult, - ) { + private fun sendScanResultsToAnalytics(result: CompletionResult) { if (result is CompletionResult.Failure) { (result.error as? TangemSdkError)?.let { error -> Analytics.send(Basic.ScanError(error)) @@ -194,14 +190,13 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co cardId: String? = null, initialMessage: Message? = null, accessCode: String? = null, - ): CompletionResult = - withContext(Dispatchers.Main) { - suspendCancellableCoroutine { continuation -> - tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode) { result -> - if (continuation.isActive) continuation.resume(result) - } + ): CompletionResult = withContext(Dispatchers.Main) { + suspendCancellableCoroutine { continuation -> + tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode) { result -> + if (continuation.isActive) continuation.resume(result) } } + } private suspend fun runTaskAsyncReturnOnMain( runnable: CardSessionRunnable, @@ -226,9 +221,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co return context.getString(stringResId, *formatArgs) } - fun setAccessCodeRequestPolicy( - useBiometricsForAccessCode: Boolean, - ) { + fun setAccessCodeRequestPolicy(useBiometricsForAccessCode: Boolean) { tangemSdk.config.userCodeRequestPolicy = if (useBiometricsForAccessCode) { UserCodeRequestPolicy.AlwaysWithBiometrics(codeType = UserCodeType.AccessCode) } else { diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt index d9e3f1aa97..196ec2f0f4 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt @@ -53,10 +53,7 @@ class TangemSigner( } } - override suspend fun sign( - hash: ByteArray, - publicKey: Wallet.PublicKey, - ): CompletionResult { + override suspend fun sign(hash: ByteArray, publicKey: Wallet.PublicKey): CompletionResult { val result = sign( hashes = listOf(hash), publicKey = publicKey, diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt index 9800be1707..a36e254ee7 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt @@ -19,7 +19,7 @@ data class WarningMessage( val origin: Origin = Origin.Remote, @StringRes val buttonTextId: Int? = null, val titleFormatArg: String? = null, - val messageFormatArg: String? = null + val messageFormatArg: String? = null, ) { val blockchainList: List? by lazy { blockchains?.map { Blockchain.fromId(it.uppercase()) } @@ -35,7 +35,7 @@ data class WarningMessage( Warning, @Json(name = "info") - Info + Info, } enum class Type { @@ -47,7 +47,7 @@ data class WarningMessage( AppRating, - TestCard + TestCard, } enum class Location { @@ -55,7 +55,7 @@ data class WarningMessage( MainScreen, @Json(name = "send") - SendScreen + SendScreen, } enum class Origin { diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt index 996032f7d6..9d908f0724 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt @@ -107,7 +107,7 @@ class WarningMessagesManager { messageResId = R.string.warning_signed_tx_previously, origin = WarningMessage.Origin.Local, buttonTextId = R.string.warning_button_learn_more, - titleFormatArg = "\u26A0" + titleFormatArg = "\u26A0", ) fun appRatingWarning(): WarningMessage = WarningMessage( diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt index 59647cbde5..5298777226 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt @@ -92,10 +92,7 @@ private fun getDerivationParams(derivationPath: String?, card: CardDTO): Derivat } } -fun WalletManagerFactory.makeWalletManagerForApp( - scanResponse: ScanResponse, - currency: Currency, -): WalletManager? { +fun WalletManagerFactory.makeWalletManagerForApp(scanResponse: ScanResponse, currency: Currency): WalletManager? { return makeWalletManagerForApp( scanResponse, blockchain = currency.blockchain, @@ -112,9 +109,7 @@ fun WalletManagerFactory.makeWalletManagersForApp( .mapNotNull { this.makeWalletManagerForApp(scanResponse, it) } } -fun WalletManagerFactory.makePrimaryWalletManager( - scanResponse: ScanResponse, -): WalletManager? { +fun WalletManagerFactory.makePrimaryWalletManager(scanResponse: ScanResponse): WalletManager? { val blockchain = if (scanResponse.card.isTestCard) { scanResponse.cardTypesResolver.getBlockchain().getTestnetVersion() ?: return null } else { diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt index 6a3b71d604..70b7f005b5 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt @@ -21,7 +21,9 @@ class UserWalletIdBuilder private constructor( } else { publicKey } - } else null + } else { + null + } return seed?.let { UserWalletId(value = calculateUserWalletId(it)) @@ -34,7 +36,9 @@ class UserWalletIdBuilder private constructor( return if (keyHash != null) { message.calculateHmacSha256(keyHash) - } else null + } else { + null + } } companion object { diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index 565f8fb826..921e8ccc3e 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -34,10 +34,7 @@ interface WalletStoreBuilder { return BlockchainNetworkWalletStoreBuilderImpl(userWallet, blockchainNetwork) } - operator fun invoke( - userWallet: UserWallet, - walletManager: WalletManager, - ): WalletMangerWalletStoreBuilder { + operator fun invoke(userWallet: UserWallet, walletManager: WalletManager): WalletMangerWalletStoreBuilder { return WalletMangerWalletStoreBuilderImpl(userWallet, walletManager) } } @@ -161,10 +158,7 @@ private fun Blockchain.toBlockchainWalletData(walletManager: WalletManager): Wal ) } -private fun Token.toTokenWalletData( - walletManager: WalletManager, - primaryToken: Token?, -): WalletDataModel { +private fun Token.toTokenWalletData(walletManager: WalletManager, primaryToken: Token?): WalletDataModel { val wallet = walletManager.wallet return WalletDataModel( currency = Currency.Token( diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index facfc3d62e..7e0f77f2d1 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -99,10 +99,7 @@ object ScanCardProcessor { } } - private fun sendAnalytics( - analyticsEvent: AnalyticsEvent?, - scanResponse: ScanResponse, - ) { + private fun sendAnalytics(analyticsEvent: AnalyticsEvent?, scanResponse: ScanResponse) { analyticsEvent?.let { // this workaround needed to send CardWasScannedEvent without adding a context val interceptor = CardContextInterceptor(scanResponse) @@ -257,10 +254,7 @@ object ScanCardProcessor { } } - private suspend inline fun navigateTo( - screen: AppScreen, - onProgressStateChange: (showProgress: Boolean) -> Unit, - ) { + private suspend inline fun navigateTo(screen: AppScreen, onProgressStateChange: (showProgress: Boolean) -> Unit) { delay(DELAY_SDK_DIALOG_CLOSE) store.dispatchOnMain(NavigationAction.NavigateTo(screen)) onProgressStateChange(false) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/CreateWalletsTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/CreateWalletsTask.kt index 5c39928f88..260736b303 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/CreateWalletsTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/CreateWalletsTask.kt @@ -28,7 +28,7 @@ class CreateWalletsTask(curves: List? = null) : CardSessionRunnab private fun createWallet( curve: EllipticCurve, session: CardSession, - callback: (result: CompletionResult) -> Unit + callback: (result: CompletionResult) -> Unit, ) { CreateWalletTask(curve).run(session) { result -> when (result) { diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/SignHashTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/SignHashTask.kt index 3e5d37ac4b..d3b749658c 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/SignHashTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/SignHashTask.kt @@ -23,11 +23,15 @@ class SignHashTask( when (response) { is CompletionResult.Success -> { - callback(CompletionResult.Success(TangemSignHashResponse( - response.data.signature, - response.data.totalSignedHashes, - session.environment.card?.wallet(publicKey.seedKey)?.remainingSignatures - ))) + callback( + CompletionResult.Success( + TangemSignHashResponse( + response.data.signature, + response.data.totalSignedHashes, + session.environment.card?.wallet(publicKey.seedKey)?.remainingSignatures, + ), + ), + ) } is CompletionResult.Failure -> callback(CompletionResult.Failure(response.error)) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/SignHashesTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/SignHashesTask.kt index 4d25a1de56..3a8a5bd48c 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/SignHashesTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/SignHashesTask.kt @@ -22,11 +22,15 @@ class SignHashesTask( SignHashesCommand(hashes.toTypedArray(), publicKey.seedKey, publicKey.derivationPath).run(session) { response -> when (response) { is CompletionResult.Success -> { - callback(CompletionResult.Success(TangemSignHashesResponse( - response.data.signatures, - response.data.totalSignedHashes, - session.environment.card?.wallet(publicKey.seedKey)?.remainingSignatures - ))) + callback( + CompletionResult.Success( + TangemSignHashesResponse( + response.data.signatures, + response.data.totalSignedHashes, + session.environment.card?.wallet(publicKey.seedKey)?.remainingSignatures, + ), + ), + ) } is CompletionResult.Failure -> callback(CompletionResult.Failure(response.error)) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt index 7bbd4d1811..eeed6d4ad6 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt @@ -267,10 +267,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor { + private fun getBlockchains(cardId: String, card: CardDTO): List { return when { DemoHelper.isDemoCardId(cardId) -> DemoHelper.config.demoBlockchains card.isTestCard -> listOf(Blockchain.BitcoinTestnet, Blockchain.EthereumTestnet) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateWalletsTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateWalletsTask.kt index da0e18e914..6c41807de9 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateWalletsTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateWalletsTask.kt @@ -13,7 +13,7 @@ import com.tangem.operations.wallet.CreateWalletTask [REDACTED_AUTHOR] */ class CreateWalletsResponse( - val createWalletResponses: List + val createWalletResponses: List, ) : CommandResponse class CreateWalletsTask( @@ -35,7 +35,7 @@ class CreateWalletsTask( private fun createWallet( curve: EllipticCurve, session: CardSession, - callback: (result: CompletionResult) -> Unit + callback: (result: CompletionResult) -> Unit, ) { CreateWalletTask(curve).run(session) { result -> when (result) { diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ProductCommandProcessor.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ProductCommandProcessor.kt index 8b9d8d9d2f..474bbd49dd 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ProductCommandProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ProductCommandProcessor.kt @@ -8,9 +8,5 @@ import com.tangem.domain.common.CardDTO [REDACTED_AUTHOR] */ interface ProductCommandProcessor { - fun proceed( - card: CardDTO, - session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) + fun proceed(card: CardDTO, session: CardSession, callback: (result: CompletionResult) -> Unit) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ResetToFactorySettingsTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ResetToFactorySettingsTask.kt index 398f369a54..1ab2b50b69 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ResetToFactorySettingsTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ResetToFactorySettingsTask.kt @@ -14,10 +14,7 @@ class ResetToFactorySettingsTask : CardSessionRunnable { deleteWallets(session, callback) } - private fun deleteWallets( - session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { + private fun deleteWallets(session: CardSession, callback: (result: CompletionResult) -> Unit) { val wallet = session.environment.card?.wallets?.lastOrNull().guard { resetBackup(session, callback) return @@ -33,10 +30,7 @@ class ResetToFactorySettingsTask : CardSessionRunnable { } } - private fun resetBackup( - session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { + private fun resetBackup(session: CardSession, callback: (result: CompletionResult) -> Unit) { val backupStatus = session.environment.card?.backupStatus if (backupStatus == null || backupStatus == Card.BackupStatus.NoBackup) { callback(CompletionResult.Success(session.environment.card!!)) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 8dde976a16..00ca32c553 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -52,10 +52,7 @@ class ScanProductTask( override val allowsRequestAccessCodeFromRepository: Boolean = false, ) : CardSessionRunnable { - override fun run( - session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { + override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { val card = this.card ?: session.environment.card.guard { callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) return diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt index 28bcdc9c35..f4c06f518a 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt @@ -5,10 +5,7 @@ import com.tangem.common.card.FirmwareVersion import com.tangem.domain.common.CardDTO object CurrenciesRepository { - fun getBlockchains( - cardFirmware: CardDTO.FirmwareVersion, - isTestNet: Boolean = false, - ): List { + fun getBlockchains(cardFirmware: CardDTO.FirmwareVersion, isTestNet: Boolean = false): List { val blockchains = if (cardFirmware < FirmwareVersion.MultiWalletAvailable) { Blockchain.secp256k1Blockchains(isTestNet) } else { @@ -23,7 +20,7 @@ object CurrenciesRepository { removeAll( listOf( // Any blockchain - ) + ), ) } } diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt b/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt index c70127f7e2..2cb1488c24 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt @@ -10,20 +10,20 @@ data class CurrencyFromJson( val id: String, val name: String, val symbol: String, - val networks: List? = null + val networks: List? = null, ) @JsonClass(generateAdapter = true) data class ContractFromJson( val networkId: String, val contractAddress: String?, - val decimalCount: Int? + val decimalCount: Int?, ) @JsonClass(generateAdapter = true) data class CurrenciesFromJson( val imageHost: String?, - val coins: List + val coins: List, ) fun List.toContracts(): List { @@ -35,7 +35,7 @@ data class Currency( val name: String, val symbol: String, val iconUrl: String, - val contracts: List + val contracts: List, ) { companion object { @@ -45,7 +45,7 @@ data class Currency( name = currency.name, symbol = currency.symbol, iconUrl = getIconUrl(currency.id, null), - contracts = currency.networks?.toContracts() ?: emptyList() + contracts = currency.networks?.toContracts() ?: emptyList(), ) } @@ -55,7 +55,7 @@ data class Currency( name = currency.name, symbol = currency.symbol, iconUrl = getIconUrl(currency.id, imageHost), - contracts = currency.networks.mapNotNull { Contract.fromNetwork(it, imageHost) } + contracts = currency.networks.mapNotNull { Contract.fromNetwork(it, imageHost) }, ) } } @@ -77,7 +77,7 @@ data class Contract( blockchain = blockchain, address = contract.contractAddress, decimalCount = contract.decimalCount, - iconUrl = getIconUrl(contract.networkId, null) + iconUrl = getIconUrl(contract.networkId, null), ) } @@ -88,7 +88,7 @@ data class Contract( blockchain = blockchain, address = contract.contractAddress, decimalCount = contract.decimalCount?.toInt(), - iconUrl = getIconUrl(contract.networkId, imageHost) + iconUrl = getIconUrl(contract.networkId, imageHost), ) } } diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/converters/CurrencyConverter.kt b/app/src/main/java/com/tangem/tap/domain/tokens/converters/CurrencyConverter.kt index 3ac6babc72..6c60dfbc89 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/converters/CurrencyConverter.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/converters/CurrencyConverter.kt @@ -15,6 +15,6 @@ object CurrencyConverter : Converter { name = value.currencyName, symbol = value.currencySymbol, decimals = value.decimals, - contractAddress = if (value is Currency.Token) value.token.contractAddress else null + contractAddress = if (value is Currency.Token) value.token.contractAddress else null, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/models/ObsoleteTokenDao.kt b/app/src/main/java/com/tangem/tap/domain/tokens/models/ObsoleteTokenDao.kt index 19d8bbf73d..5ff4d8c8ca 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/models/ObsoleteTokenDao.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/models/ObsoleteTokenDao.kt @@ -18,7 +18,7 @@ data class ObsoleteTokenDao( contractAddress = contractAddress, decimalCount = decimalCount, blockchainDao = BlockchainDao.fromBlockchain(blockchain), - customIconUrl = customIconUrl + customIconUrl = customIconUrl, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/models/TokenDao.kt b/app/src/main/java/com/tangem/tap/domain/tokens/models/TokenDao.kt index ef6f541f6e..a70e0606b3 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/models/TokenDao.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/models/TokenDao.kt @@ -14,7 +14,7 @@ data class TokenDao( @Json(name = "blockchain") val blockchainDao: BlockchainDao, val customIconUrl: String? = null, - val type: String? = null + val type: String? = null, ) { fun toToken(): Token { return Token( diff --git a/app/src/main/java/com/tangem/tap/domain/twins/CreateFirstTwinWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/twins/CreateFirstTwinWalletTask.kt index 28016d704f..35d535aa53 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/CreateFirstTwinWalletTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/CreateFirstTwinWalletTask.kt @@ -13,10 +13,7 @@ class CreateFirstTwinWalletTask(private val firstCardId: String) : CardSessionRu override val allowsRequestAccessCodeFromRepository: Boolean = false - override fun run( - session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { + override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { val card = session.environment.card val publicKey = card?.wallets?.firstOrNull()?.publicKey if (publicKey != null) { diff --git a/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt b/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt index b173602e3d..127c10ec33 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt @@ -16,10 +16,7 @@ class FinalizeTwinTask( override val allowsRequestAccessCodeFromRepository: Boolean = false - override fun run( - session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { + override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { WriteProtectedIssuerDataTask(twinPublicKey, issuerKeys).run(session) { result -> when (result) { is CompletionResult.Success -> diff --git a/app/src/main/java/com/tangem/tap/domain/twins/WriteProtectedIssuerDataTask.kt b/app/src/main/java/com/tangem/tap/domain/twins/WriteProtectedIssuerDataTask.kt index 2a415c6eda..7eae636918 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/WriteProtectedIssuerDataTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/WriteProtectedIssuerDataTask.kt @@ -19,10 +19,7 @@ class WriteProtectedIssuerDataTask( private val issuerKeys: KeyPair, ) : CardSessionRunnable { - override fun run( - session: CardSession, - callback: (result: CompletionResult) -> Unit, - ) { + override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { SignHashCommand( twinPublicKey.calculateSha256(), session.environment.card!!.wallets.first().publicKey, diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultSelectedUserWalletRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultSelectedUserWalletRepository.kt index ec44dbd914..6efa84fc70 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultSelectedUserWalletRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultSelectedUserWalletRepository.kt @@ -25,6 +25,6 @@ internal class DefaultSelectedUserWalletRepository( } private enum class StorageKey { - SelectedWalletId + SelectedWalletId, } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsPublicInformationRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsPublicInformationRepository.kt index 7d1bd9333b..ab64d4a5fb 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsPublicInformationRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsPublicInformationRepository.kt @@ -73,9 +73,7 @@ internal class DefaultUserWalletsPublicInformationRepository( } @JvmName("saveWithPublicInformation") - private suspend fun save( - publicInformation: List, - ): CompletionResult = catching { + private suspend fun save(publicInformation: List): CompletionResult = catching { withContext(Dispatchers.IO) { publicInformation .let(publicInformationAdapter::toJson) @@ -85,6 +83,6 @@ internal class DefaultUserWalletsPublicInformationRepository( } private enum class StorageKey { - UserWalletPublicInformation + UserWalletPublicInformation, } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt index 3cbf04ac4e..631d8d13c6 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt @@ -148,10 +148,7 @@ internal class DefaultUserWalletsSensitiveInformationRepository( } } - private suspend fun ByteArray.getIvAndDecrypt( - userWalletId: String, - encryptionKey: ByteArray, - ): ByteArray? { + private suspend fun ByteArray.getIvAndDecrypt(userWalletId: String, encryptionKey: ByteArray): ByteArray? { return withContext(Dispatchers.Default) { val iv = secureStorage.get(StorageKey.SensitiveInformationIv(userWalletId).name) ?: error("IV not found") diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/Mapper.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/Mapper.kt index 7d8170895c..4c7784a50a 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/Mapper.kt @@ -50,7 +50,9 @@ internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInfo internal fun List.updateWith( walletIdToSensitiveInformation: Map, ): List { - return if (walletIdToSensitiveInformation.isEmpty()) this else { + return if (walletIdToSensitiveInformation.isEmpty()) { + this + } else { this.map { wallet -> walletIdToSensitiveInformation[wallet.walletId] ?.let(wallet::updateWith) diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/ByteArrayKeyAdapter.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/ByteArrayKeyAdapter.kt index 889438c346..cae2c47666 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/ByteArrayKeyAdapter.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/ByteArrayKeyAdapter.kt @@ -9,19 +9,12 @@ import com.tangem.common.extensions.ByteArrayKey internal class ByteArrayKeyAdapter { @ToJson - fun toJson( - writer: JsonWriter, - src: ByteArrayKey, - byteArrayAdapter: JsonAdapter, - ) { + fun toJson(writer: JsonWriter, src: ByteArrayKey, byteArrayAdapter: JsonAdapter) { byteArrayAdapter.toJson(writer, src.bytes) } @FromJson - fun fromJson( - reader: JsonReader, - byteArrayAdapter: JsonAdapter, - ): ByteArrayKey? { + fun fromJson(reader: JsonReader, byteArrayAdapter: JsonAdapter): ByteArrayKey? { return byteArrayAdapter.fromJson(reader)?.let { ByteArrayKey(bytes = it) } diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/CardBackupStatusAdapter.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/CardBackupStatusAdapter.kt index 419fd22dbf..2f7e2544f5 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/CardBackupStatusAdapter.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/CardBackupStatusAdapter.kt @@ -9,11 +9,7 @@ import com.tangem.domain.common.CardDTO internal class CardBackupStatusAdapter { @ToJson - fun toJson( - writer: JsonWriter, - src: CardDTO.BackupStatus?, - mapAdapter: JsonAdapter>, - ) { + fun toJson(writer: JsonWriter, src: CardDTO.BackupStatus?, mapAdapter: JsonAdapter>) { val jsonMap = mutableMapOf() when (src) { @@ -37,10 +33,7 @@ internal class CardBackupStatusAdapter { } @FromJson - fun fromJson( - reader: JsonReader, - mapAdapter: JsonAdapter>, - ): CardDTO.BackupStatus? { + fun fromJson(reader: JsonReader, mapAdapter: JsonAdapter>): CardDTO.BackupStatus? { val map = mapAdapter.fromJson(reader) ?: return null return when (map["status"]) { diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt index fa2bbc0424..f56949a1be 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt @@ -16,10 +16,7 @@ interface WalletCurrenciesManager { * * @return [CompletionResult] of operation * */ - suspend fun update( - userWallet: UserWallet, - currency: Currency, - ): CompletionResult + suspend fun update(userWallet: UserWallet, currency: Currency): CompletionResult /** * Add list of [Currency] to [UserWallet]. @@ -32,10 +29,7 @@ interface WalletCurrenciesManager { * * @return [CompletionResult] of operation * */ - suspend fun addCurrencies( - userWallet: UserWallet, - currenciesToAdd: List, - ): CompletionResult + suspend fun addCurrencies(userWallet: UserWallet, currenciesToAdd: List): CompletionResult /** * Remove [Currency] from [UserWallet] @@ -48,10 +42,7 @@ interface WalletCurrenciesManager { * * @return [CompletionResult] of operation * */ - suspend fun removeCurrency( - userWallet: UserWallet, - currencyToRemove: Currency, - ): CompletionResult + suspend fun removeCurrency(userWallet: UserWallet, currencyToRemove: Currency): CompletionResult /** * Remove list of [Currency] from [UserWallet] @@ -64,10 +55,7 @@ interface WalletCurrenciesManager { * * @return [CompletionResult] of operation * */ - suspend fun removeCurrencies( - userWallet: UserWallet, - currenciesToRemove: List, - ): CompletionResult + suspend fun removeCurrencies(userWallet: UserWallet, currenciesToRemove: List): CompletionResult /** * Add a callback [Listener] diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt index d32bdd60ff..2281fbfe5f 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt @@ -33,29 +33,27 @@ internal class DefaultWalletCurrenciesManager( private val listeners = mutableListOf() - override suspend fun update( - userWallet: UserWallet, - currency: Currency, - ): CompletionResult = withContext(Dispatchers.Default) { - listeners.forEach { it.willUpdate(userWallet, currency) } - val walletStore = walletStoresRepository.getSync(userWallet.walletId) - .find { - it.blockchain == currency.blockchain && - it.derivationPath?.rawPath == currency.derivationPath - } + override suspend fun update(userWallet: UserWallet, currency: Currency): CompletionResult = + withContext(Dispatchers.Default) { + listeners.forEach { it.willUpdate(userWallet, currency) } + val walletStore = walletStoresRepository.getSync(userWallet.walletId) + .find { + it.blockchain == currency.blockchain && + it.derivationPath?.rawPath == currency.derivationPath + } - val updateResult = if (walletStore == null) { - CompletionResult.Success(Unit) - } else { - walletAmountsRepository.updateAmountsForWalletStore( - walletStore = walletStore, - userWallet = userWallet, - fiatCurrency = appCurrencyProvider(), - ) + val updateResult = if (walletStore == null) { + CompletionResult.Success(Unit) + } else { + walletAmountsRepository.updateAmountsForWalletStore( + walletStore = walletStore, + userWallet = userWallet, + fiatCurrency = appCurrencyProvider(), + ) + } + listeners.forEach { it.didUpdate(userWallet, currency) } + updateResult } - listeners.forEach { it.didUpdate(userWallet, currency) } - updateResult - } override suspend fun addCurrencies( userWallet: UserWallet, @@ -110,10 +108,7 @@ internal class DefaultWalletCurrenciesManager( } } - override suspend fun removeCurrency( - userWallet: UserWallet, - currencyToRemove: Currency, - ): CompletionResult { + override suspend fun removeCurrency(userWallet: UserWallet, currencyToRemove: Currency): CompletionResult { listeners.forEach { it.willCurrencyRemove(userWallet, currencyToRemove) } return removeCurrencies(userWallet, listOf(currencyToRemove)) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt index e4bebc2c07..503bfe5cc0 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt @@ -49,10 +49,7 @@ interface WalletStoresManager { * * @return [CompletionResult] of operation * */ - suspend fun fetch( - userWallet: UserWallet, - refresh: Boolean = false, - ): CompletionResult + suspend fun fetch(userWallet: UserWallet, refresh: Boolean = false): CompletionResult /** * Fetch wallet stores associated with provided [UserWallet]s. Fetched [WalletStoreModel]s updates can be observed @@ -63,10 +60,7 @@ interface WalletStoresManager { * * @return [CompletionResult] of operation * */ - suspend fun fetch( - userWallets: List, - refresh: Boolean = false, - ): CompletionResult + suspend fun fetch(userWallets: List, refresh: Boolean = false): CompletionResult /** * Update [WalletStoreModel]s amounts associated with provided [UserWallet]s @@ -75,9 +69,7 @@ interface WalletStoresManager { * * @return [CompletionResult] of operation * */ - suspend fun updateAmounts( - userWallets: List, - ): CompletionResult + suspend fun updateAmounts(userWallets: List): CompletionResult // For provider companion object diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt index 00f000f14d..e6abbc56c7 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt @@ -58,38 +58,35 @@ internal class DefaultWalletStoresManager( return walletStoresRepository.clear() } - override suspend fun fetch( - userWallets: List, - refresh: Boolean, - ): CompletionResult = withContext(Dispatchers.Default) { - val fiatCurrency = appCurrencyProvider.invoke() - val isFiatCurrencyChanged = state.value.fiatCurrency != fiatCurrency + override suspend fun fetch(userWallets: List, refresh: Boolean): CompletionResult = + withContext(Dispatchers.Default) { + val fiatCurrency = appCurrencyProvider.invoke() + val isFiatCurrencyChanged = state.value.fiatCurrency != fiatCurrency - state.update { prevState -> - prevState.copy( - fiatCurrency = fiatCurrency, - ) + state.update { prevState -> + prevState.copy( + fiatCurrency = fiatCurrency, + ) + } + + userWallets + .mapNotNull { userWallet -> + val hasNotWalletStoresForUserWallet = !walletStoresRepository.contains(userWallet.walletId) + if (refresh || hasNotWalletStoresForUserWallet || isFiatCurrencyChanged) { + fetchWalletsIfNeeded(userWallet) + } else { + null + } + } + .fold(arrayListOf()) { acc, data -> + acc.apply { add(data) } + } + .flatMap { + walletAmountsRepository.updateAmountsForUserWallets(it, fiatCurrency) + } } - userWallets - .mapNotNull { userWallet -> - val hasNotWalletStoresForUserWallet = !walletStoresRepository.contains(userWallet.walletId) - if (refresh || hasNotWalletStoresForUserWallet || isFiatCurrencyChanged) { - fetchWalletsIfNeeded(userWallet) - } else null - } - .fold(arrayListOf()) { acc, data -> - acc.apply { add(data) } - } - .flatMap { - walletAmountsRepository.updateAmountsForUserWallets(it, fiatCurrency) - } - } - - override suspend fun fetch( - userWallet: UserWallet, - refresh: Boolean, - ): CompletionResult { + override suspend fun fetch(userWallet: UserWallet, refresh: Boolean): CompletionResult { return fetch(listOf(userWallet), refresh) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletAmountsRepository.kt index a054ed0ff2..924bbb5191 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletAmountsRepository.kt @@ -24,10 +24,7 @@ interface WalletAmountsRepository { * @param userWallet [UserWallet] which will be used to get the list of associated [WalletStoreModel] * @param fiatCurrency current app [FiatCurrency] * */ - suspend fun updateAmountsForUserWallet( - userWallet: UserWallet, - fiatCurrency: FiatCurrency, - ): CompletionResult + suspend fun updateAmountsForUserWallet(userWallet: UserWallet, fiatCurrency: FiatCurrency): CompletionResult suspend fun updateAmountsForWalletStores( walletStores: List, diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletManagersRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletManagersRepository.kt index 0d8a2044be..c49f863277 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletManagersRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletManagersRepository.kt @@ -17,10 +17,7 @@ interface WalletManagersRepository { suspend fun delete(userWalletIds: List): CompletionResult - suspend fun delete( - userWalletId: UserWalletId, - blockchain: Blockchain, - ): CompletionResult + suspend fun delete(userWalletId: UserWalletId, blockchain: Blockchain): CompletionResult companion object } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletStoresRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletStoresRepository.kt index 9e8a8a9287..8359759a0a 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletStoresRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletStoresRepository.kt @@ -22,10 +22,7 @@ interface WalletStoresRepository { suspend fun clear(): CompletionResult - suspend fun storeOrUpdate( - userWalletId: UserWalletId, - walletStore: WalletStoreModel, - ): CompletionResult + suspend fun storeOrUpdate(userWalletId: UserWalletId, walletStore: WalletStoreModel): CompletionResult companion object } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index d2936d9dcc..30de69eec5 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -160,21 +160,19 @@ internal class DefaultWalletAmountsRepository( } } - private suspend fun fetchAmountsForUserWallets( - userWallets: List, - ): CompletionResult = withContext(Dispatchers.Default) { - userWallets.map { async { fetchAmountsForUserWallet(it) } }.awaitAll().fold() - } + private suspend fun fetchAmountsForUserWallets(userWallets: List): CompletionResult = + withContext(Dispatchers.Default) { + userWallets.map { async { fetchAmountsForUserWallet(it) } }.awaitAll().fold() + } - private suspend fun fetchAmountsForUserWallet( - userWallet: UserWallet, - ): CompletionResult = withContext(Dispatchers.Default) { - val userWalletId = userWallet.walletId - val scanResponse = userWallet.scanResponse - val walletStores = getWalletStores(listOf(userWallet)) + private suspend fun fetchAmountsForUserWallet(userWallet: UserWallet): CompletionResult = + withContext(Dispatchers.Default) { + val userWalletId = userWallet.walletId + val scanResponse = userWallet.scanResponse + val walletStores = getWalletStores(listOf(userWallet)) - fetchAmountForWalletStores(userWalletId, scanResponse, walletStores) - } + fetchAmountForWalletStores(userWalletId, scanResponse, walletStores) + } private suspend fun fetchAmountForWalletStores( userWalletId: UserWalletId, @@ -286,7 +284,9 @@ internal class DefaultWalletAmountsRepository( rent = rentProvider.rentAmount(), exemptionAmount = rentExempt, ) - } else null, + } else { + null + }, ) } is Failure -> Unit @@ -295,39 +295,36 @@ internal class DefaultWalletAmountsRepository( return CompletionResult.Success(Unit) } - private suspend fun updateWalletStoreWithError( - walletStore: WalletStoreModel, - wallet: Wallet, - error: TangemError, - ) = withContext(Dispatchers.Default) { - Timber.e( - error, - """ + private suspend fun updateWalletStoreWithError(walletStore: WalletStoreModel, wallet: Wallet, error: TangemError) = + withContext(Dispatchers.Default) { + Timber.e( + error, + """ Unable to fetch amounts |- User wallet id: ${walletStore.userWalletId} |- Blockchain: ${walletStore.blockchain} |- Derivation path: ${walletStore.derivationPath?.rawPath} - """.trimIndent(), - ) + """.trimIndent(), + ) - if (error is BlockchainSdkError) { - WalletStoresStorage.update { prevState -> - prevState.replaceWalletStore( - walletStoreToUpdate = walletStore, - update = { - it.updateWithError( - wallet = wallet, - error = error, - ) - }, - ) + if (error is BlockchainSdkError) { + WalletStoresStorage.update { prevState -> + prevState.replaceWalletStore( + walletStoreToUpdate = walletStore, + update = { + it.updateWithError( + wallet = wallet, + error = error, + ) + }, + ) + } + + CompletionResult.Success(Unit) + } else { + CompletionResult.Failure(error) } - - CompletionResult.Success(Unit) - } else { - CompletionResult.Failure(error) } - } private suspend fun updateWalletStoreWithAmounts( walletStore: WalletStoreModel, @@ -359,53 +356,51 @@ internal class DefaultWalletAmountsRepository( CompletionResult.Success(Unit) } - private suspend fun updateWalletStoreWithMissedDerivation( - walletStore: WalletStoreModel, - ) = withContext(Dispatchers.Default) { - Timber.e( - """ + private suspend fun updateWalletStoreWithMissedDerivation(walletStore: WalletStoreModel) = + withContext(Dispatchers.Default) { + Timber.e( + """ Missed derivation |- User wallet id: ${walletStore.userWalletId} |- Blockchain: ${walletStore.blockchain} |- Derivation path: ${walletStore.derivationPath?.rawPath} - """.trimIndent(), - ) - - WalletStoresStorage.update { prevState -> - prevState.replaceWalletStore( - walletStoreToUpdate = walletStore, - update = { - it.updateWithMissedDerivation() - }, + """.trimIndent(), ) + + WalletStoresStorage.update { prevState -> + prevState.replaceWalletStore( + walletStoreToUpdate = walletStore, + update = { + it.updateWithMissedDerivation() + }, + ) + } + + CompletionResult.Success(Unit) } - CompletionResult.Success(Unit) - } - - private suspend fun updateWalletStoreWithUnreachable( - walletStore: WalletStoreModel, - ) = withContext(Dispatchers.Default) { - Timber.e( - """ + private suspend fun updateWalletStoreWithUnreachable(walletStore: WalletStoreModel) = + withContext(Dispatchers.Default) { + Timber.e( + """ Wallet manager is null |- User wallet id: ${walletStore.userWalletId} |- Blockchain: ${walletStore.blockchain} |- Derivation path: ${walletStore.derivationPath?.rawPath} - """.trimIndent(), - ) - - WalletStoresStorage.update { prevState -> - prevState.replaceWalletStore( - walletStoreToUpdate = walletStore, - update = { - it.updateWithUnreachable() - }, + """.trimIndent(), ) - } - CompletionResult.Success(Unit) - } + WalletStoresStorage.update { prevState -> + prevState.replaceWalletStore( + walletStoreToUpdate = walletStore, + update = { + it.updateWithUnreachable() + }, + ) + } + + CompletionResult.Success(Unit) + } private suspend fun updateWalletStoresWithFiatRates( walletStores: List, @@ -428,48 +423,44 @@ internal class DefaultWalletAmountsRepository( } } - private suspend fun updateWalletStoreWithRent( - walletStore: WalletStoreModel, - rent: WalletStoreModel.WalletRent?, - ) = withContext(Dispatchers.Default) { - Timber.d( - """ + private suspend fun updateWalletStoreWithRent(walletStore: WalletStoreModel, rent: WalletStoreModel.WalletRent?) = + withContext(Dispatchers.Default) { + Timber.d( + """ Fetched wallet rent |- User wallet id: ${walletStore.userWalletId} |- Blockchain: ${walletStore.blockchain} |- Derivation path: ${walletStore.derivationPath?.rawPath} |- Rent: $rent - """.trimIndent(), - ) + """.trimIndent(), + ) - if (rent != walletStore.walletRent) { - WalletStoresStorage.update { prevState -> - prevState.replaceWalletStore( - walletStoreToUpdate = walletStore, - update = { - it.updateWithRent(rent) - }, - ) - } - } - } - - private suspend fun updateWalletManagerInStorage( - userWalletId: UserWalletId, - walletManager: WalletManager, - ) = withContext(Dispatchers.Default) { - WalletManagerStorage.update { prevManagers -> - val newManagersForUserWallet = prevManagers[userWalletId].orEmpty().toMutableList().apply { - replaceByOrAdd(walletManager) { - it.wallet.blockchain == walletManager.wallet.blockchain + if (rent != walletStore.walletRent) { + WalletStoresStorage.update { prevState -> + prevState.replaceWalletStore( + walletStoreToUpdate = walletStore, + update = { + it.updateWithRent(rent) + }, + ) } } + } - prevManagers.apply { - set(userWalletId, newManagersForUserWallet) + private suspend fun updateWalletManagerInStorage(userWalletId: UserWalletId, walletManager: WalletManager) = + withContext(Dispatchers.Default) { + WalletManagerStorage.update { prevManagers -> + val newManagersForUserWallet = prevManagers[userWalletId].orEmpty().toMutableList().apply { + replaceByOrAdd(walletManager) { + it.wallet.blockchain == walletManager.wallet.blockchain + } + } + + prevManagers.apply { + set(userWalletId, newManagersForUserWallet) + } } } - } private suspend fun getWalletStores(userWallets: List): List { return userWallets.map { it.walletId }.flatMap { userWalletId -> diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt index c7848db278..a09ea7abd2 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt @@ -125,10 +125,7 @@ internal class DefaultWalletManagersRepository( } } - override suspend fun delete( - userWalletId: UserWalletId, - blockchain: Blockchain, - ): CompletionResult = catching { + override suspend fun delete(userWalletId: UserWalletId, blockchain: Blockchain): CompletionResult = catching { deleteInternal(userWalletId, blockchain) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt index 4346396f56..849aad6056 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt @@ -14,17 +14,13 @@ import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.getPendingTransactions import java.math.BigDecimal -internal fun WalletDataModel.updateWithFiatRate( - fiatRate: BigDecimal?, -): WalletDataModel { +internal fun WalletDataModel.updateWithFiatRate(fiatRate: BigDecimal?): WalletDataModel { return this.copy( fiatRate = fiatRate, ) } -internal fun List.updateWithFiatRates( - fiatRates: Map, -): List { +internal fun List.updateWithFiatRates(fiatRates: Map): List { return this.map { walletData -> val rate = fiatRates[walletData.currency.coinId]?.toBigDecimal() walletData.updateWithFiatRate(rate) @@ -40,9 +36,7 @@ internal fun WalletDataModel.updateWithTxHistory(wallet: Wallet): WalletDataMode ) } -internal fun List.updateWithTxHistories( - wallet: Wallet, -): List { +internal fun List.updateWithTxHistories(wallet: Wallet): List { return this.map { walletData -> walletData.updateWithTxHistory(wallet) } @@ -114,10 +108,7 @@ internal fun List.updateWithDemoAmounts(wallet: Wallet): List { @@ -141,18 +132,13 @@ internal fun WalletDataModel.updateWithError( ) } -internal fun List.updateWithError( - wallet: Wallet, - error: TangemError, -): List { +internal fun List.updateWithError(wallet: Wallet, error: TangemError): List { return this.map { walletData -> walletData.updateWithError(wallet, error) } } -internal fun WalletDataModel.updateWithSelf( - newWalletData: WalletDataModel, -): WalletDataModel { +internal fun WalletDataModel.updateWithSelf(newWalletData: WalletDataModel): WalletDataModel { val oldWalletData = this val oldStatus = oldWalletData.status return oldWalletData.copy( @@ -191,9 +177,7 @@ internal fun List.updateWithUnreachable(): List.updateWithSelf( - newWalletsData: List, -): List { +internal fun List.updateWithSelf(newWalletsData: List): List { val oldWalletsData = this val updatedWalletsData = arrayListOf() diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt index efcd36e402..f77470a6f0 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt @@ -29,10 +29,7 @@ internal inline fun HashMap>.replaceWalletS } } -internal fun WalletStoreModel.updateWithError( - wallet: Wallet, - error: TangemError, -): WalletStoreModel { +internal fun WalletStoreModel.updateWithError(wallet: Wallet, error: TangemError): WalletStoreModel { return this.copy( walletsData = walletsData.updateWithError( wallet = wallet, @@ -41,41 +38,31 @@ internal fun WalletStoreModel.updateWithError( ) } -internal fun WalletStoreModel.updateWithTxHistories( - wallet: Wallet, -): WalletStoreModel { +internal fun WalletStoreModel.updateWithTxHistories(wallet: Wallet): WalletStoreModel { return this.copy( walletsData = walletsData.updateWithTxHistories(wallet = wallet), ) } -internal fun WalletStoreModel.updateWithAmounts( - wallet: Wallet, -): WalletStoreModel { +internal fun WalletStoreModel.updateWithAmounts(wallet: Wallet): WalletStoreModel { return this.copy( walletsData = walletsData.updateWithAmounts(wallet = wallet), ) } -internal fun WalletStoreModel.updateWithDemoAmounts( - wallet: Wallet, -): WalletStoreModel { +internal fun WalletStoreModel.updateWithDemoAmounts(wallet: Wallet): WalletStoreModel { return this.copy( walletsData = walletsData.updateWithDemoAmounts(wallet = wallet), ) } -internal fun WalletStoreModel.updateWithFiatRates( - rates: Map, -): WalletStoreModel { +internal fun WalletStoreModel.updateWithFiatRates(rates: Map): WalletStoreModel { return this.copy( walletsData = walletsData.updateWithFiatRates(rates), ) } -internal fun WalletStoreModel.updateWithSelf( - newWalletStore: WalletStoreModel, -): WalletStoreModel { +internal fun WalletStoreModel.updateWithSelf(newWalletStore: WalletStoreModel): WalletStoreModel { val oldStore = this return oldStore.copy( derivationPath = newWalletStore.derivationPath, diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt index 8759dc91d4..1cae897360 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt @@ -287,11 +287,7 @@ class WalletConnectManager { } } - fun signBnb( - id: Long, - data: ByteArray, - sessionData: WCSession, - ) { + fun signBnb(id: Long, data: ByteArray, sessionData: WCSession) { val activeData = sessions[sessionData] ?: return scope.launch { val hash = WalletConnectSdkHelper().signBnbTransaction(data, activeData, cardId).guard { @@ -307,11 +303,7 @@ class WalletConnectManager { } } - fun handlePersonalSignRequest( - message: WCEthereumSignMessage, - session: WalletConnectSession, - id: Long, - ) { + fun handlePersonalSignRequest(message: WCEthereumSignMessage, session: WalletConnectSession, id: Long) { val activeData = sessions[session.session] ?: return scope.launch { val data = WalletConnectSdkHelper().prepareDataForPersonalSign( diff --git a/app/src/main/java/com/tangem/tap/features/BaseFragment.kt b/app/src/main/java/com/tangem/tap/features/BaseFragment.kt index fe5c9a3926..cf8be74484 100644 --- a/app/src/main/java/com/tangem/tap/features/BaseFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/BaseFragment.kt @@ -71,10 +71,13 @@ interface FragmentOnBackPressedHandler { @SuppressLint("FragmentBackPressedCallback") fun Fragment.addBackPressHandler(handler: FragmentOnBackPressedHandler) { - activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - handler.handleOnBackPressed() - } - }) + activity?.onBackPressedDispatcher?.addCallback( + this, + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + handler.handleOnBackPressed() + } + }, + ) view?.findViewById(R.id.toolbar)?.setNavigationOnClickListener { activity?.onBackPressed() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index ab69008a6b..e7eab8cc49 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -275,10 +275,7 @@ class DetailsMiddleware { } } - private suspend fun toggleSaveWallets( - scanResponse: ScanResponse?, - enable: Boolean, - ): CompletionResult { + private suspend fun toggleSaveWallets(scanResponse: ScanResponse?, enable: Boolean): CompletionResult { return if (enable) { saveCurrentWallet(scanResponse, enableAccessCodesSaving = false) } else { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 5adbc797e0..380d7be88b 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -44,9 +44,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { } } -private fun handlePrepareScreen( - action: DetailsAction.PrepareScreen, -): DetailsState { +private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsState { return DetailsState( scanResponse = action.scanResponse, wallets = action.wallets, @@ -64,8 +62,7 @@ private fun handlePrepareCardSettingsScreen( card: CardDTO, cardTypesResolver: CardTypesResolver, state: DetailsState, -): - DetailsState { +): DetailsState { val cardSettingsState = CardSettingsState( cardInfo = card.toCardInfo(cardTypesResolver), manageSecurityState = prepareSecurityOptions(card, cardTypesResolver), @@ -112,10 +109,7 @@ private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypesResolver: Card return !isNotAllowed } -private fun handleEraseWallet( - action: DetailsAction.ResetToFactory, - state: DetailsState, -): DetailsState { +private fun handleEraseWallet(action: DetailsAction.ResetToFactory, state: DetailsState): DetailsState { return when (action) { is DetailsAction.ResetToFactory.Confirm -> state.copy(cardSettingsState = state.cardSettingsState?.copy(resetConfirmed = action.confirmed)) @@ -123,10 +117,7 @@ private fun handleEraseWallet( } } -private fun handleSecurityAction( - action: DetailsAction.ManageSecurity, - state: DetailsState, -): DetailsState { +private fun handleSecurityAction(action: DetailsAction.ManageSecurity, state: DetailsState): DetailsState { return when (action) { is DetailsAction.ManageSecurity.SelectOption -> { val manageSecurityState = state.cardSettingsState?.manageSecurityState?.copy( @@ -155,10 +146,7 @@ private fun handleSecurityAction( } } -private fun handlePrivacyAction( - action: DetailsAction.AppSettings, - state: DetailsState, -): DetailsState { +private fun handlePrivacyAction(action: DetailsAction.AppSettings, state: DetailsState): DetailsState { return when (action) { is DetailsAction.AppSettings.SwitchPrivacySetting -> state.copy( appSettingsState = when (action.setting) { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index 0957c8f2dc..014ca34512 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -285,11 +285,7 @@ class WalletConnectMiddleware { } } - private fun handleScanResponse( - scanResponse: ScanResponse, - session: WalletConnectSession, - blockchain: Blockchain, - ) { + private fun handleScanResponse(scanResponse: ScanResponse, session: WalletConnectSession, blockchain: Blockchain) { val card = scanResponse.card if (!scanResponse.cardTypesResolver.isMultiwalletAllowed()) { store.dispatchOnMain(WalletConnectAction.UnsupportedCard) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectReducer.kt index a4990f5d8b..ed1573f3bb 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectReducer.kt @@ -3,10 +3,7 @@ package com.tangem.tap.features.details.redux.walletconnect import org.rekotlin.Action object WalletConnectReducer { - fun reduce( - action: Action, - state: WalletConnectState, - ): WalletConnectState { + fun reduce(action: Action, state: WalletConnectState): WalletConnectState { if (action !is WalletConnectAction) return state return when (action) { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt index 70e41f4f0c..5c32fdb2cd 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt @@ -123,7 +123,7 @@ data class WcTransactionData( enum class WcTransactionType { EthSignTransaction, - EthSendTransaction + EthSendTransaction, } data class WcPersonalSignData( @@ -156,5 +156,5 @@ data class TradeData( val price: String, val quantity: String, val amount: String, - val symbol: String + val symbol: String, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsFragment.kt index 3302facf0b..5ced6c832e 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsFragment.kt @@ -30,11 +30,7 @@ class AppSettingsFragment : Fragment(), StoreSubscriber { viewModel.checkBiometricsStatus() } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(requireContext()).apply { setContent { isTransitionGroup = true diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsScreen.kt index 84ff3c3dba..9255526f4a 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsScreen.kt @@ -159,9 +159,7 @@ private fun onCheckedChange( // region Preview @Composable -private fun AppSettingsScreenSample( - modifier: Modifier = Modifier, -) { +private fun AppSettingsScreenSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary), @@ -199,9 +197,7 @@ private fun AppSettingsScreenPreview_Dark() { } @Composable -private fun AppSettingsScreen_EnrollBiometrics_Sample( - modifier: Modifier = Modifier, -) { +private fun AppSettingsScreen_EnrollBiometrics_Sample(modifier: Modifier = Modifier) { Column(modifier = modifier.background(TangemTheme.colors.background.primary)) { AppSettingsScreen( state = AppSettingsScreenState( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/EnrollBiometricsCard.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/EnrollBiometricsCard.kt index b541b88894..1386a364d7 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/EnrollBiometricsCard.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/EnrollBiometricsCard.kt @@ -63,9 +63,7 @@ internal fun EnrollBiometricsCard(onClick: () -> Unit) { // region Preview @Composable -private fun EnrollBiometricsCardSample( - modifier: Modifier = Modifier, -) { +private fun EnrollBiometricsCardSample(modifier: Modifier = Modifier) { Column( modifier = modifier.background(TangemTheme.colors.background.secondary), ) { diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsAlertDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsAlertDialog.kt index 0ed7409abd..c82113133b 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsAlertDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/SettingsAlertDialog.kt @@ -66,9 +66,7 @@ internal fun SettingsAlertDialog( // region Preview @Composable -private fun SettingsAlertDialogSample( - modifier: Modifier = Modifier, -) { +private fun SettingsAlertDialogSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary), diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsFragment.kt index 15a943d590..e67d9b5adf 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsFragment.kt @@ -31,11 +31,7 @@ class CardSettingsFragment : Fragment(), StoreSubscriber { exitTransition = inflater.inflateTransition(android.R.transition.fade) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(requireContext()).apply { setContent { isTransitionGroup = true diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/common/DetailsComposeElements.kt b/app/src/main/java/com/tangem/tap/features/details/ui/common/DetailsComposeElements.kt index 34ed64cceb..616fbaafc9 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/common/DetailsComposeElements.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/common/DetailsComposeElements.kt @@ -76,10 +76,7 @@ fun SettingsScreensScaffold( } @Composable -fun ScreenTitle( - titleRes: Int, - modifier: Modifier = Modifier, -) { +fun ScreenTitle(titleRes: Int, modifier: Modifier = Modifier) { Text( text = stringResource(id = titleRes), modifier = modifier.padding(start = 20.dp, end = 20.dp), @@ -111,12 +108,7 @@ fun EmptyTopBarWithNavigation( } @Composable -fun DetailsMainButton( - title: String, - onClick: () -> Unit, - modifier: Modifier = Modifier, - enabled: Boolean = true, -) { +fun DetailsMainButton(title: String, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true) { Button( onClick = onClick, modifier = modifier diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt index 1580b87400..3c37bacd20 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt @@ -27,11 +27,7 @@ class DetailsFragment : Fragment(), StoreSubscriber { exitTransition = inflater.inflateTransition(android.R.transition.fade) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(requireContext()).apply { setContent { isTransitionGroup = true diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt index 631f292c66..d4526edf76 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt @@ -159,10 +159,7 @@ fun DetailsItem(item: SettingsElement, appCurrency: String, onItemsClick: () -> } @Composable -fun TangemSocialAccounts( - links: List, - onSocialNetworkClick: (SocialNetworkLink) -> Unit, -) { +fun TangemSocialAccounts(links: List, onSocialNetworkClick: (SocialNetworkLink) -> Unit) { LazyRow(modifier = Modifier.padding(start = 8.dp, end = 8.dp)) { items(links) { Icon( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt index df8b8979be..ce8e1fd1ef 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt @@ -33,7 +33,7 @@ enum class SettingsElement( LinkMoreCards(R.drawable.ic_more_cards, R.string.details_row_title_create_backup), TermsOfService(R.drawable.ic_text, R.string.disclaimer_title), // General Terms of Service of the App PrivacyPolicy(R.drawable.ic_lock_24, R.string.details_row_privacy_policy), - TesterMenu(R.drawable.ic_alert_24, R.string.tester_menu) + TesterMenu(R.drawable.ic_alert_24, R.string.tester_menu), } @Immutable diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardFragment.kt index 8ea18c0604..df48063920 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardFragment.kt @@ -30,11 +30,7 @@ class ResetCardFragment : Fragment(), StoreSubscriber { exitTransition = inflater.inflateTransition(android.R.transition.fade) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(requireContext()).apply { setContent { isTransitionGroup = true diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt index c73f6bf836..d64bf444ca 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt @@ -134,9 +134,7 @@ fun ResetCardView(state: ResetCardScreenState) { // region Preview @Composable -private fun ResetCardScreenSample( - modifier: Modifier = Modifier, -) { +private fun ResetCardScreenSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.secondary), diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeFragment.kt index dcddb62a2f..77eb446ad1 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/securitymode/SecurityModeFragment.kt @@ -30,11 +30,7 @@ class SecurityModeFragment : Fragment(), StoreSubscriber { exitTransition = inflater.inflateTransition(android.R.transition.fade) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(requireContext()).apply { setContent { isTransitionGroup = true diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/QrScanFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/QrScanFragment.kt index 927adfe845..a08b9af8b2 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/QrScanFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/QrScanFragment.kt @@ -25,18 +25,17 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } - activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - store.dispatch(NavigationAction.PopBackTo()) - } - }) + activity?.onBackPressedDispatcher?.addCallback( + this, + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + store.dispatch(NavigationAction.PopBackTo()) + } + }, + ) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View? { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { if (!permissionIsGranted()) requestPermission() scannerView = ZXingScannerView(activity) @@ -62,11 +61,7 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler { } } - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray, - ) { + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { if (requestCode != CameraView.PERMISSION_REQUEST_CODE) return if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) { diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt index 3ed76fdee2..4d5354e3f4 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectFragment.kt @@ -31,11 +31,7 @@ class WalletConnectFragment : Fragment(), StoreSubscriber { exitTransition = inflater.inflateTransition(android.R.transition.fade) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(requireContext()).apply { setContent { isTransitionGroup = true 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 caefb4546a..7b14107334 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 @@ -65,10 +65,7 @@ fun WalletConnectScreen(state: WalletConnectScreenState, onBackClick: () -> Unit } @Composable -private fun AddSessionFab( - onAddSession: () -> Unit, - modifier: Modifier = Modifier, -) { +private fun AddSessionFab(onAddSession: () -> Unit, modifier: Modifier = Modifier) { FloatingActionButton( onClick = onAddSession, backgroundColor = colorResource(id = R.color.button_primary), diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ChooseNetworkDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ChooseNetworkDialog.kt index 8e0ffe0f4a..ba70ae5a54 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ChooseNetworkDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ChooseNetworkDialog.kt @@ -10,11 +10,7 @@ import com.tangem.tap.store import com.tangem.wallet.R object ChooseNetworkDialog { - fun create( - session: WalletConnectSession, - networks: List, - context: Context, - ): AlertDialog { + fun create(session: WalletConnectSession, networks: List, context: Context): AlertDialog { return AlertDialog.Builder(context) .setTitle(context.getString(R.string.wallet_connect_select_network)) .setNegativeButton(context.getString(R.string.common_cancel)) { _, _ -> diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt index b88b4488ab..fb06687b57 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt @@ -13,7 +13,8 @@ import java.util.* enum class DisclaimerType { Tangem, SaltPay, - Start2Coin; + Start2Coin, + ; companion object { fun get(cardDTO: CardDTO): DisclaimerType { diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt index 4e07832feb..abc9d83f27 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerWebViewClient.kt @@ -42,11 +42,7 @@ class DisclaimerWebViewClient : WebViewClient() { loadedUrl = url } - override fun onReceivedError( - view: WebView?, - resourceRequest: WebResourceRequest?, - error: WebResourceError?, - ) { + override fun onReceivedError(view: WebView?, resourceRequest: WebResourceRequest?, error: WebResourceError?) { super.onReceivedError(view, resourceRequest, error) error?.let { progressState = ProgressState.Error } } diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt index b32b6a6ab2..4626dbbc44 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -33,11 +33,7 @@ class HomeFragment : Fragment(), StoreSubscriber { store.dispatch(HomeAction.Init) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(inflater.context).apply { setContent { BackHandler { diff --git a/app/src/main/java/com/tangem/tap/features/home/RegionProvider.kt b/app/src/main/java/com/tangem/tap/features/home/RegionProvider.kt index 5c8483c259..ef3ab25517 100644 --- a/app/src/main/java/com/tangem/tap/features/home/RegionProvider.kt +++ b/app/src/main/java/com/tangem/tap/features/home/RegionProvider.kt @@ -14,7 +14,7 @@ interface RegionProvider { } class RegionService( - private val providers: List + private val providers: List, ) : RegionProvider { override fun getRegion(): String? { for (provider in providers) { diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt index 2a545e623b..d119f5b863 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt @@ -138,10 +138,7 @@ fun StoriesWalletForEveryone(stepDuration: Int) { } @Composable -private fun SplitContent( - topContent: @Composable () -> Unit, - bottomContent: @Composable () -> Unit, -) { +private fun SplitContent(topContent: @Composable () -> Unit, bottomContent: @Composable () -> Unit) { Column( modifier = Modifier .fillMaxSize(), @@ -154,11 +151,7 @@ private fun SplitContent( } @Composable -private fun TopContent( - titleText: String, - subtitleText: AnnotatedString, - isDarkBackground: Boolean, -) { +private fun TopContent(titleText: String, subtitleText: AnnotatedString, isDarkBackground: Boolean) { SpacerH32() StoriesTitleText( text = titleText, @@ -173,10 +166,7 @@ private fun TopContent( @Suppress("MagicNumber") @Composable -private fun StoriesTitleText( - text: String, - isDarkBackground: Boolean, -) { +private fun StoriesTitleText(text: String, isDarkBackground: Boolean) { StoriesTextAnimation( slideInDuration = 500, slideInDelay = 150, @@ -215,11 +205,7 @@ private fun StoriesSubtitleText(subtitleText: AnnotatedString) { } @Composable -private fun StoriesImage( - @DrawableRes drawableResId: Int, - isDarkBackground: Boolean, - modifier: Modifier = Modifier, -) { +private fun StoriesImage(@DrawableRes drawableResId: Int, isDarkBackground: Boolean, modifier: Modifier = Modifier) { Image( painter = painterResource(id = drawableResId), contentDescription = null, diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt index 87cee39eb4..d84debb7c6 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt @@ -25,10 +25,7 @@ import com.tangem.tap.features.home.compose.HorizontalSlidingImage import com.tangem.wallet.R @Composable -fun StoriesCurrenciesContent( - paused: Boolean, - duration: Int, -) { +fun StoriesCurrenciesContent(paused: Boolean, duration: Int) { val currencyDrawableList = remember { listOf( R.drawable.currency0, @@ -72,10 +69,7 @@ fun StoriesCurrenciesContent( @Suppress("MagicNumber") @Composable -fun StoriesWeb3Content( - paused: Boolean, - duration: Int, -) { +fun StoriesWeb3Content(paused: Boolean, duration: Int) { val dappsItemList = remember { listOf( R.drawable.dapps0, diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt index 5dcfbb5f1f..6678901f43 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt @@ -36,11 +36,7 @@ import com.tangem.wallet.R @Suppress("LongMethod", "ComplexMethod", "MagicNumber") @Composable -fun FirstStoriesContent( - isPaused: Boolean, - duration: Int, - onHideContent: (Boolean) -> Unit, -) { +fun FirstStoriesContent(isPaused: Boolean, duration: Int, onHideContent: (Boolean) -> Unit) { val screenState = remember { mutableStateOf(StartingScreenState.INIT) } val progress = remember { Animatable(0f) } diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt index fcb0fce154..ef021f5dc6 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt @@ -15,10 +15,7 @@ import com.tangem.wallet.R [REDACTED_AUTHOR] */ @Composable -fun FloatingCardsContent( - isPaused: Boolean, - stepDuration: Int, -) { +fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int) { val imageBitmap = asImageBitmap(R.drawable.card_placeholder_wallet) val cards = listOf( FloatingCard.first(), @@ -50,12 +47,7 @@ private object FloatingCard { @Suppress("TopLevelComposableFunctions") @Composable - fun Item( - isPaused: Boolean, - stepDuration: Int, - imageBitmap: ImageBitmap, - cardValues: CardValues, - ) { + fun Item(isPaused: Boolean, stepDuration: Int, imageBitmap: ImageBitmap, cardValues: CardValues) { Image( bitmap = imageBitmap, contentDescription = "Floating Tangem card", diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt index 4692fa91aa..f92adcf9d1 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt @@ -38,8 +38,8 @@ fun StoriesProgressBar( targetValue = 1f, animationSpec = tween( durationMillis = (stepDuration * (1f - progress.value)).toInt(), - easing = LinearEasing - ) + easing = LinearEasing, + ), ) progress.snapTo(0f) onStepFinish() @@ -57,7 +57,7 @@ fun StoriesProgressBar( modifier = Modifier .height(2.dp) .weight(1f) - .background(Color.White.copy(alpha = 0.4f)) + .background(Color.White.copy(alpha = 0.4f)), ) { Box( modifier = Modifier diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingSaltPayHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingSaltPayHelper.kt index 5a6132c72a..53c844cd40 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingSaltPayHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingSaltPayHelper.kt @@ -14,10 +14,7 @@ import com.tangem.tap.preferencesStorage */ object OnboardingSaltPayHelper { - suspend fun isOnboardingCase( - scanResponse: ScanResponse, - manager: SaltPayActivationManager, - ): Result { + suspend fun isOnboardingCase(scanResponse: ScanResponse, manager: SaltPayActivationManager): Result { return try { val updatedStep = manager.update(SaltPayActivationStep.None, null).successOr { return it } @@ -37,14 +34,10 @@ object OnboardingSaltPayHelper { } @Suppress("UnusedPrivateMember") - fun testProceedToOnboarding( - scanResponse: ScanResponse, - manager: SaltPayActivationManager, - ): Result = Result.Success(true) + fun testProceedToOnboarding(scanResponse: ScanResponse, manager: SaltPayActivationManager): Result = + Result.Success(true) @Suppress("UnusedPrivateMember") - fun testProceedToMainScreen( - scanResponse: ScanResponse, - manager: SaltPayActivationManager, - ): Result = Result.Success(false) + fun testProceedToMainScreen(scanResponse: ScanResponse, manager: SaltPayActivationManager): Result = + Result.Success(false) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index 3549ea11ab..39fea7dbfd 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -108,28 +108,27 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { tvBody.text = "" } - private fun setupCreateWalletState(state: OnboardingNoteState) = - with(mainBinding.onboardingActionContainer) { - btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) - btnMainAction.setOnClickListener { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) - store.dispatch(OnboardingNoteAction.CreateWallet) - } - btnAlternativeAction.setText(R.string.onboarding_button_what_does_it_mean) - btnAlternativeAction.setOnClickListener { } - - btnRefreshBalanceWidget.mainView.setOnClickListener(null) - - tvHeader.setText(R.string.onboarding_create_wallet_header) - tvBody.setText(R.string.onboarding_create_wallet_body) - - mainBinding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable( - requireContext().getDrawableCompat(R.drawable.shape_circle), - ) - updateConstraints(state.currentStep, R.layout.lp_onboarding_create_wallet) - - btnAlternativeAction.isVisible = false // temporary + private fun setupCreateWalletState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { + btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) + btnMainAction.setOnClickListener { + Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) + store.dispatch(OnboardingNoteAction.CreateWallet) } + btnAlternativeAction.setText(R.string.onboarding_button_what_does_it_mean) + btnAlternativeAction.setOnClickListener { } + + btnRefreshBalanceWidget.mainView.setOnClickListener(null) + + tvHeader.setText(R.string.onboarding_create_wallet_header) + tvBody.setText(R.string.onboarding_create_wallet_body) + + mainBinding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable( + requireContext().getDrawableCompat(R.drawable.shape_circle), + ) + updateConstraints(state.currentStep, R.layout.lp_onboarding_create_wallet) + + btnAlternativeAction.isVisible = false // temporary + } private fun setupTopUpWalletState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { if (state.isBuyAllowed) { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 94fe803ccc..4dad678741 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -193,10 +193,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } } -private fun updateScanResponseAfterBackup( - scanResponse: ScanResponse, - backupState: BackupState, -): ScanResponse { +private fun updateScanResponseAfterBackup(scanResponse: ScanResponse, backupState: BackupState): ScanResponse { val card = if (backupState.backupCardsNumber > 0) { val cardsCount = backupState.backupCardsNumber scanResponse.card.copy( @@ -412,10 +409,7 @@ private fun finishCardsActivationForDiscardedUnfinishedBackup(cardId: String) { /** * SaltPay state maybe not initialized if backup resumed from ResumeFoundUnfinishedBackup action */ -private fun initSaltPayOnBackupFinishedIfNeeded( - scanResponse: ScanResponse?, - state: OnboardingWalletState, -) { +private fun initSaltPayOnBackupFinishedIfNeeded(scanResponse: ScanResponse?, state: OnboardingWalletState) { if (state.backupState.isInterruptedBackup) return if (scanResponse == null) return diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt index dcb4044499..409ca000e6 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt @@ -131,9 +131,7 @@ class SaltPayActivationManager( .tryExtractError() } - suspend fun sendTransactions( - signedTransactions: List, - ): BlockchainResult> { + suspend fun sendTransactions(signedTransactions: List): BlockchainResult> { return gnosisRegistrator.sendTransactions(signedTransactions) } @@ -208,13 +206,12 @@ class SaltPayActivationManager( ) } - private fun makeRegisterKYCRequest(): RegisterKYCRequest = - RegisterKYCRequest( - cardId = cardId, - publicKey = cardPublicKey, - kycProvider = "UTORG", - kycRefId = kycUrlProvider.kycRefId, - ) + private fun makeRegisterKYCRequest(): RegisterKYCRequest = RegisterKYCRequest( + cardId = cardId, + publicKey = cardPublicKey, + kycProvider = "UTORG", + kycRefId = kycUrlProvider.kycRefId, + ) companion object { fun stub(): SaltPayActivationManager = SaltPayActivationManager( diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayRegistrationTask.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayRegistrationTask.kt index 11a0a30404..fb4bd50ed9 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayRegistrationTask.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayRegistrationTask.kt @@ -55,10 +55,7 @@ class SaltPayRegistrationTask( } } - private fun attestWallet( - session: CardSession, - callback: CompletionCallback, - ) { + private fun attestWallet(session: CardSession, callback: CompletionCallback) { val card = session.environment.card.guard { callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead())) return diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt index 368cb6a3a3..537ed92d90 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt @@ -166,14 +166,10 @@ class WalletBackupAnimator( private enum class State { TreeCards, - TwoCards + TwoCards, } - private fun BackupCardType.animateAlpha( - alpha: Float, - duration: Long = 0L, - startDelay: Long = 0L, - ) { + private fun BackupCardType.animateAlpha(alpha: Float, duration: Long = 0L, startDelay: Long = 0L) { when (this) { ORIGIN -> { cardsWidget.getOriginCardView().animate().apply { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupInfoAdapter.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupInfoAdapter.kt index 5b62611410..6ea3bf1a25 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupInfoAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupInfoAdapter.kt @@ -12,22 +12,20 @@ class BackupInfoAdapter : RecyclerView.Adapter() { private val data = backupInfoSnippets - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BackupInfoViewHolder = - BackupInfoViewHolder( - ItemBackupInfoAdapterBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ) - ) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BackupInfoViewHolder = BackupInfoViewHolder( + ItemBackupInfoAdapterBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false, + ), + ) override fun getItemCount(): Int = data.size - override fun onBindViewHolder(holder: BackupInfoViewHolder, position: Int) = - holder.binding.run { - tvHeader.text = root.getString(data[position].header) - tvBody.text = root.getString(data[position].body) - } + override fun onBindViewHolder(holder: BackupInfoViewHolder, position: Int) = holder.binding.run { + tvHeader.text = root.getString(data[position].header) + tvBody.text = root.getString(data[position].body) + } } private class BackupInfo( @@ -38,19 +36,19 @@ private class BackupInfo( private val backupInfoSnippets = listOf( BackupInfo( R.string.onboarding_wallet_info_title_first, - R.string.onboarding_wallet_info_subtitle_first + R.string.onboarding_wallet_info_subtitle_first, ), BackupInfo( R.string.onboarding_wallet_info_title_second, - R.string.onboarding_wallet_info_subtitle_second + R.string.onboarding_wallet_info_subtitle_second, ), BackupInfo( R.string.onboarding_wallet_info_title_third, - R.string.onboarding_wallet_info_subtitle_third + R.string.onboarding_wallet_info_subtitle_third, ), BackupInfo( R.string.onboarding_wallet_info_title_fourth, - R.string.onboarding_wallet_info_subtitle_fourth + R.string.onboarding_wallet_info_subtitle_fourth, ), ) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt index 07939d2ad2..0f8715a237 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt @@ -47,8 +47,10 @@ import com.tangem.wallet.databinding.ViewOnboardingProgressBinding import org.rekotlin.StoreSubscriber @Suppress("LargeClass", "MagicNumber") -class OnboardingWalletFragment : BaseFragment(R.layout.fragment_onboarding_wallet), - StoreSubscriber, FragmentOnBackPressedHandler { +class OnboardingWalletFragment : + BaseFragment(R.layout.fragment_onboarding_wallet), + StoreSubscriber, + FragmentOnBackPressedHandler { private val pbBinding: ViewOnboardingProgressBinding by viewBinding(ViewOnboardingProgressBinding::bind) internal val binding: FragmentOnboardingWalletBinding by viewBinding(FragmentOnboardingWalletBinding::bind) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/WalletCardsWidget.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/WalletCardsWidget.kt index 64479ca66d..8f0bc94325 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/WalletCardsWidget.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/WalletCardsWidget.kt @@ -21,10 +21,7 @@ class WalletCardsWidget( var currentState: WidgetState? = null private set - fun toWelcome( - animate: Boolean = true, - onEnd: () -> Unit = {}, - ) { + fun toWelcome(animate: Boolean = true, onEnd: () -> Unit = {}) { if (currentState == WidgetState.WELCOME) return currentState = WidgetState.WELCOME @@ -34,11 +31,7 @@ class WalletCardsWidget( leapfrogWidget.fold { animator.start() } } - fun toFolded( - animate: Boolean = true, - duration: Long = animDuration, - onEnd: () -> Unit = {}, - ) { + fun toFolded(animate: Boolean = true, duration: Long = animDuration, onEnd: () -> Unit = {}) { if (currentState == WidgetState.FOLDED) return currentState = WidgetState.FOLDED @@ -50,10 +43,7 @@ class WalletCardsWidget( animator.start() } - fun toFan( - animate: Boolean = true, - onEnd: () -> Unit = {}, - ) { + fun toFan(animate: Boolean = true, onEnd: () -> Unit = {}) { if (currentState == WidgetState.FAN) return currentState = WidgetState.FAN @@ -63,11 +53,7 @@ class WalletCardsWidget( leapfrogWidget.fold { animator.start() } } - fun toLeapfrog( - animate: Boolean = true, - onEndFold: () -> Unit = {}, - onEnd: () -> Unit = {}, - ) { + fun toLeapfrog(animate: Boolean = true, onEndFold: () -> Unit = {}, onEnd: () -> Unit = {}) { if (currentState == WidgetState.LEAPFROG) return currentState = WidgetState.LEAPFROG @@ -102,10 +88,7 @@ class WalletCardsWidget( } } - private fun createCardAnimator( - cardType: BackupCardType, - properties: CardProperties, - ): ObjectAnimator { + private fun createCardAnimator(cardType: BackupCardType, properties: CardProperties): ObjectAnimator { val view = getLeapViewByCard(cardType).view val animator = ObjectAnimator.ofPropertyValuesHolder( view, diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletReducer.kt index 89eefd41db..f2552462b6 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletReducer.kt @@ -7,7 +7,9 @@ internal object SaveWalletReducer { fun reduce(action: Action, state: AppState): SaveWalletState { return if (action is SaveWalletAction) { internalReduce(action, state.saveWalletState) - } else state.saveWalletState + } else { + state.saveWalletState + } } private fun internalReduce(action: SaveWalletAction, state: SaveWalletState): SaveWalletState { diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt index 3f0f4f77c4..0a6a076bff 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt @@ -39,10 +39,7 @@ internal class SaveWalletBottomSheetFragment : ComposeBottomSheetFragment Unit, - onCloseClick: () -> Unit, -) { +internal fun SaveWalletScreenContent(showProgress: Boolean, onSaveWalletClick: () -> Unit, onCloseClick: () -> Unit) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Header(onCloseClick = onCloseClick) SpacerHHalf() @@ -89,9 +85,7 @@ private fun Header(onCloseClick: () -> Unit) { } @Composable -private fun Title( - modifier: Modifier = Modifier, -) { +private fun Title(modifier: Modifier = Modifier) { Column( modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally, @@ -113,9 +107,7 @@ private fun Title( } @Composable -private fun Description( - modifier: Modifier = Modifier, -) { +private fun Description(modifier: Modifier = Modifier) { Column( modifier = modifier, verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24), @@ -135,10 +127,7 @@ private fun Description( } @Composable -private fun Footer( - showProgress: Boolean, - onSaveWalletClick: () -> Unit, -) { +private fun Footer(showProgress: Boolean, onSaveWalletClick: () -> Unit) { Column( modifier = Modifier .padding(horizontal = TangemTheme.dimens.spacing16) @@ -163,11 +152,7 @@ private fun Footer( } @Composable -private fun DescriptionItem( - iconPainter: Painter, - title: String, - description: String, -) { +private fun DescriptionItem(iconPainter: Painter, title: String, description: String) { Row( verticalAlignment = Alignment.Top, horizontalArrangement = Arrangement.SpaceEvenly, @@ -197,9 +182,7 @@ private fun DescriptionItem( // region Preview @Composable -private fun SaveWalletScreenContentSample( - modifier: Modifier = Modifier, -) { +private fun SaveWalletScreenContentSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary), diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt index f69e50bf9c..5ca27d5e6c 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt @@ -73,7 +73,7 @@ sealed class AddressPayIdVerifyAction : SendScreenAction { PAY_ID_NOT_REGISTERED, PAY_ID_REQUEST_FAILED, ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN, - ADDRESS_SAME_AS_WALLET + ADDRESS_SAME_AS_WALLET, } data class ChangePasteBtnEnableState(val isEnabled: Boolean) : AddressPayIdVerifyAction() diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt index 727964e0c4..9221d5ef60 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt @@ -41,7 +41,7 @@ class AmountReducer : SendInternalReducer { viewBalanceValue = rescaledBalance.stripZeroPlainString(), mainCurrency = state.createMainCurrency(currency, currencyCanBeSwitched), maxLengthOfAmount = sendState.getDecimals(currency), - cursorAtTheSamePosition = false + cursorAtTheSamePosition = false, ) } MainCurrencyType.CRYPTO -> { @@ -51,7 +51,7 @@ class AmountReducer : SendInternalReducer { viewBalanceValue = state.balanceCrypto.stripZeroPlainString(), mainCurrency = state.createMainCurrency(currency, currencyCanBeSwitched), maxLengthOfAmount = sendState.getDecimals(currency), - cursorAtTheSamePosition = false + cursorAtTheSamePosition = false, ) } } @@ -75,7 +75,7 @@ class AmountReducer : SendInternalReducer { viewAmountValue = InputViewValue(viewValue, action.isUserInput), amountToSendCrypto = action.amountCrypto, cursorAtTheSamePosition = true, - error = null + error = null, ) } is AmountAction.SetAmountError -> state.copy(error = action.error) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt index b59ed31979..583e9f0439 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt @@ -66,11 +66,7 @@ class TransactionExtrasReducer : SendInternalReducer { return updateLastState(sendState.copy(transactionExtrasState = result), result) } - private fun handleXlmMemo( - action: XlmMemo, - sendState: SendState, - infoState: TransactionExtrasState, - ): SendState { + private fun handleXlmMemo(action: XlmMemo, sendState: SendState, infoState: TransactionExtrasState): SendState { fun clearMemo(memo: XlmMemoState): XlmMemoState = memo.copy(text = null, id = null, error = null) val result = when (action) { diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt index 6d0b9bee8a..10ffa2dc51 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt @@ -101,5 +101,5 @@ data class XrpDestinationTagState( enum class TransactionExtraError { INVALID_DESTINATION_TAG, INVALID_XLM_MEMO, - INVALID_BINANCE_MEMO + INVALID_BINANCE_MEMO, } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/FeeState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/FeeState.kt index 79b199a5e8..e9c9472bb4 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/FeeState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/FeeState.kt @@ -21,7 +21,7 @@ data class FeeState( val controlsLayoutIsVisible: Boolean = false, val feeChipGroupIsVisible: Boolean = true, val includeFeeSwitcherIsEnabled: Boolean = true, - val progressState: ProgressState = ProgressState.Done + val progressState: ProgressState = ProgressState.Done, ) : SendScreenState { override val stateId: StateId = StateId.FEE diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/ReceiptState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/ReceiptState.kt index 29a6b2e210..5a9808ea69 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/ReceiptState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/ReceiptState.kt @@ -11,7 +11,7 @@ data class ReceiptState( val crypto: ReceiptCrypto? = null, val tokenFiat: ReceiptTokenFiat? = null, val tokenCrypto: ReceiptTokenCrypto? = null, - val mainCurrency: MainCurrency? = null + val mainCurrency: MainCurrency? = null, ) : SendScreenState { override val stateId: StateId = StateId.RECEIPT } @@ -19,7 +19,7 @@ data class ReceiptState( data class ReceiptSymbols( val fiat: String, val crypto: String, - val token: String? = null + val token: String? = null, ) data class ReceiptFiat( @@ -27,7 +27,7 @@ data class ReceiptFiat( val feeFiat: String, val totalFiat: String, val willSentCrypto: String, - val symbols: ReceiptSymbols + val symbols: ReceiptSymbols, ) data class ReceiptCrypto( @@ -36,14 +36,14 @@ data class ReceiptCrypto( val totalCrypto: String, val feeFiat: String, val willSentFiat: String, - val symbols: ReceiptSymbols + val symbols: ReceiptSymbols, ) data class ReceiptTokenCrypto( val amountToken: String, val feeCoin: String, val totalFiat: String, - val symbols: ReceiptSymbols + val symbols: ReceiptSymbols, ) data class ReceiptTokenFiat( @@ -52,5 +52,5 @@ data class ReceiptTokenFiat( val totalFiat: String, val willSentToken: String, val willSentFeeCoin: String, - val symbols: ReceiptSymbols + val symbols: ReceiptSymbols, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index 055f885169..91376439fc 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -277,104 +277,101 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : } @Suppress("LongMethod", "ComplexMethod") - private fun handleReceiptState( - fg: SendFragment, - state: ReceiptState, - feeProgressState: ProgressState, - ) = with(fg.binding.clReceiptContainer) { - val mainLayout = clReceiptContainer as ViewGroup - val totalLayout = llTotalContainer.llTotal as ViewGroup - val totalTokenLayout = llTotalContainer.flTotalTokenCrypto as ViewGroup + private fun handleReceiptState(fg: SendFragment, state: ReceiptState, feeProgressState: ProgressState) = + with(fg.binding.clReceiptContainer) { + val mainLayout = clReceiptContainer as ViewGroup + val totalLayout = llTotalContainer.llTotal as ViewGroup + val totalTokenLayout = llTotalContainer.flTotalTokenCrypto as ViewGroup - fun getString(id: Int, vararg formatStrings: String): String = mainLayout.getString(id, *formatStrings) + fun getString(id: Int, vararg formatStrings: String): String = mainLayout.getString(id, *formatStrings) - fun roughOrEmpty(value: String): String { - return if (value == UNKNOWN_AMOUNT_SIGN) value else "$ROUGH_SIGN $value" - } - - when (feeProgressState) { - ProgressState.Loading -> { - tvReceiptFeeValue.hide() - pbReceiptFee.show() + fun roughOrEmpty(value: String): String { + return if (value == UNKNOWN_AMOUNT_SIGN) value else "$ROUGH_SIGN $value" } - ProgressState.Done -> { - pbReceiptFee.hide() - tvReceiptFeeValue.show() - } - else -> {} - } - when (state.visibleTypeOfReceipt) { - ReceiptLayoutType.FIAT -> { - val receipt = state.fiat ?: return - - totalLayout.show(true) - totalTokenLayout.show(false) - tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}") - tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}") - llTotalContainer.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}") - - val willSent = getString( - R.string.send_total_subtitle_format, - "${receipt.willSentCrypto} ${receipt.symbols.crypto}", - ) - llTotalContainer.tvWillBeSentValue.update(willSent) - } - ReceiptLayoutType.CRYPTO -> { - val receipt = state.crypto ?: return - - totalLayout.show(true) - totalTokenLayout.show(false) - tvReceiptAmountValue.update("${receipt.amountCrypto} ${receipt.symbols.crypto}") - tvReceiptFeeValue.update("${receipt.feeCrypto} ${receipt.symbols.crypto}") - llTotalContainer.tvTotalValue.update("${receipt.totalCrypto} ${receipt.symbols.crypto}") - - if (receipt.willSentFiat == UNKNOWN_AMOUNT_SIGN) { - llTotalContainer.tvWillBeSentValue.hide() - } else { - llTotalContainer.tvWillBeSentValue.show() - llTotalContainer.tvWillBeSentValue.update( - getString( - R.string.send_total_subtitle_fiat_format, - "${receipt.willSentFiat} ${receipt.symbols.fiat}", - "${receipt.feeFiat} ${receipt.symbols.fiat}", - ), - ) + when (feeProgressState) { + ProgressState.Loading -> { + tvReceiptFeeValue.hide() + pbReceiptFee.show() } + ProgressState.Done -> { + pbReceiptFee.hide() + tvReceiptFeeValue.show() + } + else -> {} } - ReceiptLayoutType.TOKEN_FIAT -> { - val receipt = state.tokenFiat ?: return - totalLayout.show(true) - totalTokenLayout.show(false) - tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}") - tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}") - llTotalContainer.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}") + when (state.visibleTypeOfReceipt) { + ReceiptLayoutType.FIAT -> { + val receipt = state.fiat ?: return - val willSent = getString( - R.string.send_total_subtitle_asset_format, - "${receipt.symbols.token ?: ""} ${receipt.willSentToken}", - "${receipt.symbols.crypto} ${receipt.willSentFeeCoin}", - ) - llTotalContainer.tvWillBeSentValue.update(willSent) - } - ReceiptLayoutType.TOKEN_CRYPTO -> { - val receipt = state.tokenCrypto ?: return + totalLayout.show(true) + totalTokenLayout.show(false) + tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}") + tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}") + llTotalContainer.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}") - totalLayout.show(false) - totalTokenLayout.show(true) + val willSent = getString( + R.string.send_total_subtitle_format, + "${receipt.willSentCrypto} ${receipt.symbols.crypto}", + ) + llTotalContainer.tvWillBeSentValue.update(willSent) + } + ReceiptLayoutType.CRYPTO -> { + val receipt = state.crypto ?: return - tvReceiptAmountValue.update("${receipt.amountToken} ${receipt.symbols.token}") - tvReceiptFeeValue.update("${receipt.feeCoin} ${receipt.symbols.crypto}") + totalLayout.show(true) + totalTokenLayout.show(false) + tvReceiptAmountValue.update("${receipt.amountCrypto} ${receipt.symbols.crypto}") + tvReceiptFeeValue.update("${receipt.feeCrypto} ${receipt.symbols.crypto}") + llTotalContainer.tvTotalValue.update("${receipt.totalCrypto} ${receipt.symbols.crypto}") - val willSent = SpannableStringBuilder() - .bold { - append(roughOrEmpty(receipt.totalFiat)).append(" ") - append(receipt.symbols.fiat) + if (receipt.willSentFiat == UNKNOWN_AMOUNT_SIGN) { + llTotalContainer.tvWillBeSentValue.hide() + } else { + llTotalContainer.tvWillBeSentValue.show() + llTotalContainer.tvWillBeSentValue.update( + getString( + R.string.send_total_subtitle_fiat_format, + "${receipt.willSentFiat} ${receipt.symbols.fiat}", + "${receipt.feeFiat} ${receipt.symbols.fiat}", + ), + ) } - llTotalContainer.tvTotalTokenCryptoValue.update(willSent.toString()) + } + ReceiptLayoutType.TOKEN_FIAT -> { + val receipt = state.tokenFiat ?: return + + totalLayout.show(true) + totalTokenLayout.show(false) + tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}") + tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}") + llTotalContainer.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}") + + val willSent = getString( + R.string.send_total_subtitle_asset_format, + "${receipt.symbols.token ?: ""} ${receipt.willSentToken}", + "${receipt.symbols.crypto} ${receipt.willSentFeeCoin}", + ) + llTotalContainer.tvWillBeSentValue.update(willSent) + } + ReceiptLayoutType.TOKEN_CRYPTO -> { + val receipt = state.tokenCrypto ?: return + + totalLayout.show(false) + totalTokenLayout.show(true) + + tvReceiptAmountValue.update("${receipt.amountToken} ${receipt.symbols.token}") + tvReceiptFeeValue.update("${receipt.feeCoin} ${receipt.symbols.crypto}") + + val willSent = SpannableStringBuilder() + .bold { + append(roughOrEmpty(receipt.totalFiat)).append(" ") + append(receipt.symbols.fiat) + } + llTotalContainer.tvTotalTokenCryptoValue.update(willSent.toString()) + } + else -> {} } - else -> {} } - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrReducer.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrReducer.kt index 8ec0fc117c..a27d16d2db 100644 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/sprinklr/redux/SprinklrReducer.kt @@ -7,7 +7,9 @@ internal object SprinklrReducer { fun reduce(action: Action, state: AppState): SprinklrState { return if (action is SprinklrAction) { internalReduce(action, state.sprinklrState) - } else state.sprinklrState + } else { + state.sprinklrState + } } private fun internalReduce(action: SprinklrAction, state: SprinklrState): SprinklrState { diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt index 685a52d600..b567dce03b 100644 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt +++ b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt @@ -30,10 +30,7 @@ internal class SprinklrActivity : ComposeActivity() { } @Composable - override fun ScreenContent( - state: SprinklrScreenState, - modifier: Modifier, - ) { + override fun ScreenContent(state: SprinklrScreenState, modifier: Modifier) { BackHandler(onBack = state.onNavigateBack) SprinklrScreenContent( modifier = modifier diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenContent.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenContent.kt index f80a4b43f3..5277ba0cea 100644 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenContent.kt +++ b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrScreenContent.kt @@ -10,10 +10,7 @@ import com.tangem.tap.features.sprinklr.ui.webview.SprinklrWebViewClient @SuppressLint("SetJavaScriptEnabled") @Composable -internal fun SprinklrScreenContent( - state: SprinklrScreenState, - modifier: Modifier = Modifier, -) { +internal fun SprinklrScreenContent(state: SprinklrScreenState, modifier: Modifier = Modifier) { WebView( modifier = modifier, state = rememberWebViewState(url = state.initialUrl), diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrViewModel.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrViewModel.kt index 989b813d19..87c033582a 100644 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrViewModel.kt @@ -52,9 +52,11 @@ internal class SprinklrViewModel : ViewModel(), StoreSubscriber { return if (isExternalUrl(url)) { store.dispatchOnMain(NavigationAction.OpenUrl(url)) this - } else when (this) { - is WebContent.Url -> copy(url = url) - else -> WebContent.Url(url) + } else { + when (this) { + is WebContent.Url -> copy(url = url) + else -> WebContent.Url(url) + } } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt index 3dc5ab9c7b..d5c9bfe9c0 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt @@ -65,10 +65,7 @@ private class AddCustomTokenScreen // for simple search @OptIn(ExperimentalMaterialApi::class) @Composable -fun AddCustomTokenScreen( - state: MutableState, - closePopupTrigger: ClosePopupTrigger, -) { +fun AddCustomTokenScreen(state: MutableState, closePopupTrigger: ClosePopupTrigger) { val selectedTestCase = remember { mutableStateOf(TestCase.ContractAddress) } val bottomSheetScaffoldState = rememberBottomSheetScaffoldState( @@ -112,10 +109,7 @@ private suspend fun BottomSheetScaffoldState.toggle() { } @Composable -private fun ScreenContent( - state: MutableState, - closePopupTrigger: ClosePopupTrigger, -) { +private fun ScreenContent(state: MutableState, closePopupTrigger: ClosePopupTrigger) { val scaffoldState = rememberScaffoldState() Scaffold( @@ -158,10 +152,7 @@ private fun ScreenContent( } @Composable -private fun FormFields( - state: MutableState, - closePopupTrigger: ClosePopupTrigger, -) { +private fun FormFields(state: MutableState, closePopupTrigger: ClosePopupTrigger) { val context = LocalContext.current val errorConverter = remember { ModuleMessageConverter(context) } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/HangingOverKeyboardView.kt b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/HangingOverKeyboardView.kt index 269a3177a6..a330583a8b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/HangingOverKeyboardView.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/HangingOverKeyboardView.kt @@ -19,7 +19,7 @@ fun HangingOverKeyboardView( modifier: Modifier = Modifier, keyboardState: State, spaceBetweenKeyboard: Dp = 0.dp, - content: @Composable (BoxScope.() -> Unit) + content: @Composable (BoxScope.() -> Unit), ) { val padding = remember(keyboardState) { when (val state = keyboardState.value) { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/ContractAddressTests.kt b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/ContractAddressTests.kt index 2eb3b4923b..581af5a8df 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/ContractAddressTests.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/ContractAddressTests.kt @@ -21,9 +21,7 @@ import com.tangem.domain.redux.domainStore [REDACTED_AUTHOR] */ @Composable -fun ContractAddressTests( - onItemClick: VoidCallback, -) { +fun ContractAddressTests(onItemClick: VoidCallback) { val casesInfo = listOf( "USDC on ETH" to "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "BUSD on ETH" to "0x4fabb145d64652a948d72533023f6e7a623c7c53", @@ -37,9 +35,7 @@ fun ContractAddressTests( } @Composable -fun SolanaAddressTests( - onItemClick: VoidCallback, -) { +fun SolanaAddressTests(onItemClick: VoidCallback) { val casesInfo = listOf( "USDT (full)" to "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", "USDT (valid - 2/3 of address)" to "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8Ben", @@ -50,10 +46,7 @@ fun SolanaAddressTests( } @Composable -private fun CasesListContent( - casesList: List>, - onItemClick: VoidCallback, -) { +private fun CasesListContent(casesList: List>, onItemClick: VoidCallback) { LazyColumn( content = { item { @@ -96,9 +89,7 @@ fun ResetAllFieldsButton(onItemClick: VoidCallback) { } @Composable -fun ResetContractAddressButton( - onItemClick: VoidCallback, -) { +fun ResetContractAddressButton(onItemClick: VoidCallback) { ActionButton( name = "Set empty address", onClick = { @@ -109,11 +100,7 @@ fun ResetContractAddressButton( } @Composable -private fun ContractAddressButton( - name: String, - address: String, - onItemClick: VoidCallback, -) { +private fun ContractAddressButton(name: String, address: String, onItemClick: VoidCallback) { ActionButton( modifier = Modifier.fillMaxWidth(), name = name, @@ -125,11 +112,7 @@ private fun ContractAddressButton( } @Composable -fun ActionButton( - name: String, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { +fun ActionButton(name: String, onClick: () -> Unit, modifier: Modifier = Modifier) { Button( modifier = modifier.padding(horizontal = 8.dp), onClick = onClick, diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt index 10b261d68b..cdd70f25f3 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt @@ -186,11 +186,7 @@ private fun Subtitle(isExpanded: Boolean, modifier: Modifier = Modifier) { @OptIn(ExperimentalAnimationApi::class) @Composable -private fun ChangeNetworksViewButton( - isExpanded: Boolean, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { +private fun ChangeNetworksViewButton(isExpanded: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { IconButton(onClick = onClick, modifier = modifier.size(size = TangemTheme.dimens.size46)) { AnimatedContent( targetState = isExpanded, diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt index 39ac838653..612a51e449 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt @@ -15,24 +15,24 @@ sealed class TokensAction : Action { data class LoadCurrencies( val supportedBlockchains: List? = null, - val scanResponse: ScanResponse? = null + val scanResponse: ScanResponse? = null, ) : TokensAction() { data class Success(val currencies: List, val loadMore: Boolean) : TokensAction() object Failure : TokensAction() } data class LoadMore( - val scanResponse: ScanResponse? = null + val scanResponse: ScanResponse? = null, ) : TokensAction() data class SetAddedCurrencies( val wallets: List, - val derivationStyle: DerivationStyle? + val derivationStyle: DerivationStyle?, ) : TokensAction() data class SaveChanges( val addedTokens: List, - val addedBlockchains: List + val addedBlockchains: List, ) : TokensAction() object PrepareAndNavigateToAddCustomToken : TokensAction() diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyPlaceholderIcon.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyPlaceholderIcon.kt index c62f31075e..188c75e57b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyPlaceholderIcon.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyPlaceholderIcon.kt @@ -22,7 +22,7 @@ fun CurrencyPlaceholderIcon(id: String) { Box( contentAlignment = Alignment.Center, modifier = Modifier - .background(circleColor, shape = CircleShape) + .background(circleColor, shape = CircleShape), ) { Text( text = id.firstOrNull()?.titlecase() ?: "", diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt index bff5cc2247..ceb4e333c7 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt @@ -162,10 +162,7 @@ fun NetworkItem( @Suppress("MagicNumber") @Composable -private fun prepareNetworkNameSpannableText( - blockchain: Blockchain, - contractAddress: String?, -): AnnotatedString { +private fun prepareNetworkNameSpannableText(blockchain: Blockchain, contractAddress: String?): AnnotatedString { val blockchainName = blockchain.fullNameWithoutTestnet.uppercase() val additionalText = if (contractAddress == null) "MAIN" else blockchain.getNetworkName().uppercase() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt index c67c02d950..4c4079055c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt @@ -58,10 +58,7 @@ sealed interface Currency { fun isToken(): Boolean = this is Token companion object { - fun fromBlockchainNetwork( - blockchainNetwork: BlockchainNetwork, - token: SdkToken? = null, - ): Currency { + fun fromBlockchainNetwork(blockchainNetwork: BlockchainNetwork, token: SdkToken? = null): Currency { return if (token != null) { Token( token = token, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 45013512af..b55d54277d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -168,7 +168,9 @@ data class WalletState( state = walletsData.findProgressState(), error = this.error.takeIf { newProgressState == ProgressState.Error }, ) - } else this + } else { + this + } } companion object { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt index 974ef88df8..8c1847b11a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt @@ -41,7 +41,7 @@ class AppCurrencyMiddleware( WalletDialog.CurrencySelectionDialog( currenciesList = storedFiatCurrencies.mapToUiModel(), currentAppCurrency = appCurrencyProvider.invoke(), - ) + ), ) } @@ -55,7 +55,7 @@ class AppCurrencyMiddleware( WalletDialog.CurrencySelectionDialog( currenciesList = currenciesList.mapToUiModel(), currentAppCurrency = appCurrencyProvider.invoke(), - ) + ), ) } } @@ -82,7 +82,7 @@ class AppCurrencyMiddleware( FiatCurrency( code = it.code, name = it.name, - symbol = it.unit + symbol = it.unit, ) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index f2cc59a816..d7c7bd6d85 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -30,10 +30,7 @@ import timber.log.Timber class MultiWalletMiddleware { @Suppress("LongMethod", "ComplexMethod") - fun handle( - action: WalletAction.MultiWallet, - walletState: WalletState?, - ) { + fun handle(action: WalletAction.MultiWallet, walletState: WalletState?) { when (action) { is WalletAction.MultiWallet.SelectWallet -> { if (action.currency != null) { @@ -105,29 +102,27 @@ class MultiWalletMiddleware { } } - private fun scanAndUpdateCard( - selectedUserWallet: UserWallet, - state: WalletState?, - ) = scope.launch(Dispatchers.Default) { - tangemSdkManager.scanProduct( - cardId = selectedUserWallet.cardId, - userTokensRepository = userTokensRepository, - additionalBlockchainsToDerive = state?.missingDerivations?.map { it.blockchain }, - allowsRequestAccessCodeFromRepository = true, - ) - .flatMap { scanResponse -> - userWalletsListManager.update( - userWalletId = selectedUserWallet.walletId, - update = { userWallet -> - userWallet.copy( - scanResponse = scanResponse, - ) - }, - ) - } - .doOnSuccess { updatedUserWallet -> - store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(emptyList())) - store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true) - } - } + private fun scanAndUpdateCard(selectedUserWallet: UserWallet, state: WalletState?) = + scope.launch(Dispatchers.Default) { + tangemSdkManager.scanProduct( + cardId = selectedUserWallet.cardId, + userTokensRepository = userTokensRepository, + additionalBlockchainsToDerive = state?.missingDerivations?.map { it.blockchain }, + allowsRequestAccessCodeFromRepository = true, + ) + .flatMap { scanResponse -> + userWalletsListManager.update( + userWalletId = selectedUserWallet.walletId, + update = { userWallet -> + userWallet.copy( + scanResponse = scanResponse, + ) + }, + ) + } + .doOnSuccess { updatedUserWallet -> + store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(emptyList())) + store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index ec7597b8c7..6020f4c151 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -46,10 +46,7 @@ class TradeCryptoMiddleware { } } - private fun proceedBuyAction( - state: () -> AppState?, - action: WalletAction.TradeCryptoAction.Buy, - ) { + private fun proceedBuyAction(state: () -> AppState?, action: WalletAction.TradeCryptoAction.Buy) { val selectedWalletData = store.state.walletState.selectedWalletData ?: return val currency = chooseAppropriateCurrency(store.state.walletState) ?: return @@ -164,7 +161,7 @@ class TradeCryptoMiddleware { val bundle = bundleOf( SwapFragment.CURRENCY_BUNDLE_KEY to Json.encodeToString(currency), - SwapFragment.DERIVATION_PATH to store.state.walletState.selectedWalletData?.currency?.derivationPath + SwapFragment.DERIVATION_PATH to store.state.walletState.selectedWalletData?.currency?.derivationPath, ) store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Swap, bundle = bundle)) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index 1de96bac4b..9562b735fa 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -106,9 +106,7 @@ class WarningsMiddleware { } } - private fun checkIfWarningNeeded( - scanResponse: ScanResponse, - ): WarningMessage? { + private fun checkIfWarningNeeded(scanResponse: ScanResponse): WarningMessage? { if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.isDemoCard()) return null if (scanResponse.cardTypesResolver.isMultiwalletAllowed()) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/AppCurrencyReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/AppCurrencyReducer.kt index a098368d06..49ba3fa007 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/AppCurrencyReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/AppCurrencyReducer.kt @@ -4,13 +4,11 @@ import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState class AppCurrencyReducer { - fun reduce( - action: WalletAction.AppCurrencyAction, - state: WalletState, - ): WalletState { + fun reduce(action: WalletAction.AppCurrencyAction, state: WalletState): WalletState { return when (action) { is WalletAction.AppCurrencyAction.SelectAppCurrency, - is WalletAction.AppCurrencyAction.ChooseAppCurrency -> state + is WalletAction.AppCurrencyAction.ChooseAppCurrency, + -> state } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 78e56b7d93..d95339a75b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -210,10 +210,7 @@ fun Wallet.createAddressesData(): List { return listOfAddressData } -private fun handleCheckSignedHashesActions( - action: WalletAction.Warnings, - state: WalletState, -): WalletState { +private fun handleCheckSignedHashesActions(action: WalletAction.Warnings, state: WalletState): WalletState { return when (action) { WalletAction.Warnings.CheckHashesCount.ConfirmHashesCount -> state.copy(hashesCountVerified = true) WalletAction.Warnings.CheckHashesCount.NeedToCheckHashesCountOnline -> state.copy( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt index 16703319a4..0afeb7e3b0 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt @@ -152,14 +152,13 @@ class BalanceWidget( } } - private fun showBalanceWithoutToken(data: BalanceWidgetData, showAmount: Boolean) = - with(binding.lBalance) { - groupBaseCurrency.hide() - tvCurrency.text = data.currency - tvAmount.text = if (showAmount) data.amountFormatted else "" - if (showAmount) { - tvFiatAmount.show() - tvFiatAmount.text = data.fiatAmountFormatted - } + private fun showBalanceWithoutToken(data: BalanceWidgetData, showAmount: Boolean) = with(binding.lBalance) { + groupBaseCurrency.hide() + tvCurrency.text = data.currency + tvAmount.text = if (showAmount) data.amountFormatted else "" + if (showAmount) { + tvFiatAmount.show() + tvFiatAmount.text = data.fiatAmountFormatted } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 2668f1c79a..e070d1e5da 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -70,7 +70,8 @@ import javax.inject.Inject @Suppress("LargeClass", "MagicNumber") @AndroidEntryPoint -class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), +class WalletDetailsFragment : + Fragment(R.layout.fragment_wallet_details), StoreSubscriber { @Inject @@ -496,11 +497,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), setStatus(getString(mainMessage), R.color.darkGray4, null) } - private fun TextView.setStatus( - text: String, - @ColorRes color: Int, - @DrawableRes drawable: Int?, - ) { + private fun TextView.setStatus(text: String, @ColorRes color: Int, @DrawableRes drawable: Int?) { this.text = text setTextColor(getColor(color)) setCompoundDrawablesWithIntrinsicBounds(drawable ?: 0, 0, 0, 0) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/PendingTransactionsAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/PendingTransactionsAdapter.kt index 6d50e30035..0a59da666a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/PendingTransactionsAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/PendingTransactionsAdapter.kt @@ -20,7 +20,7 @@ class PendingTransactionsAdapter : val binding = ItemPendingTransactionBinding.inflate( LayoutInflater.from(parent.context), parent, - false + false, ) return TransactionsViewHolder(binding) } @@ -30,15 +30,9 @@ class PendingTransactionsAdapter : } object DiffUtilCallback : DiffUtil.ItemCallback() { - override fun areContentsTheSame( - oldItem: PendingTransaction, - newItem: PendingTransaction - ) = oldItem == newItem + override fun areContentsTheSame(oldItem: PendingTransaction, newItem: PendingTransaction) = oldItem == newItem - override fun areItemsTheSame( - oldItem: PendingTransaction, - newItem: PendingTransaction - ) = oldItem == newItem + override fun areItemsTheSame(oldItem: PendingTransaction, newItem: PendingTransaction) = oldItem == newItem } class TransactionsViewHolder(val binding: ItemPendingTransactionBinding) : diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt index 60c0d65fbc..98f4fbecee 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt @@ -40,15 +40,9 @@ class WalletAdapter : ListAdapter(D } object DiffUtilCallback : DiffUtil.ItemCallback() { - override fun areContentsTheSame( - oldItem: WalletData, - newItem: WalletData, - ) = oldItem == newItem + override fun areContentsTheSame(oldItem: WalletData, newItem: WalletData) = oldItem == newItem - override fun areItemsTheSame( - oldItem: WalletData, - newItem: WalletData, - ) = oldItem == newItem + override fun areItemsTheSame(oldItem: WalletData, newItem: WalletData) = oldItem == newItem } class WalletsViewHolder(val binding: ItemCurrencyWalletBinding) : diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletDetailWarningMessagesAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletDetailWarningMessagesAdapter.kt index a96101b35a..95be9ce597 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletDetailWarningMessagesAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletDetailWarningMessagesAdapter.kt @@ -37,7 +37,7 @@ class WalletDetailWarningMessagesAdapter : } class WalletDetailsWarningMessageVH( - val binding: LayoutWarningCardBinding + val binding: LayoutWarningCardBinding, ) : RecyclerView.ViewHolder(binding.root) { fun bind(warning: WalletWarningDescription) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt index c22f00de55..762d6e818e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt @@ -40,11 +40,9 @@ class WarningMessagesAdapter : ListAdapter(Dif } object DiffUtilCallback : DiffUtil.ItemCallback() { - override fun areContentsTheSame(oldItem: WarningMessage, newItem: WarningMessage) = - oldItem == newItem + override fun areContentsTheSame(oldItem: WarningMessage, newItem: WarningMessage) = oldItem == newItem - override fun areItemsTheSame(oldItem: WarningMessage, newItem: WarningMessage) = - oldItem == newItem + override fun areItemsTheSame(oldItem: WarningMessage, newItem: WarningMessage) = oldItem == newItem } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/AmountToSendBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/AmountToSendBottomSheetDialog.kt index db783afc52..160d3fc40e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/AmountToSendBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/AmountToSendBottomSheetDialog.kt @@ -44,7 +44,7 @@ class AmountToSendBottomSheetDialog( binding!!.rvAmountsToSend.layoutManager = LinearLayoutManager(context) val dividerItemDecoration = DividerItemDecoration( ContextThemeWrapper(binding!!.root.context, R.style.AppTheme), - DividerItemDecoration.VERTICAL + DividerItemDecoration.VERTICAL, ) binding!!.rvAmountsToSend.addItemDecoration(dividerItemDecoration) @@ -61,7 +61,7 @@ class ChooseAmountAdapter : ListAdapter() { - override fun areContentsTheSame( - oldItem: Amount, - newItem: Amount - ) = oldItem.currencySymbol == newItem.currencySymbol + override fun areContentsTheSame(oldItem: Amount, newItem: Amount) = + oldItem.currencySymbol == newItem.currencySymbol - override fun areItemsTheSame( - oldItem: Amount, - newItem: Amount - ) = oldItem == newItem + override fun areItemsTheSame(oldItem: Amount, newItem: Amount) = oldItem == newItem } class AmountViewHolder(val binding: ItemWalletAmountToSendBinding) : diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconView.kt index 4019726797..ee5b7dc3e2 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconView.kt @@ -47,10 +47,7 @@ class CurrencyIconView @JvmOverloads constructor( } } -fun CurrencyIconView.load( - currency: Currency, - derivationStyle: DerivationStyle?, -) { +fun CurrencyIconView.load(currency: Currency, derivationStyle: DerivationStyle?) { isCustomCurrencyBadgeVisible = currency.isCustomCurrency(derivationStyle) CurrencyIconRequest( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt index f17f324571..4efe5659b4 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt @@ -101,10 +101,7 @@ internal class TotalBalanceCard @JvmOverloads constructor( } @Composable -private fun TotalBalanceCardContent( - state: TotalBalanceCardState, - modifier: Modifier = Modifier, -) { +private fun TotalBalanceCardContent(state: TotalBalanceCardState, modifier: Modifier = Modifier) { TotalBalanceCardScaffold( modifier = modifier, title = { @@ -199,9 +196,7 @@ private fun TotalBalanceCardScaffold( } @Composable -private fun LoadingAmount( - modifier: Modifier = Modifier, -) { +private fun LoadingAmount(modifier: Modifier = Modifier) { Box(modifier = modifier.shimmer()) { Box( modifier = Modifier @@ -216,10 +211,7 @@ private fun LoadingAmount( } @Composable -private fun LoadedAmount( - amount: AnnotatedString, - modifier: Modifier = Modifier, -) { +private fun LoadedAmount(amount: AnnotatedString, modifier: Modifier = Modifier) { Box(modifier = modifier) { Text( text = amount, @@ -232,10 +224,7 @@ private fun LoadedAmount( } @Composable -private fun buildAmountString( - amount: BigDecimal?, - fiatCurrencySymbol: String, -): AnnotatedString { +private fun buildAmountString(amount: BigDecimal?, fiatCurrencySymbol: String): AnnotatedString { if (amount == null) return AnnotatedString(text = UNKNOWN_AMOUNT_SIGN) val format = DecimalFormat.getInstance(Locale.getDefault()) as DecimalFormat @@ -290,9 +279,7 @@ private sealed interface TotalBalanceCardState { // region Preview @Composable -private fun TotalBalanceCardContentSample( - modifier: Modifier = Modifier, -) { +private fun TotalBalanceCardContentSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/WalletDetailsButtonsRow.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/WalletDetailsButtonsRow.kt index 30d48309a8..c7457f1158 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/WalletDetailsButtonsRow.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/WalletDetailsButtonsRow.kt @@ -42,7 +42,7 @@ internal class WalletDetailsButtonsRow @JvmOverloads constructor( fun updateButtonsVisibility( actions: Set, exchangeServiceFeatureOn: Boolean, - sendAllowed: Boolean + sendAllowed: Boolean, ) = with(binding) { containerActionButtons.isVisible = exchangeServiceFeatureOn diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/CurrencySelectionDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/CurrencySelectionDialog.kt index 6cce3b391b..835b547e6d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/CurrencySelectionDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/CurrencySelectionDialog.kt @@ -8,10 +8,7 @@ import com.tangem.tap.store import com.tangem.wallet.R object CurrencySelectionDialog { - fun create( - dialog: WalletDialog.CurrencySelectionDialog, - context: Context - ): AlertDialog { + fun create(dialog: WalletDialog.CurrencySelectionDialog, context: Context): AlertDialog { val currenciesToShow = dialog.currenciesList .map { it.displayName } .toTypedArray() @@ -28,8 +25,8 @@ object CurrencySelectionDialog { dialog.currenciesList.getOrNull(which)?.let { selectedCurrency -> store.dispatch( WalletAction.AppCurrencyAction.SelectAppCurrency( - fiatCurrency = selectedCurrency - ) + fiatCurrency = selectedCurrency, + ), ) store.dispatch(WalletAction.DialogAction.Hide) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index 4d2bdc1fdc..fd920555a0 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -143,46 +143,35 @@ class MultiWalletView : WalletView() { } } - private fun handleBackupWarning( - binding: FragmentWalletBinding, - showBackupWarning: Boolean, - ) = with(binding.lWalletBackupWarning) { - root.isVisible = showBackupWarning - root.setOnClickListener { - Analytics.send(MainScreen.NoticeBackupYourWalletTapped()) - store.dispatch(WalletAction.MultiWallet.BackupWallet) + private fun handleBackupWarning(binding: FragmentWalletBinding, showBackupWarning: Boolean) = + with(binding.lWalletBackupWarning) { + root.isVisible = showBackupWarning + root.setOnClickListener { + Analytics.send(MainScreen.NoticeBackupYourWalletTapped()) + store.dispatch(WalletAction.MultiWallet.BackupWallet) + } } - } - private fun handleRescanWarning( - binding: FragmentWalletBinding, - showRescanWarning: Boolean, - ) = with(binding.lWalletRescanWarning) { - root.isVisible = showRescanWarning - root.setOnClickListener { - Analytics.send(MainScreen.NoticeScanYourCardTapped()) - store.dispatch(WalletAction.MultiWallet.ScanToGetDerivations) + private fun handleRescanWarning(binding: FragmentWalletBinding, showRescanWarning: Boolean) = + with(binding.lWalletRescanWarning) { + root.isVisible = showRescanWarning + root.setOnClickListener { + Analytics.send(MainScreen.NoticeScanYourCardTapped()) + store.dispatch(WalletAction.MultiWallet.ScanToGetDerivations) + } } - } - private fun handleTotalBalance( - binding: FragmentWalletBinding, - totalBalance: TotalBalance?, - walletsCount: Int, - ) = with(binding.lCardTotalBalance) { - isVisible = walletsCount > 0 + private fun handleTotalBalance(binding: FragmentWalletBinding, totalBalance: TotalBalance?, walletsCount: Int) = + with(binding.lCardTotalBalance) { + isVisible = walletsCount > 0 - onChangeFiatCurrencyClick = { - store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) + onChangeFiatCurrencyClick = { + store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) + } + status = totalBalance } - status = totalBalance - } - private fun handleErrorStates( - state: WalletState, - binding: FragmentWalletBinding, - fragment: WalletFragment, - ) { + private fun handleErrorStates(state: WalletState, binding: FragmentWalletBinding, fragment: WalletFragment) { when (state.primaryWalletData?.currencyData?.status) { BalanceStatus.EmptyCard -> { showErrorState( @@ -220,16 +209,15 @@ class MultiWalletView : WalletView() { } } - private fun configureButtonsForEmptyWalletState(binding: FragmentWalletBinding) = - with(binding) { - rowButtons.btnBuy.hide() - rowButtons.btnSell.hide() - rowButtons.btnTrade.hide() - rowButtons.show() + private fun configureButtonsForEmptyWalletState(binding: FragmentWalletBinding) = with(binding) { + rowButtons.btnBuy.hide() + rowButtons.btnSell.hide() + rowButtons.btnTrade.hide() + rowButtons.show() - rowButtons.btnSend.text = fragment?.getText(R.string.wallet_button_create_wallet) - rowButtons.onSendClick = { store.dispatch(WalletAction.CreateWallet) } - } + rowButtons.btnSend.text = fragment?.getText(R.string.wallet_button_create_wallet) + rowButtons.onSendClick = { store.dispatch(WalletAction.CreateWallet) } + } override fun onDestroyFragment() { super.onDestroyFragment() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt index a379f290a8..e999ee383a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt @@ -197,18 +197,16 @@ class SaltPayWalletView : WalletView() { groupShimmer.show() } - private fun handleTxSuccess( - txWidget: LayoutSaltPayTxHistoryBinding, - dataList: List, - ) = with(txWidget) { - Timber.d("handleTxSuccess") - groupShimmer.hide() - groupEmpty.hide() - groupError.hide() - // root.beginDelayedTransition() - updateTxHistoryWidget(txWidget, dataList) - groupSuccess.show() - } + private fun handleTxSuccess(txWidget: LayoutSaltPayTxHistoryBinding, dataList: List) = + with(txWidget) { + Timber.d("handleTxSuccess") + groupShimmer.hide() + groupEmpty.hide() + groupError.hide() + // root.beginDelayedTransition() + updateTxHistoryWidget(txWidget, dataList) + groupSuccess.show() + } private fun handleTxEmpty(txWidget: LayoutSaltPayTxHistoryBinding) = with(txWidget) { Timber.d("handleTxEmpty") @@ -230,12 +228,10 @@ class SaltPayWalletView : WalletView() { groupError.show() } - private fun updateTxHistoryWidget( - txWidget: LayoutSaltPayTxHistoryBinding, - dataList: List, - ) = with(txWidget) { - (rvTxHistory.adapter as TxHistoryAdapter).submitList(dataList) - } + private fun updateTxHistoryWidget(txWidget: LayoutSaltPayTxHistoryBinding, dataList: List) = + with(txWidget) { + (rvTxHistory.adapter as TxHistoryAdapter).submitList(dataList) + } override fun onViewDestroy() { Timber.d("onViewDestroy") diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index c93b07f234..9191b57a00 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -70,7 +70,7 @@ internal class WalletSelectorMiddleware { addWallet() } is WalletSelectorAction.SelectWallet -> { - selectWallet(action.userWalletId, action.sendAnalyticsEvent) + selectWallet(action.userWalletId) } is WalletSelectorAction.RemoveWallets -> { deleteWallets(action.userWalletsIds, state) @@ -189,7 +189,7 @@ internal class WalletSelectorMiddleware { } } - private fun selectWallet(userWalletId: UserWalletId, sendAnalyticsEvent: Boolean) { + private fun selectWallet(userWalletId: UserWalletId) { scope.launch { userWalletsListManager.get(userWalletId) .flatMap { userWallet -> diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt index e965a29794..c28a1e4ab1 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt @@ -10,7 +10,9 @@ internal object WalletSelectorReducer { fun reduce(action: Action, state: AppState): WalletSelectorState { return if (action is WalletSelectorAction) { internalReduce(action, state.walletSelectorState) - } else state.walletSelectorState + } else { + state.walletSelectorState + } } @Suppress("ComplexMethod") diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt index d22d12d85c..a00447b139 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt @@ -9,9 +9,7 @@ import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletIt import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem -internal fun List.toUiModels( - appCurrency: FiatCurrency, -): Sequence { +internal fun List.toUiModels(appCurrency: FiatCurrency): Sequence { return this.asSequence().map { userWalletModel -> with(userWalletModel) { val balance = when (fiatBalance) { diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt index b611289180..9f82671d66 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt @@ -51,10 +51,7 @@ internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment WarningModel.BiometricsLockoutWarning( isPermanent = error.isPermanent, diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsLockoutWarningContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsLockoutWarningContent.kt index 1416b5af61..3abfb1ade2 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsLockoutWarningContent.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/BiometricsLockoutWarningContent.kt @@ -12,9 +12,7 @@ import com.tangem.tap.features.walletSelector.ui.model.WarningModel import com.tangem.wallet.R @Composable -internal fun BiometricsLockoutWarningContent( - warning: WarningModel.BiometricsLockoutWarning, -) { +internal fun BiometricsLockoutWarningContent(warning: WarningModel.BiometricsLockoutWarning) { BasicDialog( title = stringResource(id = R.string.biometric_lockout_warning_title), message = stringResource( @@ -34,9 +32,7 @@ internal fun BiometricsLockoutWarningContent( // region Preview @Composable -private fun BiometricsLockoutDialogSample( - modifier: Modifier = Modifier, -) { +private fun BiometricsLockoutDialogSample(modifier: Modifier = Modifier) { Column(modifier = modifier) { BiometricsLockoutWarningContent( warning = WarningModel.BiometricsLockoutWarning( @@ -64,9 +60,7 @@ private fun BiometricsLockoutDialogPreview_Dark() { } @Composable -private fun BiometricsLockoutDialog_Permanent_Sample( - modifier: Modifier = Modifier, -) { +private fun BiometricsLockoutDialog_Permanent_Sample(modifier: Modifier = Modifier) { Column(modifier = modifier) { BiometricsLockoutWarningContent( warning = WarningModel.BiometricsLockoutWarning( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/KeyInvalidatedWarningContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/KeyInvalidatedWarningContent.kt index 0b31a73101..4459f55a1d 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/KeyInvalidatedWarningContent.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/KeyInvalidatedWarningContent.kt @@ -12,9 +12,7 @@ import com.tangem.tap.features.walletSelector.ui.model.WarningModel import com.tangem.wallet.R @Composable -internal fun KeyInvalidatedWarningContent( - warning: WarningModel.KeyInvalidatedWarning, -) { +internal fun KeyInvalidatedWarningContent(warning: WarningModel.KeyInvalidatedWarning) { BasicDialog( title = stringResource(id = R.string.common_attention), message = stringResource(id = R.string.key_invalidated_warning_description), @@ -28,9 +26,7 @@ internal fun KeyInvalidatedWarningContent( // region Preview @Composable -private fun KeyInvalidatedWarningSample( - modifier: Modifier = Modifier, -) { +private fun KeyInvalidatedWarningSample(modifier: Modifier = Modifier) { Column(modifier = modifier) { KeyInvalidatedWarningContent( warning = WarningModel.KeyInvalidatedWarning(onDismiss = {}), diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RenameWalletDialogContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RenameWalletDialogContent.kt index 97d465df54..64b69bad75 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RenameWalletDialogContent.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RenameWalletDialogContent.kt @@ -47,9 +47,7 @@ internal fun RenameWalletDialogContent(dialog: DialogModel.RenameWalletDialog) { // region Preview @Composable -private fun RenameWalletDialogContentSample( - modifier: Modifier = Modifier, -) { +private fun RenameWalletDialogContentSample(modifier: Modifier = Modifier) { Column( modifier = modifier, ) { diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt index d10ed293f0..ecf9cc83e9 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt @@ -266,9 +266,7 @@ private fun EditWalletsBar( // region Preview @Composable -private fun WalletSelectorScreenContentSample( - modifier: Modifier = Modifier, -) { +private fun WalletSelectorScreenContentSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(color = TangemTheme.colors.background.primary), @@ -303,9 +301,7 @@ private fun WalletSelectorScreenContentPreview_Dark() { } @Composable -private fun WalletSelectorScreenContent_EditWallets_Sample( - modifier: Modifier = Modifier, -) { +private fun WalletSelectorScreenContent_EditWallets_Sample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary), diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt index 385916f599..70c46cb0ce 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt @@ -84,11 +84,7 @@ internal fun WalletItem( } @Composable -private fun WalletCardImage( - cardImageUrl: String, - isChecked: Boolean, - isSelected: Boolean, -) { +private fun WalletCardImage(cardImageUrl: String, isChecked: Boolean, isSelected: Boolean) { Box( modifier = Modifier .width(TangemTheme.dimens.size62) @@ -107,7 +103,9 @@ private fun WalletCardImage( color = tintColor, blendMode = BlendMode.SrcOver, ) - } else null + } else { + null + } } SubcomposeAsyncImage( @@ -283,9 +281,7 @@ private fun LoadedTokensInfo( } @Composable -private fun LockedPlaceholder( - modifier: Modifier = Modifier, -) { +private fun LockedPlaceholder(modifier: Modifier = Modifier) { Box( modifier = modifier .padding(vertical = TangemTheme.dimens.spacing2) @@ -309,9 +305,7 @@ private fun LockedPlaceholder( } @Composable -private fun CardImagePlaceholder( - modifier: Modifier = Modifier, -) { +private fun CardImagePlaceholder(modifier: Modifier = Modifier) { Box(modifier = modifier) { Image( modifier = Modifier.matchParentSize(), @@ -322,9 +316,7 @@ private fun CardImagePlaceholder( } @Composable -private fun CardImageShimmer( - modifier: Modifier = Modifier, -) { +private fun CardImageShimmer(modifier: Modifier = Modifier) { Box(modifier = modifier.shimmer()) { Box( modifier = Modifier @@ -335,9 +327,7 @@ private fun CardImageShimmer( } @Composable -private fun SelectedWalletBadge( - modifier: Modifier = Modifier, -) { +private fun SelectedWalletBadge(modifier: Modifier = Modifier) { Box( modifier = modifier .size(TangemTheme.dimens.size18) @@ -357,9 +347,7 @@ private fun SelectedWalletBadge( } @Composable -private fun CheckedWalletMark( - modifier: Modifier = Modifier, -) { +private fun CheckedWalletMark(modifier: Modifier = Modifier) { Box( modifier = modifier, contentAlignment = Alignment.Center, diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index 495b112f1d..e728d10a4a 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -106,9 +106,7 @@ internal class WelcomeMiddleware { } } - private suspend inline fun scanCardInternal( - crossinline onCardScanned: suspend (ScanResponse) -> Unit, - ) { + private suspend inline fun scanCardInternal(crossinline onCardScanned: suspend (ScanResponse) -> Unit) { tangemSdkManager.setAccessCodeRequestPolicy( useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, ) diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt index f44447f2a9..5f14d1744d 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt @@ -7,7 +7,9 @@ internal object WelcomeReducer { fun reduce(action: Action, state: AppState): WelcomeState { return if (action is WelcomeAction) { internalReduce(action, state.welcomeState) - } else state.welcomeState + } else { + state.welcomeState + } } private fun internalReduce(action: WelcomeAction, state: WelcomeState): WelcomeState { diff --git a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt index 81cad48aca..0554bdf27c 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt @@ -45,10 +45,7 @@ internal class WelcomeFragment : ComposeFragment() { } @Composable - override fun ScreenContent( - state: WelcomeScreenState, - modifier: Modifier, - ) { + override fun ScreenContent(state: WelcomeScreenState, modifier: Modifier) { val snackbarHostState = remember { SnackbarHostState() } val errorMessage by rememberUpdatedState(newValue = state.error?.resolveReference()) val warning by rememberUpdatedState(newValue = state.warning) diff --git a/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WarningDialog.kt b/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WarningDialog.kt index fb974cc393..40ae13b0cb 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WarningDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WarningDialog.kt @@ -12,9 +12,7 @@ import com.tangem.tap.features.welcome.ui.model.WarningModel import com.tangem.wallet.R @Composable -internal fun WarningDialog( - warning: WarningModel?, -) { +internal fun WarningDialog(warning: WarningModel?) { when (warning) { null -> Unit is WarningModel.BiometricsLockoutWarning -> { @@ -50,9 +48,7 @@ internal fun WarningDialog( // region Preview @Composable -private fun BiometricsLockoutDialogSample( - modifier: Modifier = Modifier, -) { +private fun BiometricsLockoutDialogSample(modifier: Modifier = Modifier) { Column(modifier = modifier) { WarningDialog( warning = WarningModel.BiometricsLockoutWarning( @@ -80,9 +76,7 @@ private fun BiometricsLockoutDialogPreview_Dark() { } @Composable -private fun BiometricsLockoutDialog_Permanent_Sample( - modifier: Modifier = Modifier, -) { +private fun BiometricsLockoutDialog_Permanent_Sample(modifier: Modifier = Modifier) { Column(modifier = modifier) { WarningDialog( warning = WarningModel.BiometricsLockoutWarning( @@ -111,9 +105,7 @@ private fun BiometricsLockoutDialog_Permanent_Preview_Dark() { // region Preview @Composable -private fun KeyInvalidatedWarningSample( - modifier: Modifier = Modifier, -) { +private fun KeyInvalidatedWarningSample(modifier: Modifier = Modifier) { Column(modifier = modifier) { WarningDialog(warning = WarningModel.KeyInvalidatedWarning(onDismiss = {})) } diff --git a/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WelcomeScreenContent.kt b/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WelcomeScreenContent.kt index 4cf55f6bcd..373d370eda 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WelcomeScreenContent.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/ui/components/WelcomeScreenContent.kt @@ -91,9 +91,7 @@ internal fun WelcomeScreenContent( // region Preview @Composable -private fun WelcomeScreenContentSample( - modifier: Modifier = Modifier, -) { +private fun WelcomeScreenContentSample(modifier: Modifier = Modifier) { Box( modifier = modifier .background(TangemTheme.colors.background.primary), diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoApi.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoApi.kt index 89308da1ce..5d9fece041 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoApi.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoApi.kt @@ -8,9 +8,7 @@ import retrofit2.http.Path interface MercuryoApi { @GET("{apiVersion}/lib/currencies") - suspend fun currencies( - @Path("apiVersion") apiVersion: String, - ): MercuryoCurrenciesResponse + suspend fun currencies(@Path("apiVersion") apiVersion: String): MercuryoCurrenciesResponse } data class MercuryoCurrenciesResponse( diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoEnvironment.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoEnvironment.kt index af3cda029a..36fd477bc5 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoEnvironment.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoEnvironment.kt @@ -16,11 +16,7 @@ data class MercuryoEnvironment( private const val BASE_URL = "https://api.mercuryo.io/" private const val API_VERSION = "v1.6" - fun prod( - widgetId: String, - secret: String, - apiVersion: String = API_VERSION, - ): MercuryoEnvironment { + fun prod(widgetId: String, secret: String, apiVersion: String = API_VERSION): MercuryoEnvironment { return MercuryoEnvironment( baseUrl = BASE_URL, apiVersion = apiVersion, diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt index 9561664182..8f76434576 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt @@ -125,10 +125,7 @@ class MercuryoService( return (address + environment.secret).calculateSha512().toHexString().lowercase() } - override fun getSellCryptoReceiptUrl( - action: CurrencyExchangeManager.Action, - transactionId: String, - ): String? = null + override fun getSellCryptoReceiptUrl(action: CurrencyExchangeManager.Action, transactionId: String): String? = null private fun blockchainFromCurrencyName(currencyName: String): Blockchain? = when (currencyName) { "BNB" -> Blockchain.BSC diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayApi.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayApi.kt index 27dc8d0c3b..ce7c4c2a7f 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayApi.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayApi.kt @@ -8,14 +8,10 @@ import retrofit2.http.Query interface MoonPayApi { @GET(MOOONPAY_IP_ADDRESS_REQUEST_URL) - suspend fun getUserStatus( - @Query("apiKey") moonPayApiKey: String, - ): MoonPayUserStatus + suspend fun getUserStatus(@Query("apiKey") moonPayApiKey: String): MoonPayUserStatus @GET(MOOONPAY_CURRENCIES_REQUEST_URL) - suspend fun getCurrencies( - @Query("apiKey") moonPayApiKey: String, - ): List + suspend fun getCurrencies(@Query("apiKey") moonPayApiKey: String): List companion object { const val MOOONPAY_BASE_URL = "https://api.moonpay.com/" diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/UtorgEnvironment.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/UtorgEnvironment.kt index b31e8aa8bf..0aac5a8b43 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/UtorgEnvironment.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/UtorgEnvironment.kt @@ -25,15 +25,13 @@ data class UtorgEnvironment( private val STAGE_BASE_URL = Uri.parse("https://app-stage.utorg.pro") private const val STAGE_VERSION = "v1" - fun prod( - authProvider: UtorgAuthProvider, - apiVersion: String = PROD_VERSION, - ): UtorgEnvironment = UtorgEnvironment( - baseUri = PROD_BASE_URL, - sidValue = authProvider.sidValue, - apiVersion = apiVersion, - utorgApi = createApi(PROD_BASE_URL, authProvider, false), - ) + fun prod(authProvider: UtorgAuthProvider, apiVersion: String = PROD_VERSION): UtorgEnvironment = + UtorgEnvironment( + baseUri = PROD_BASE_URL, + sidValue = authProvider.sidValue, + apiVersion = apiVersion, + utorgApi = createApi(PROD_BASE_URL, authProvider, false), + ) fun stage( authProvider: UtorgAuthProvider, diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/api/UtorgApi.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/api/UtorgApi.kt index 6244d39a5e..b18618e38b 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/api/UtorgApi.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/api/UtorgApi.kt @@ -12,15 +12,10 @@ import retrofit2.http.Path interface UtorgApi { @POST("api/merchant/{apiVersion}/settings/currency") - suspend fun getCurrency( - @Path("apiVersion") apiVersion: String, - ): UtorgCurrencyResponse + suspend fun getCurrency(@Path("apiVersion") apiVersion: String): UtorgCurrencyResponse @POST("api/merchant/{apiVersion}/settings/successUrl") - suspend fun setSuccessUrl( - @Path("apiVersion") apiVersion: String, - @Body request: RequestSuccessUrl, - ) + suspend fun setSuccessUrl(@Path("apiVersion") apiVersion: String, @Body request: RequestSuccessUrl) } data class RequestSuccessUrl( diff --git a/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyApi.kt b/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyApi.kt index 8566c89a86..d9d00a663b 100644 --- a/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyApi.kt +++ b/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyApi.kt @@ -22,8 +22,7 @@ data class VerifyPayIdResponse( val addresses: List = mutableListOf(), val payId: String? = null, ) { - fun getAddressDetails(): PayIdAddressDetails? = - if (addresses.isNotEmpty()) addresses[0].addressDetails else null + fun getAddressDetails(): PayIdAddressDetails? = if (addresses.isNotEmpty()) addresses[0].addressDetails else null } @JsonClass(generateAdapter = true) diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt index 3f5c655ec2..5a2fddd325 100644 --- a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt @@ -158,11 +158,9 @@ class AppRatingLaunchObserver( editor.apply() } - private fun userWasInteractWithRating(): Boolean = - preferences.getBoolean(K_USER_WAS_INTERACT_WITH_RATING, false) + private fun userWasInteractWithRating(): Boolean = preferences.getBoolean(K_USER_WAS_INTERACT_WITH_RATING, false) - private fun getCounterOfNextShowing(): Int = - preferences.getInt(K_SHOW_RATING_AT_LAUNCH_COUNT, firstShowing) + private fun getCounterOfNextShowing(): Int = preferences.getInt(K_SHOW_RATING_AT_LAUNCH_COUNT, firstShowing) companion object { private const val K_SHOW_RATING_AT_LAUNCH_COUNT = "showRatingDialogAtLaunchCount" diff --git a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt index 705cd2824f..0ef9bf082d 100644 --- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt @@ -42,7 +42,9 @@ class DerivationManagerImpl( contractAddress = currency.contractAddress, decimals = currency.decimalCount, ) - } else null + } else { + null + } val blockchainNetwork = BlockchainNetwork(blockchain, card) val appCurrency = com.tangem.tap.features.wallet.models.Currency.fromBlockchainNetwork( blockchainNetwork, diff --git a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt index b5225f4588..b49a4168c6 100644 --- a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt @@ -397,11 +397,7 @@ class TransactionManagerImpl( } } - private fun createAmount( - amount: BigDecimal, - currency: Currency, - blockchain: Blockchain, - ): Amount { + private fun createAmount(amount: BigDecimal, currency: Currency, blockchain: Blockchain): Amount { return when (currency) { is Currency.NativeToken -> { Amount(value = amount, blockchain = blockchain) @@ -412,11 +408,7 @@ class TransactionManagerImpl( } } - private fun createAmountForSwap( - amount: BigDecimal, - currency: Currency?, - blockchain: Blockchain, - ): Amount { + private fun createAmountForSwap(amount: BigDecimal, currency: Currency?, blockchain: Blockchain): Amount { return when (currency) { is Currency.NativeToken, null, diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/Analytics.kt b/core/analytics/src/main/java/com/tangem/core/analytics/Analytics.kt index 0e0f40b6c9..8dda5adedf 100644 --- a/core/analytics/src/main/java/com/tangem/core/analytics/Analytics.kt +++ b/core/analytics/src/main/java/com/tangem/core/analytics/Analytics.kt @@ -18,7 +18,8 @@ import java.util.concurrent.Executors /** [REDACTED_AUTHOR] */ -interface GlobalAnalyticsEventHandler : AnalyticsEventHandler, +interface GlobalAnalyticsEventHandler : + AnalyticsEventHandler, AnalyticsHandlerHolder, AnalyticsFilterHolder, ParamsInterceptorHolder diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/api/ClientApi.kt b/core/analytics/src/main/java/com/tangem/core/analytics/api/ClientApi.kt index 0989dfaad4..f44a0133cd 100644 --- a/core/analytics/src/main/java/com/tangem/core/analytics/api/ClientApi.kt +++ b/core/analytics/src/main/java/com/tangem/core/analytics/api/ClientApi.kt @@ -4,15 +4,9 @@ package com.tangem.core.analytics.api [REDACTED_AUTHOR] */ interface EventLogger { - fun logEvent( - event: String, - params: Map = emptyMap(), - ) + fun logEvent(event: String, params: Map = emptyMap()) } interface ErrorEventLogger { - fun logErrorEvent( - error: Throwable, - params: Map = emptyMap(), - ) + fun logErrorEvent(error: Throwable, params: Map = emptyMap()) } \ No newline at end of file diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/api/EventHandlerApi.kt b/core/analytics/src/main/java/com/tangem/core/analytics/api/EventHandlerApi.kt index ca6721037c..49aadf88c3 100644 --- a/core/analytics/src/main/java/com/tangem/core/analytics/api/EventHandlerApi.kt +++ b/core/analytics/src/main/java/com/tangem/core/analytics/api/EventHandlerApi.kt @@ -22,10 +22,7 @@ interface AnalyticsHandler : AnalyticsEventHandler { } interface ErrorEventHandler { - fun send( - error: Throwable, - params: Map = emptyMap(), - ) + fun send(error: Throwable, params: Map = emptyMap()) } interface AnalyticsHandlerHolder { diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt index 711963d504..56963e7456 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt @@ -33,10 +33,7 @@ interface TangemTechApi { ): CoinsResponse @GET("rates") - suspend fun getRates( - @Query("currencyId") currencyId: String, - @Query("coinIds") coinIds: String, - ): RatesResponse + suspend fun getRates(@Query("currencyId") currencyId: String, @Query("coinIds") coinIds: String): RatesResponse @GET("currencies") suspend fun getCurrencyList(): CurrenciesResponse diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt index ab0752e212..4404533bf3 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt @@ -43,11 +43,13 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager { override fun resetToDefault(name: String) { when (name) { - IS_SENDING_TO_PAY_ID_ENABLED -> config = - config.copy(isSendingToPayIdEnabled = defaultConfig.isSendingToPayIdEnabled) + IS_SENDING_TO_PAY_ID_ENABLED -> + config = + config.copy(isSendingToPayIdEnabled = defaultConfig.isSendingToPayIdEnabled) IS_TOP_UP_ENABLED -> config = config.copy(isTopUpEnabled = defaultConfig.isTopUpEnabled) - IS_CREATING_TWIN_CARDS_ALLOWED -> config = - config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed) + IS_CREATING_TWIN_CARDS_ALLOWED -> + config = + config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed) } } diff --git a/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt b/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt index 9e9e143cf2..66d6c0f90b 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt @@ -16,6 +16,6 @@ sealed class RequestHeader(vararg pairs: Pair) { class AuthenticationHeader(authProvider: AuthProvider) : RequestHeader( "card_public_key" to authProvider.getCardPublicKey(), - "card_id" to authProvider.getCardId() + "card_id" to authProvider.getCardId(), ) } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt index c720130f16..50651d2e35 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt @@ -42,12 +42,7 @@ import com.tangem.core.ui.res.TangemTheme * [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=97%3A103&t=TmfD6UBHPg9uYfev-4) * */ @Composable -fun TextButton( - text: String, - onClick: () -> Unit, - modifier: Modifier = Modifier, - enabled: Boolean = true, -) { +fun TextButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true) { TangemButton( modifier = modifier, text = text, @@ -84,12 +79,7 @@ fun TextButtonIconLeft( } @Composable -fun WarningTextButton( - text: String, - onClick: () -> Unit, - modifier: Modifier = Modifier, - enabled: Boolean = true, -) { +fun WarningTextButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true) { TangemButton( modifier = modifier, text = text, @@ -239,12 +229,7 @@ fun SecondaryButtonIconLeft( // region Other @Composable -fun SelectorButton( - text: String, - onClick: () -> Unit, - modifier: Modifier = Modifier, - enabled: Boolean = true, -) { +fun SelectorButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true) { TangemButton( modifier = modifier, text = text, @@ -461,9 +446,7 @@ private open class TangemButtonColors( // region Preview @Composable -private fun PrimaryButtonSample( - modifier: Modifier = Modifier, -) { +private fun PrimaryButtonSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary), @@ -537,9 +520,7 @@ private fun PrimaryButtonPreview_Dark() { } @Composable -private fun SecondaryButtonSample( - modifier: Modifier = Modifier, -) { +private fun SecondaryButtonSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary), @@ -613,9 +594,7 @@ private fun SecondaryButtonPreview_Dark() { } @Composable -private fun TextButtonSample( - modifier: Modifier = Modifier, -) { +private fun TextButtonSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary), diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Cards.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Cards.kt index 0fc92ad614..b06cff2ece 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Cards.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Cards.kt @@ -43,11 +43,7 @@ import com.valentinilk.shimmer.shimmer * >Figma component */ @Composable -fun SmallInfoCard( - startText: String, - endText: String, - isLoading: Boolean = false, -) { +fun SmallInfoCard(startText: String, endText: String, isLoading: Boolean = false) { Surface( shape = RoundedCornerShape(TangemTheme.dimens.radius12), color = TangemTheme.colors.background.primary, @@ -74,12 +70,7 @@ fun SmallInfoCard( * >Figma component */ @Composable -fun SmallInfoCardWithDisclaimer( - startText: String, - endText: String, - disclaimer: String, - isLoading: Boolean = false, -) { +fun SmallInfoCardWithDisclaimer(startText: String, endText: String, disclaimer: String, isLoading: Boolean = false) { Surface( shape = RoundedCornerShape(TangemTheme.dimens.radius12), color = TangemTheme.colors.background.primary, @@ -106,12 +97,7 @@ fun SmallInfoCardWithDisclaimer( * >Figma component */ @Composable -fun SmallInfoCardWithWarning( - startText: String, - endText: String, - warningText: String, - disclaimer: String? = null, -) { +fun SmallInfoCardWithWarning(startText: String, endText: String, warningText: String, disclaimer: String? = null) { Surface( shape = RoundedCornerShape(TangemTheme.dimens.size12), color = TangemTheme.colors.background.primary, @@ -274,12 +260,7 @@ fun IconWithTitleAndDescription( // region elements @Composable -private fun CardInfoBox( - startText: String, - endText: String, - disclaimer: String?, - isLoading: Boolean = false, -) { +private fun CardInfoBox(startText: String, endText: String, disclaimer: String?, isLoading: Boolean = false) { val isOpened = remember { mutableStateOf(false) } Column { Row( diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Dialogs.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Dialogs.kt index aaf52b686e..36052e27f0 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Dialogs.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Dialogs.kt @@ -159,10 +159,7 @@ private fun TangemDialog( } @Composable -private fun DialogContent( - type: DialogType, - modifier: Modifier = Modifier, -) { +private fun DialogContent(type: DialogType, modifier: Modifier = Modifier) { Column( modifier = modifier, verticalArrangement = Arrangement.Center, @@ -196,11 +193,7 @@ private fun DialogContent( } @Composable -private fun DialogButtons( - confirmButton: DialogButton, - dismissButton: DialogButton?, - modifier: Modifier = Modifier, -) { +private fun DialogButtons(confirmButton: DialogButton, dismissButton: DialogButton?, modifier: Modifier = Modifier) { Row( modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy( @@ -315,9 +308,7 @@ private fun Preview_BasicDialog_InDarkTheme() { } @Composable -private fun WarningBasicDialogSample( - modifier: Modifier = Modifier, -) { +private fun WarningBasicDialogSample(modifier: Modifier = Modifier) { Column( modifier = modifier, ) { @@ -349,9 +340,7 @@ private fun WarningBasicDialogPreview_Dark() { } @Composable -private fun TextInputDialogSample( - modifier: Modifier = Modifier, -) { +private fun TextInputDialogSample(modifier: Modifier = Modifier) { Column( modifier = modifier, ) { diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/MiddleEllipsisText.kt b/core/ui/src/main/java/com/tangem/core/ui/components/MiddleEllipsisText.kt index 8d5527b5a6..9bdff5f987 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/MiddleEllipsisText.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/MiddleEllipsisText.kt @@ -153,21 +153,19 @@ private class BoundCounter( private var _nextCharWidth: Float? = null private var invalidCharsCount = 0 - fun widthWithNextChar(): Float = - width + nextCharWidth() + fun widthWithNextChar(): Float = width + nextCharWidth() - private fun nextCharWidth(): Float = - _nextCharWidth ?: run { - var boundingBox: Rect - // invalidCharsCount fixes this bug: https://issuetracker.google.com/issues/197146630 - invalidCharsCount-- - do { - boundingBox = textLayoutResult - .getBoundingBox(charPosition(string.count() + ++invalidCharsCount)) - } while (boundingBox.right == 0f) - _nextCharWidth = boundingBox.width - boundingBox.width - } + private fun nextCharWidth(): Float = _nextCharWidth ?: run { + var boundingBox: Rect + // invalidCharsCount fixes this bug: https://issuetracker.google.com/issues/197146630 + invalidCharsCount-- + do { + boundingBox = textLayoutResult + .getBoundingBox(charPosition(string.count() + ++invalidCharsCount)) + } while (boundingBox.right == 0f) + _nextCharWidth = boundingBox.width + boundingBox.width + } fun addNextChar() { string += text[charPosition(string.count())] diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt b/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt index 3e767ca2f5..ebab2d5145 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt @@ -106,10 +106,7 @@ fun ResultScreenContent( } @Composable -fun SuccessImage( - resultColor: Color, - @DrawableRes icon: Int, -) { +fun SuccessImage(resultColor: Color, @DrawableRes icon: Int) { Box( modifier = Modifier .background( diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/SystemBarsEffect.kt b/core/ui/src/main/java/com/tangem/core/ui/components/SystemBarsEffect.kt index 34ac768e47..ea843b7a7a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/SystemBarsEffect.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/SystemBarsEffect.kt @@ -6,9 +6,7 @@ import com.google.accompanist.systemuicontroller.SystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController @Composable -fun SystemBarsEffect( - block: SystemUiController.() -> Unit, -) { +fun SystemBarsEffect(block: SystemUiController.() -> Unit) { val systemUiController = rememberSystemUiController() SideEffect { block(systemUiController) } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/TextFields.kt b/core/ui/src/main/java/com/tangem/core/ui/components/TextFields.kt index 6b9df80601..eafe741803 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/TextFields.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/TextFields.kt @@ -180,7 +180,7 @@ private fun TangemTextField( } private enum class TangemTextFieldSize { - Default + Default, } @Composable @@ -305,11 +305,7 @@ internal data class TangemTextFieldColors( } @Composable - override fun labelColor( - enabled: Boolean, - error: Boolean, - interactionSource: InteractionSource, - ): State { + override fun labelColor(enabled: Boolean, error: Boolean, interactionSource: InteractionSource): State { val focused by interactionSource.collectIsFocusedAsState() val targetValue = when { @@ -347,9 +343,7 @@ internal data class TangemTextFieldColors( // region Preview @Composable -private fun OutlineTextFieldSample( - modifier: Modifier = Modifier, -) { +private fun OutlineTextFieldSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Warnings.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Warnings.kt index d8293a9868..b6b858d2cd 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Warnings.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Warnings.kt @@ -24,11 +24,7 @@ import com.tangem.core.ui.res.TangemTheme * >Figma component */ @Composable -fun WarningCard( - title: String, - description: String, - icon: @Composable (() -> Unit)? = null, -) { +fun WarningCard(title: String, description: String, icon: @Composable (() -> Unit)? = null) { WarningCardSurface( content = { WarningBody( @@ -128,10 +124,7 @@ private fun WarningBody( @OptIn(ExperimentalMaterialApi::class) @Composable -private fun WarningCardSurface( - onClick: (() -> Unit)? = null, - content: @Composable () -> Unit, -) { +private fun WarningCardSurface(onClick: (() -> Unit)? = null, content: @Composable () -> Unit) { Card( shape = RoundedCornerShape(TangemTheme.dimens.size12), backgroundColor = TangemTheme.colors.background.primary, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/atoms/Hand.kt b/core/ui/src/main/java/com/tangem/core/ui/components/atoms/Hand.kt index e3ade6def9..cbb97ce8e1 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/atoms/Hand.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/atoms/Hand.kt @@ -18,9 +18,7 @@ import com.tangem.core.ui.res.TangemTheme * [Show in Figma](https://www.figma.com/file/17JyRbuUEZ42DluaFEuGQk/Atoms?node-id=135%3A25&t=Jo68S6ilyewVU8MV-4) * */ @Composable -fun Hand( - modifier: Modifier = Modifier, -) { +fun Hand(modifier: Modifier = Modifier) { Box( modifier = modifier .padding(vertical = TangemTheme.dimens.spacing8) @@ -41,9 +39,7 @@ fun Hand( // region Preview @Composable -private fun HandSample( - modifier: Modifier = Modifier, -) { +private fun HandSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary) diff --git a/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeBottomSheetFragment.kt b/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeBottomSheetFragment.kt index a88b3a2ff7..7e50223a02 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeBottomSheetFragment.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeBottomSheetFragment.kt @@ -26,11 +26,7 @@ abstract class ComposeBottomSheetFragment : BottomSheetDialogFragme override fun getTheme(): Int = R.style.AppTheme_TransparentBottomSheetDialog - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return createComposeView(inflater.context) } diff --git a/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeFragment.kt b/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeFragment.kt index d7ab04a268..cde4de5275 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeFragment.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeFragment.kt @@ -7,11 +7,7 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment abstract class ComposeFragment : Fragment(), ComposeScreen { - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return createComposeView(inflater.context) } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeScreen.kt b/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeScreen.kt index 20d6bf7bf1..987f29cd34 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeScreen.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/fragments/ComposeScreen.kt @@ -40,8 +40,5 @@ internal interface ComposeScreen { @Suppress("TopLevelComposableFunctions") @Composable - fun ScreenContent( - state: ScreenState, - modifier: Modifier, - ) + fun ScreenContent(state: ScreenState, modifier: Modifier) } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/ButtonColorType.kt b/core/ui/src/main/java/com/tangem/core/ui/res/ButtonColorType.kt index 5eb3a3fcff..2e45dc7577 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/ButtonColorType.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/ButtonColorType.kt @@ -17,7 +17,7 @@ enum class ButtonColorType(val lightColor: Color, val darkColor: Color) { SECONDARY(lightColor = Light2, darkColor = Dark5), DISABLED(lightColor = Light2, darkColor = Dark6), POSITIVE(lightColor = Meadow, darkColor = Meadow), - POSITIVE_DISABLED(lightColor = MagicMint, darkColor = DarkGreen) + POSITIVE_DISABLED(lightColor = MagicMint, darkColor = DarkGreen), } @Composable diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/IconColorType.kt b/core/ui/src/main/java/com/tangem/core/ui/res/IconColorType.kt index 9fa83581b6..f009843950 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/IconColorType.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/IconColorType.kt @@ -24,7 +24,7 @@ enum class IconColorType(val lightColor: Color, val darkColor: Color) { INACTIVE(lightColor = Light4, darkColor = Dark4), ACCENT(lightColor = Meadow, darkColor = Meadow), WARNING(lightColor = Amaranth, darkColor = Amaranth), - ATTENTION(lightColor = Tangerine, darkColor = Tangerine) + ATTENTION(lightColor = Tangerine, darkColor = Tangerine), } @Composable diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemTheme.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemTheme.kt index 8239973f6a..139dc810c6 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemTheme.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemTheme.kt @@ -69,10 +69,7 @@ object TangemTheme { @Stable @Composable -private fun materialThemeColors( - colors: TangemColors, - isDark: Boolean, -): Colors { +private fun materialThemeColors(colors: TangemColors, isDark: Boolean): Colors { return Colors( primary = colors.background.primary, primaryVariant = colors.background.secondary, diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TextColorType.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TextColorType.kt index 5b726844aa..39f85b8fa1 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TextColorType.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TextColorType.kt @@ -24,7 +24,7 @@ enum class TextColorType(val lightColor: Color, val darkColor: Color) { ACCENT(lightColor = Meadow, darkColor = Meadow), WARNING(lightColor = Amaranth, darkColor = Amaranth), ATTENTION(lightColor = Tangerine, darkColor = Tangerine), - CONSTANT_WHITE(lightColor = White, darkColor = White) + CONSTANT_WHITE(lightColor = White, darkColor = White), } @Composable diff --git a/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt b/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt index b9ed8ee566..59452dbf7a 100644 --- a/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt +++ b/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt @@ -25,11 +25,7 @@ class Debouncer { private var debounceJob: Job? = null - fun debounce( - waitMs: Long = 300L, - coroutineScope: CoroutineScope, - destinationFunction: () -> Unit, - ) { + fun debounce(waitMs: Long = 300L, coroutineScope: CoroutineScope, destinationFunction: () -> Unit) { debounceJob?.cancel() debounceJob = coroutineScope.launch { delay(waitMs) diff --git a/core/utils/src/main/java/com/tangem/utils/detekt/UnusedRequiredComponent.kt b/core/utils/src/main/java/com/tangem/utils/detekt/UnusedRequiredComponent.kt index 273d9dc981..3ee986c4d2 100644 --- a/core/utils/src/main/java/com/tangem/utils/detekt/UnusedRequiredComponent.kt +++ b/core/utils/src/main/java/com/tangem/utils/detekt/UnusedRequiredComponent.kt @@ -22,7 +22,7 @@ package com.tangem.utils.detekt AnnotationTarget.TYPE, AnnotationTarget.EXPRESSION, AnnotationTarget.FILE, - AnnotationTarget.TYPEALIAS + AnnotationTarget.TYPEALIAS, ) @Retention(AnnotationRetention.SOURCE) annotation class UnusedRequiredComponent(val description: String) \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/DomainModuleMessage.kt b/domain/src/main/java/com/tangem/domain/DomainModuleMessage.kt index 6eb55484ca..27d7606e7f 100644 --- a/domain/src/main/java/com/tangem/domain/DomainModuleMessage.kt +++ b/domain/src/main/java/com/tangem/domain/DomainModuleMessage.kt @@ -52,9 +52,11 @@ sealed class AddCustomTokenError( object UnsupportedSolanaToken : Warning() } - data class SelectTokeNetworkError(val networkId: String) : AddCustomTokenError( - message = "Unknown network [$networkId] should not be included in the network selection dialog.", - ), FbConsumeException + data class SelectTokeNetworkError(val networkId: String) : + AddCustomTokenError( + message = "Unknown network [$networkId] should not be included in the network selection dialog.", + ), + FbConsumeException data class UnAppropriateInitialization( val of: String, diff --git a/domain/src/main/java/com/tangem/domain/DomainWrapped.kt b/domain/src/main/java/com/tangem/domain/DomainWrapped.kt index 1b41d0e9cd..a94866c343 100644 --- a/domain/src/main/java/com/tangem/domain/DomainWrapped.kt +++ b/domain/src/main/java/com/tangem/domain/DomainWrapped.kt @@ -19,14 +19,14 @@ sealed interface DomainWrapped { data class Token( val token: com.tangem.blockchain.common.Token, override val blockchain: com.tangem.blockchain.common.Blockchain, - override val derivationPath: String? + override val derivationPath: String?, ) : Currency { override val currencySymbol = token.symbol } data class Blockchain( override val blockchain: com.tangem.blockchain.common.Blockchain, - override val derivationPath: String? + override val derivationPath: String?, ) : Currency { override val currencySymbol: String = blockchain.currency } diff --git a/domain/src/main/java/com/tangem/domain/common/CardDTO.kt b/domain/src/main/java/com/tangem/domain/common/CardDTO.kt index 63695e8fdc..630a017700 100644 --- a/domain/src/main/java/com/tangem/domain/common/CardDTO.kt +++ b/domain/src/main/java/com/tangem/domain/common/CardDTO.kt @@ -267,7 +267,8 @@ data class CardDTO( enum class LinkedTerminalStatus { Current, Other, - None; + None, + ; companion object { internal fun fromSdkStatus(sdkStatus: Card.LinkedTerminalStatus): LinkedTerminalStatus { diff --git a/domain/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt b/domain/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt index b84051a3c1..5d9f6fafa7 100644 --- a/domain/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt +++ b/domain/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt @@ -32,8 +32,10 @@ class TangemCardTypesResolver( override fun isMultiwalletAllowed(): Boolean = !isTangemTwins() && !card.isStart2Coin && !isTangemNote() && !isSaltPay() && - (card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable || - card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1) + ( + card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable || + card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1 + ) override fun getBlockchain(): Blockchain { return when (productType) { diff --git a/domain/src/main/java/com/tangem/domain/common/Throttling.kt b/domain/src/main/java/com/tangem/domain/common/Throttling.kt index b7ef3d7783..e0344ec362 100644 --- a/domain/src/main/java/com/tangem/domain/common/Throttling.kt +++ b/domain/src/main/java/com/tangem/domain/common/Throttling.kt @@ -31,7 +31,7 @@ open class Throttler( } class ThrottlerWithValues( - duration: Long + duration: Long, ) : Throttler(duration), ValuesHolder { private val valuesHolder: MutableMap = mutableMapOf() diff --git a/domain/src/main/java/com/tangem/domain/common/form/Form.kt b/domain/src/main/java/com/tangem/domain/common/form/Form.kt index b63423436e..cca8b72a5f 100644 --- a/domain/src/main/java/com/tangem/domain/common/form/Form.kt +++ b/domain/src/main/java/com/tangem/domain/common/form/Form.kt @@ -38,7 +38,7 @@ interface Field { data class Data( val value: Data, - val isUserInput: Boolean + val isUserInput: Boolean, ) } diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt index ba47bee24f..1a533426fc 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt @@ -81,11 +81,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT } @Suppress("ComplexMethod") - override suspend fun handleAction( - action: Action, - storeState: DomainState, - cancel: ValueCallback, - ) { + override suspend fun handleAction(action: Action, storeState: DomainState, cancel: ValueCallback) { if (action !is AddCustomTokenAction) return when (action) { diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/Models.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/Models.kt index 3dba21a577..444255ef7f 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/Models.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/Models.kt @@ -11,7 +11,7 @@ data class ScreenState( val symbol: ViewStates.TokenField, val decimals: ViewStates.TokenField, val derivationPath: ViewStates.TokenField, - val addButton: ViewStates.AddButton + val addButton: ViewStates.AddButton, ) sealed class ViewStates { @@ -22,6 +22,6 @@ sealed class ViewStates { ) : ViewStates() data class AddButton( - val isEnabled: Boolean = true + val isEnabled: Boolean = true, ) : ViewStates() } \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/redux/ReStoreHub.kt b/domain/src/main/java/com/tangem/domain/redux/ReStoreHub.kt index fc2f0df299..fcef0871d2 100644 --- a/domain/src/main/java/com/tangem/domain/redux/ReStoreHub.kt +++ b/domain/src/main/java/com/tangem/domain/redux/ReStoreHub.kt @@ -3,7 +3,13 @@ package com.tangem.domain.redux import android.webkit.ValueCallback import com.tangem.domain.redux.global.DomainGlobalState import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.job +import kotlinx.coroutines.launch import org.rekotlin.Action import org.rekotlin.DispatchFunction import org.rekotlin.Middleware @@ -38,14 +44,14 @@ internal interface ReStoreReducer { */ internal abstract class BaseStoreHub( private val name: String, - private val dispatcher: CoroutineDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher() + private val dispatcher: CoroutineDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher(), ) : ReStoreHub { val globalState: DomainGlobalState get() = domainStore.state.globalState val hubScope = CoroutineScope( - Job() + dispatcher + CoroutineName(name) + FeatureCoroutineExceptionHandler.create(name) + Job() + dispatcher + CoroutineName(name) + FeatureCoroutineExceptionHandler.create(name), ) private val actionsAndJobs = mutableMapOf() diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt index 2c477d67e3..ad770f8c2e 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt @@ -10,10 +10,5 @@ interface ReferralRepository { suspend fun getReferralStatus(walletId: String): ReferralData /** Starts user referral program */ - suspend fun startReferral( - walletId: String, - networkId: String, - tokenId: String, - address: String, - ): ReferralData + suspend fun startReferral(walletId: String, networkId: String, tokenId: String, address: String): ReferralData } \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt index e0671b7ffd..09e9cea01c 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt @@ -102,8 +102,11 @@ internal class SwapRepositoryImpl @Inject constructor( } } - override suspend fun checkTokensSpendAllowance(networkId: String, tokenAddress: String, walletAddress: String): - AggregatedSwapDataModel { + override suspend fun checkTokensSpendAllowance( + networkId: String, + tokenAddress: String, + walletAddress: String, + ): AggregatedSwapDataModel { return withContext(coroutineDispatcher.io) { try { val response = oneInchErrorsHandler.handleOneInchResponse( diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 2bb5569c19..b955369d7e 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -305,11 +305,7 @@ internal class SwapInteractorImpl @Inject constructor( return allowance.error == DataError.NoError && allowance.dataModel != ZERO_BALANCE } - private fun createEmptyAmountState( - networkId: String, - fromToken: Currency, - toToken: Currency, - ): SwapState { + private fun createEmptyAmountState(networkId: String, fromToken: Currency, toToken: Currency): SwapState { val appCurrency = userWalletManager.getUserAppCurrency() val fromTokenBalance = cache.getBalanceForToken(networkId, derivationPath, fromToken.symbol) val toTokenBalance = cache.getBalanceForToken(networkId, derivationPath, toToken.symbol) @@ -372,10 +368,7 @@ internal class SwapInteractorImpl @Inject constructor( } } - private suspend fun getFormattedFiatFee( - networkId: String, - fee: BigDecimal, - ): String { + private suspend fun getFormattedFiatFee(networkId: String, fee: BigDecimal): String { val appCurrency = userWalletManager.getUserAppCurrency() val nativeToken = userWalletManager.getNativeTokenForNetwork(networkId) val rates = repository.getRates(appCurrency.code, listOf(nativeToken.id)) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt index 932a45fd4e..70289f0c3f 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt @@ -32,11 +32,7 @@ interface SwapRepository { * @param tokenAddress token you want to exchange * @param amount number of tokens is allowed. By default infinite */ - suspend fun dataToApprove( - networkId: String, - tokenAddress: String, - amount: String? = null, - ): ApproveModel + suspend fun dataToApprove(networkId: String, tokenAddress: String, amount: String? = null): ApproveModel /** * Get the number of tokens that the 1inch router is allowed to spend diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt index 7f65454b85..572c5484ac 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt @@ -37,9 +37,7 @@ class SwapDomainModule { @Provides @Singleton - fun provideBlockchainInteractor( - transactionManager: TransactionManager, - ): BlockchainInteractor { + fun provideBlockchainInteractor(transactionManager: TransactionManager): BlockchainInteractor { return BlockchainInteractorImpl( transactionManager = transactionManager, ) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt index fee4466f54..fbcbeb51b0 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt @@ -9,9 +9,11 @@ sealed class DataError { fun mapErrors(error: String?): DataError { return if (error == null) { DataError.NoError - } else when (error) { - INSUFFICIENT_LIQUIDITY_ERROR -> DataError.InsufficientLiquidity - else -> DataError.UnknownError(error) + } else { + when (error) { + INSUFFICIENT_LIQUIDITY_ERROR -> DataError.InsufficientLiquidity + else -> DataError.UnknownError(error) + } } } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index c5924121b8..11d2617601 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -290,11 +290,7 @@ internal class StateBuilder(val actions: UiActions) { ) } - fun createErrorTransaction( - uiState: SwapStateHolder, - txState: TxState, - onAlertClick: () -> Unit, - ): SwapStateHolder { + fun createErrorTransaction(uiState: SwapStateHolder, txState: TxState, onAlertClick: () -> Unit): SwapStateHolder { return uiState.copy( alert = SwapWarning.GenericWarning( message = null, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt index 78df67253d..9862a5b00b 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt @@ -293,9 +293,7 @@ private fun FeeItem(feeState: FeeState, currency: String) { } @Composable -private fun SwapWarnings( - warnings: List, -) { +private fun SwapWarnings(warnings: List) { Column( modifier = Modifier .background(color = TangemTheme.colors.background.secondary) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt index 382986835c..b10aac1300 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt @@ -198,10 +198,7 @@ private fun TokenItem(token: TokenToSelect, network: Network, onTokenClick: () - @Suppress("MagicNumber") @Composable -private fun TokenIcon( - token: TokenToSelect, - @DrawableRes iconPlaceholder: Int?, -) { +private fun TokenIcon(token: TokenToSelect, @DrawableRes iconPlaceholder: Int?) { val data = token.iconUrl.ifEmpty { iconPlaceholder } @@ -233,9 +230,7 @@ private fun TokenIcon( } @Composable -private fun TokenImageShimmer( - modifier: Modifier = Modifier, -) { +private fun TokenImageShimmer(modifier: Modifier = Modifier) { Box(modifier = modifier.shimmer()) { Box( modifier = Modifier diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt index 1e886b5303..761a8f9448 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt @@ -121,11 +121,7 @@ fun TransactionCard( } @Composable -private fun Header( - type: TransactionCardType, - balance: String, - modifier: Modifier = Modifier, -) { +private fun Header(type: TransactionCardType, balance: String, modifier: Modifier = Modifier) { Row( modifier = modifier .fillMaxWidth() @@ -383,9 +379,7 @@ private fun makePriceImpactBalanceWarning(value: String, priceImpactPercents: In } @Composable -private fun TokenImageShimmer( - modifier: Modifier = Modifier, -) { +private fun TokenImageShimmer(modifier: Modifier = Modifier) { Box(modifier = modifier.shimmer()) { Box( modifier = Modifier diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index e441f3bf63..1c1ea1538f 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -159,11 +159,7 @@ internal class SwapViewModel @Inject constructor( } } - private fun loadQuotesTask( - fromToken: Currency, - toToken: Currency, - amount: String, - ): PeriodicTask { + private fun loadQuotesTask(fromToken: Currency, toToken: Currency, amount: String): PeriodicTask { return PeriodicTask( UPDATE_DELAY, task = { diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt index 31b45f81f9..341b2879e7 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt @@ -20,10 +20,7 @@ import com.tangem.feature.tester.impl.R @OptIn(ExperimentalFoundationApi::class) @Composable -internal fun TesterActionsScreen( - state: TesterActionsContentState, - modifier: Modifier = Modifier, -) { +internal fun TesterActionsScreen(state: TesterActionsContentState, modifier: Modifier = Modifier) { LazyColumn( modifier = modifier .fillMaxSize() @@ -48,11 +45,7 @@ internal fun TesterActionsScreen( } @Composable -private fun TesterActionItem( - progress: Boolean, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { +private fun TesterActionItem(progress: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { Box(modifier = modifier.padding(all = TangemTheme.dimens.spacing16)) { PrimaryButton( modifier = Modifier.fillMaxWidth(), @@ -65,9 +58,7 @@ private fun TesterActionItem( // region Preview @Composable -private fun TesterActionsScreenSample( - modifier: Modifier = Modifier, -) { +private fun TesterActionsScreenSample(modifier: Modifier = Modifier) { Column( modifier = modifier .background(TangemTheme.colors.background.primary), diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 00e0cb0b22..f61ac7485b 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -70,13 +70,13 @@ kotlinSerialization = "1.4.1" # region Tangem tangemBlockchainSdk = "develop-185" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-206" +tangemCardSdk = "develop-208" # tangemCardSdk = "0.0.1" # Keep it! - used for local builds # endregion Tangem # region Tools detektComposeRules = "1.2.2" -detekt = "1.21.0" +detekt = "1.22.0" # endregion Tools # region Testing diff --git a/plugins/configuration/detekt.yml b/plugins/configuration/detekt.yml index 434aed89be..51dbfc0927 100644 --- a/plugins/configuration/detekt.yml +++ b/plugins/configuration/detekt.yml @@ -66,7 +66,7 @@ comments: complexity: active: true - ComplexMethod: + CyclomaticComplexMethod: active: true ComplexCondition: active: true @@ -550,7 +550,7 @@ style: NestedClassesVisibility: active: true NewLineAtEndOfFile: - active: false # This rules overlaps with style>NewLineAtEndOfFile from the standard rules + active: false # Same as FinalNewline NoTabs: active: true NullableBooleanCheck: @@ -690,8 +690,8 @@ formatting: Filename: active: true # This rules overlaps with naming>MatchingDeclarationName from the standard rules mustBeFirst: true - FinalNewline: - active: false + FinalNewline: # This rules overlaps with style>NewLineAtEndOfFile from the standard rules + active: true insertFinalNewLine: true FunKeywordSpacing: active: true @@ -797,10 +797,10 @@ formatting: active: true TrailingCommaOnCallSite: active: true - useTrailingCommaOnCallSite: false + useTrailingCommaOnCallSite: true TrailingCommaOnDeclarationSite: active: true - useTrailingCommaOnCallSite: false + useTrailingCommaOnDeclarationSite: true TypeArgumentListSpacing: active: true TypeParameterListSpacing: @@ -808,7 +808,7 @@ formatting: UnnecessaryParenthesesBeforeTrailingLambda: active: true Wrapping: - active: false + active: true indentSize: 4 compose: From c069df9302efeb69ca100fa09a3a31304184a9e2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 10 Apr 2023 18:22:31 +0900 Subject: [PATCH 04/30] Updated on 2026-08-14 --- app/build.gradle.kts | 1 + .../tangem/tap/features/home/HomeFragment.kt | 3 + .../tokens/presentation/TokensListFragment.kt | 8 +- ...etworkItemState.kt => NetworkItemState.kt} | 30 +- .../presentation/states/TokenItemModel.kt | 14 - .../presentation/states/TokenItemState.kt | 48 ++ ...tateHolder.kt => TokensListStateHolder.kt} | 24 +- ...lbarState.kt => TokensListToolbarState.kt} | 8 +- .../states/TokensListVisibility.kt | 4 +- .../tokens/presentation/ui/AddTokensScreen.kt | 141 ++---- .../presentation/ui/AddTokensToolbar.kt | 97 ++-- .../presentation/ui/BriefNetworksList.kt | 23 +- .../presentation/ui/DetailedNetworksList.kt | 94 ++-- .../tokens/presentation/ui/TokenItem.kt | 86 +--- .../presentation/ui/TokenListPreviewData.kt | 74 +++ .../viewmodels/AddTokensViewModel.kt | 113 ----- .../viewmodels/TokensListViewModel.kt | 453 ++++++++++++++++++ .../com/tangem/core/ui/res/TangemDimens.kt | 1 + gradle/dependencies.toml | 2 + 19 files changed, 786 insertions(+), 438 deletions(-) rename app/src/main/java/com/tangem/tap/features/tokens/presentation/states/{AddTokensNetworkItemState.kt => NetworkItemState.kt} (54%) delete mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemModel.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt rename app/src/main/java/com/tangem/tap/features/tokens/presentation/states/{AddTokensStateHolder.kt => TokensListStateHolder.kt} (59%) rename app/src/main/java/com/tangem/tap/features/tokens/presentation/states/{AddTokensToolbarState.kt => TokensListToolbarState.kt} (93%) create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/AddTokensViewModel.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9d6381ca2f..b3831aa789 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -76,6 +76,7 @@ dependencies { kapt(deps.hilt.kapt) /** Other libraries */ + implementation(deps.kotlin.immutable.collections) implementation(deps.material) implementation(deps.googlePlay.core) implementation(deps.googlePlay.core.ktx) diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt index 4626dbbc44..372866fafc 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.platform.ComposeView +import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsControllerCompat import androidx.fragment.app.Fragment import com.google.accompanist.appcompattheme.AppCompatTheme @@ -49,6 +50,8 @@ class HomeFragment : Fragment(), StoreSubscriber { override fun onStart() { super.onStart() + activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, false) } + store.subscribe(this) { state -> state.skipRepeats { oldState, newState -> oldState.homeState == newState.homeState diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt index 85bb563548..0c66bbcbea 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt @@ -5,13 +5,14 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.core.view.WindowCompat import androidx.fragment.app.Fragment import androidx.hilt.navigation.compose.hiltViewModel import androidx.transition.TransitionInflater import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.features.tokens.presentation.ui.AddTokensScreen -import com.tangem.tap.features.tokens.presentation.viewmodels.AddTokensViewModel +import com.tangem.tap.features.tokens.presentation.viewmodels.TokensListViewModel import com.tangem.wallet.R import dagger.hilt.android.AndroidEntryPoint @@ -35,9 +36,8 @@ internal class TokensListFragment : Fragment() { setContent { isTransitionGroup = true - val viewModel = hiltViewModel().apply { - // TODO("[REDACTED_TASK_KEY] subscribe on Redux events") - // subscribeOnReduxEvents(lifecycle = LocalLifecycleOwner.current.lifecycle) + val viewModel = hiltViewModel().apply { + subscribeOnReduxEvents(lifecycle = LocalLifecycleOwner.current.lifecycle) } TangemTheme { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensNetworkItemState.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt similarity index 54% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensNetworkItemState.kt rename to app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt index c0df838d4d..c11142b85a 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensNetworkItemState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt @@ -1,11 +1,13 @@ package com.tangem.tap.features.tokens.presentation.states +import com.tangem.tap.features.tokens.redux.ContractAddress + /** * Network item state * [REDACTED_AUTHOR] */ -sealed interface AddTokensNetworkItemState { +sealed interface NetworkItemState { /** Network name */ val name: String @@ -23,6 +25,7 @@ sealed interface AddTokensNetworkItemState { * Network item state that is available for read * * @property name network name + * @property protocolName network protocol name * @property iconResId network icon id from resources * @property isMainNetwork flag that determines if the network is the main network for the token */ @@ -31,25 +34,30 @@ sealed interface AddTokensNetworkItemState { override val protocolName: String, override val iconResId: Int, override val isMainNetwork: Boolean, - ) : AddTokensNetworkItemState + ) : NetworkItemState /** * Network item state that is available for read and edit * - * @property name network name - * @property iconResId network icon id from resources - * @property isMainNetwork flag that determines if the network is the main network for the token - * @property isAdded flag that determines if the user has saved the token - * @property networkId network id - * @property onToggleClick lambda be invoked when switch is been toggled + * @property name network name + * @property protocolName network protocol name + * @property iconResId network icon id from resources + * @property isMainNetwork flag that determines if the network is the main network for the token + * @property isAdded flag that determines if the user has saved the token + * @property networkId network id + * @property contractAddress contract address + * @property onToggleClick lambda be invoked when switch is been toggled + * @property onNetworkClick lambda be invoked when network item is been clicked */ - data class EditAccess( + data class ManageAccess( override val name: String, override val protocolName: String, override val iconResId: Int, override val isMainNetwork: Boolean, val isAdded: Boolean, val networkId: String, - val onToggleClick: (String) -> Unit, - ) : AddTokensNetworkItemState + val contractAddress: ContractAddress?, + val onToggleClick: (String, String) -> Unit, + val onNetworkClick: () -> Unit, + ) : NetworkItemState } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemModel.kt deleted file mode 100644 index 07e0af08f0..0000000000 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemModel.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.tap.features.tokens.presentation.states - -/** - * Token model - * - * @property name token name - * @property iconUrl token icon url - * @property networks list of networks - */ -data class TokenItemModel( - val name: String, - val iconUrl: String, - val networks: List, -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt new file mode 100644 index 0000000000..5ce98ed4f0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt @@ -0,0 +1,48 @@ +package com.tangem.tap.features.tokens.presentation.states + +import kotlinx.collections.immutable.ImmutableList + +/** + * Network item state + * +[REDACTED_AUTHOR] + */ +sealed interface TokenItemState { + + /** Token name */ + val name: String + + /** Token icon url */ + val iconUrl: String + + /** List of networks */ + val networks: ImmutableList + + /** + * Token item state that is available for read + * + * @property name token name + * @property iconUrl token icon url + * @property networks list of networks that is available for read + */ + data class ReadAccess( + override val name: String, + override val iconUrl: String, + override val networks: ImmutableList, + ) : TokenItemState + + /** + * Token item state that is available for read and edit + * + * @property name token name + * @property iconUrl token icon url + * @property networks list of networks is available for read and edit + * @property id token id + */ + data class ManageAccess( + override val name: String, + override val iconUrl: String, + override val networks: ImmutableList, + val id: String, + ) : TokenItemState +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensStateHolder.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt similarity index 59% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensStateHolder.kt rename to app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt index 2db2b8bc59..0cf5c4d03a 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt @@ -1,21 +1,23 @@ package com.tangem.tap.features.tokens.presentation.states +import kotlinx.collections.immutable.ImmutableList + /** - * State holder for adding token screen + * State holder for screen with list of tokens * [REDACTED_AUTHOR] */ -internal sealed interface AddTokensStateHolder { +internal sealed interface TokensListStateHolder { /** Toolbar state */ - val toolbarState: AddTokensToolbarState + val toolbarState: TokensListToolbarState /** * Util function that allow to make a copy * * @param toolbarState toolbar state */ - fun copySealed(toolbarState: AddTokensToolbarState): AddTokensStateHolder { + fun copySealed(toolbarState: TokensListToolbarState): TokensListStateHolder { return when (this) { is ManageAccess -> copy(toolbarState = toolbarState) is Loading -> copy(toolbarState = toolbarState) @@ -28,7 +30,7 @@ internal sealed interface AddTokensStateHolder { * * @property toolbarState toolbar state */ - data class Loading(override val toolbarState: AddTokensToolbarState) : AddTokensStateHolder + data class Loading(override val toolbarState: TokensListToolbarState) : TokensListStateHolder /** * State screen that is available only for read @@ -37,9 +39,9 @@ internal sealed interface AddTokensStateHolder { * @property tokens tokens list */ data class ReadAccess( - override val toolbarState: AddTokensToolbarState, - override val tokens: List, - ) : AddTokensStateHolder, TokensListVisibility + override val toolbarState: TokensListToolbarState, + override val tokens: ImmutableList, + ) : TokensListStateHolder, TokensListVisibility /** * State screen that is available for read and edit @@ -49,8 +51,8 @@ internal sealed interface AddTokensStateHolder { * @property onSaveButtonClick callback to be invoked when SaveButton is being clicked */ data class ManageAccess( - override val toolbarState: AddTokensToolbarState, - override val tokens: List, + override val toolbarState: TokensListToolbarState, + override val tokens: ImmutableList, val onSaveButtonClick: () -> Unit, - ) : AddTokensStateHolder, TokensListVisibility + ) : TokensListStateHolder, TokensListVisibility } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensToolbarState.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt similarity index 93% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensToolbarState.kt rename to app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt index 8a21094acc..532c0739cf 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/AddTokensToolbarState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt @@ -1,7 +1,7 @@ package com.tangem.tap.features.tokens.presentation.states /** Toolbar state */ -sealed interface AddTokensToolbarState { +sealed interface TokensListToolbarState { /** Callback to be invoked when BackButton is being clicked */ val onBackButtonClick: () -> Unit @@ -10,7 +10,7 @@ sealed interface AddTokensToolbarState { val onSearchButtonClick: () -> Unit /** Toolbar state as title */ - sealed interface Title : AddTokensToolbarState { + sealed interface Title : TokensListToolbarState { /** Toolbar title id from resources */ val titleResId: Int @@ -36,7 +36,7 @@ sealed interface AddTokensToolbarState { * @property onSearchButtonClick callback to be invoked when SearchButton is being clicked * @property onAddCustomTokenClick callback to be invoked when AddCustomTokenButton is being clicked */ - data class EditAccess( + data class ManageAccess( override val titleResId: Int, override val onBackButtonClick: () -> Unit, override val onSearchButtonClick: () -> Unit, @@ -59,5 +59,5 @@ sealed interface AddTokensToolbarState { val value: String, val onValueChange: (String) -> Unit, val onCleanButtonClick: () -> Unit, - ) : AddTokensToolbarState + ) : TokensListToolbarState } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListVisibility.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListVisibility.kt index b1bd56a96e..4062066ad3 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListVisibility.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListVisibility.kt @@ -1,8 +1,10 @@ package com.tangem.tap.features.tokens.presentation.states +import kotlinx.collections.immutable.ImmutableList + /** Marker interface for states that have a list of tokens */ sealed interface TokensListVisibility { /** Tokens list */ - val tokens: List + val tokens: ImmutableList } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt index e2098944a0..a691d057e6 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt @@ -1,6 +1,9 @@ package com.tangem.tap.features.tokens.presentation.ui import androidx.activity.compose.BackHandler +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues @@ -12,6 +15,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.FabPosition import androidx.compose.material.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -22,33 +26,51 @@ import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.common.compose.extensions.OnBottomReached -import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemState -import com.tangem.tap.features.tokens.presentation.states.AddTokensStateHolder -import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState -import com.tangem.tap.features.tokens.presentation.states.TokenItemModel +import com.tangem.tap.features.tokens.presentation.states.TokenItemState +import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder +import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState import com.tangem.tap.features.tokens.presentation.states.TokensListVisibility import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.store import com.tangem.wallet.R +import kotlinx.collections.immutable.persistentListOf /** [REDACTED_AUTHOR] */ @Composable -internal fun AddTokensScreen(stateHolder: AddTokensStateHolder) { +internal fun AddTokensScreen(stateHolder: TokensListStateHolder) { BackHandler(onBack = stateHolder.toolbarState.onBackButtonClick) Scaffold( topBar = { AddTokensToolbar(state = stateHolder.toolbarState) }, floatingActionButton = { - if (stateHolder is AddTokensStateHolder.ManageAccess) { + if (stateHolder is TokensListStateHolder.ManageAccess) { SaveChangesButton(onClick = stateHolder.onSaveButtonClick) } }, - ) { - when (stateHolder) { - is AddTokensStateHolder.Loading -> LoadingContent() - is TokensListVisibility -> TokensListContent(stateHolder = stateHolder, scaffoldPadding = it) + floatingActionButtonPosition = FabPosition.Center, + ) { scaffoldPadding -> + // This is a hack because AnimatedContent trigger recomposition if stateHolder content is changed + AnimatedVisibility( + visible = stateHolder is TokensListVisibility, + enter = fadeIn(), + exit = fadeOut(), + ) { + if (stateHolder is TokensListVisibility) { + TokensListContent( + stateHolder = stateHolder, + scaffoldPadding = scaffoldPadding, + ) + } + } + + AnimatedVisibility( + visible = stateHolder is TokensListStateHolder.Loading, + enter = fadeIn(), + exit = fadeOut(), + ) { + LoadingContent() } } } @@ -67,9 +89,10 @@ private fun LoadingContent() { @Composable private fun TokensListContent(stateHolder: TokensListVisibility, scaffoldPadding: PaddingValues) { - val state = rememberLazyListState() - state.OnBottomReached(loadMoreThreshold = 40) { - store.dispatch(TokensAction.LoadMore(scanResponse = store.state.globalState.scanResponse)) + val state = rememberLazyListState().apply { + OnBottomReached(loadMoreThreshold = 40) { + store.dispatch(TokensAction.LoadMore(scanResponse = store.state.globalState.scanResponse)) + } } LazyColumn( modifier = Modifier @@ -79,7 +102,7 @@ private fun TokensListContent(stateHolder: TokensListVisibility, scaffoldPadding ) { items( items = stateHolder.tokens, - key = TokenItemModel::name, + key = TokenItemState::name, itemContent = { TokenItem(model = it) }, ) } @@ -102,8 +125,8 @@ private fun SaveChangesButton(onClick: () -> Unit) { private fun Preview_AddTokensScreen_Loading() { TangemTheme { AddTokensScreen( - stateHolder = AddTokensStateHolder.Loading( - toolbarState = AddTokensToolbarState.Title.EditAccess( + stateHolder = TokensListStateHolder.Loading( + toolbarState = TokensListToolbarState.Title.ManageAccess( titleResId = R.string.main_manage_tokens, onBackButtonClick = {}, onSearchButtonClick = {}, @@ -119,53 +142,16 @@ private fun Preview_AddTokensScreen_Loading() { private fun Preview_AddTokensScreen_ManageAccess() { TangemTheme { AddTokensScreen( - stateHolder = AddTokensStateHolder.ManageAccess( - toolbarState = AddTokensToolbarState.Title.EditAccess( + stateHolder = TokensListStateHolder.ManageAccess( + toolbarState = TokensListToolbarState.Title.ManageAccess( titleResId = R.string.main_manage_tokens, onBackButtonClick = {}, onSearchButtonClick = {}, onAddCustomTokenClick = {}, ), - tokens = listOf( - TokenItemModel( - name = "ETHEREUM (ETH)", - iconUrl = "", - networks = listOf( - AddTokensNetworkItemState.EditAccess( - name = "ETHEREUM", - protocolName = "MAIN", - iconResId = R.drawable.img_btc_22, - isMainNetwork = true, - isAdded = true, - networkId = "", - onToggleClick = {}, - ), - ), - ), - TokenItemModel( - name = "Tether (USDT)", - iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", - networks = listOf( - AddTokensNetworkItemState.EditAccess( - name = "ETHEREUM", - protocolName = "MAIN", - iconResId = R.drawable.img_eth_22, - isMainNetwork = false, - isAdded = true, - networkId = "", - onToggleClick = {}, - ), - AddTokensNetworkItemState.EditAccess( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_no_color, - isMainNetwork = false, - isAdded = false, - networkId = "", - onToggleClick = {}, - ), - ), - ), + tokens = persistentListOf( + TokenListPreviewData.createManageToken(), + TokenListPreviewData.createManageToken(), ), onSaveButtonClick = {}, ), @@ -178,44 +164,15 @@ private fun Preview_AddTokensScreen_ManageAccess() { private fun Preview_AddTokensScreen_ReadAccess() { TangemTheme { AddTokensScreen( - stateHolder = AddTokensStateHolder.ReadAccess( - toolbarState = AddTokensToolbarState.Title.EditAccess( + stateHolder = TokensListStateHolder.ReadAccess( + toolbarState = TokensListToolbarState.Title.ReadAccess( titleResId = R.string.search_tokens_title, onBackButtonClick = {}, onSearchButtonClick = {}, - onAddCustomTokenClick = {}, ), - tokens = listOf( - TokenItemModel( - name = "ETHEREUM (ETH)", - iconUrl = "", - networks = listOf( - AddTokensNetworkItemState.ReadAccess( - name = "ETHEREUM", - protocolName = "MAIN", - iconResId = R.drawable.img_btc_22, - isMainNetwork = true, - ), - ), - ), - TokenItemModel( - name = "Tether (USDT)", - iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", - networks = listOf( - AddTokensNetworkItemState.ReadAccess( - name = "ETHEREUM", - protocolName = "MAIN", - iconResId = R.drawable.img_eth_22, - isMainNetwork = false, - ), - AddTokensNetworkItemState.ReadAccess( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_no_color, - isMainNetwork = false, - ), - ), - ), + tokens = persistentListOf( + TokenListPreviewData.createReadToken(), + TokenListPreviewData.createReadToken(), ), ), ) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt index b8c160fa6e..a79d8cb8b4 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt @@ -1,12 +1,8 @@ package com.tangem.tap.features.tokens.presentation.ui -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions @@ -16,13 +12,18 @@ import androidx.compose.material.IconButton import androidx.compose.material.Text import androidx.compose.material.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -30,17 +31,19 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp +import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState -import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState.SearchInputField -import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState.Title +import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState +import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState.SearchInputField +import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState.Title import com.tangem.wallet.R +import kotlinx.coroutines.delay /** [REDACTED_AUTHOR] */ @Composable -internal fun AddTokensToolbar(state: AddTokensToolbarState) { +internal fun AddTokensToolbar(state: TokensListToolbarState) { TopAppBar(backgroundColor = TangemTheme.colors.background.secondary) { IconButton(onClick = state.onBackButtonClick) { Icon( @@ -50,14 +53,9 @@ internal fun AddTokensToolbar(state: AddTokensToolbarState) { ) } - val contentModifier = Modifier - .weight(1f) - .padding(horizontal = TangemTheme.dimens.spacing16) - .padding(bottom = TangemTheme.dimens.spacing4) - when (state) { - is Title -> TitleContent(state = state, modifier = contentModifier) - is SearchInputField -> InputContent(state = state, modifier = contentModifier) + is Title -> TitleContent(state = state, modifier = Modifier.weight(1f)) + is SearchInputField -> InputContent(state = state, modifier = Modifier.weight(1f)) } } } @@ -66,7 +64,7 @@ internal fun AddTokensToolbar(state: AddTokensToolbarState) { private fun TitleContent(state: Title, modifier: Modifier = Modifier) { Text( text = stringResource(id = state.titleResId), - modifier = modifier, + modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing26), color = TangemTheme.colors.text.primary1, maxLines = 1, style = TangemTheme.typography.h3, @@ -80,7 +78,7 @@ private fun TitleContent(state: Title, modifier: Modifier = Modifier) { ) } - if (state is Title.EditAccess) { + if (state is Title.ManageAccess) { IconButton(onClick = state.onAddCustomTokenClick) { Icon( painter = painterResource(id = R.drawable.ic_plus_24), @@ -91,12 +89,15 @@ private fun TitleContent(state: Title, modifier: Modifier = Modifier) { } } +@OptIn(ExperimentalComposeUiApi::class) @Composable -fun InputContent(state: SearchInputField, modifier: Modifier = Modifier) { +private fun InputContent(state: SearchInputField, modifier: Modifier = Modifier) { + val focusRequester = remember { FocusRequester() } + BasicTextField( value = state.value, onValueChange = state.onValueChange, - modifier = modifier, + modifier = modifier.focusRequester(focusRequester), textStyle = TangemTheme.typography.subtitle1.copy(fontWeight = FontWeight.Normal), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Search), keyboardActions = KeyboardActions(onSearch = { state.onSearchButtonClick() }), @@ -104,48 +105,52 @@ fun InputContent(state: SearchInputField, modifier: Modifier = Modifier) { maxLines = 1, cursorBrush = SolidColor(value = TangemTheme.colors.stroke.secondary), ) { innerTextField -> - Column(modifier = Modifier.padding(top = TangemTheme.dimens.spacing6)) { - Row(verticalAlignment = Alignment.CenterVertically) { - Box( - modifier = Modifier - .weight(1f) - .padding(start = TangemTheme.dimens.spacing6), - ) { - Hint(value = state.value) - innerTextField() - } - - IconButton(onClick = state.onCleanButtonClick) { - Icon( - painter = painterResource(id = R.drawable.ic_cross_rounded_24), - contentDescription = "Clean entered value", - tint = TangemTheme.colors.icon.secondary, - ) - } - } - + Row(verticalAlignment = Alignment.CenterVertically) { Box( modifier = Modifier - .fillMaxWidth() - .height(height = TangemTheme.dimens.size1) - .background(color = TangemTheme.colors.stroke.primary), - ) + .weight(1f) + .padding( + start = TangemTheme.dimens.spacing28, + top = TangemTheme.dimens.spacing2, + end = TangemTheme.dimens.spacing16, + ), + ) { + Hint(value = state.value) + innerTextField() + } + + IconButton(onClick = state.onCleanButtonClick) { + Icon( + painter = painterResource(id = R.drawable.ic_cross_rounded_24), + contentDescription = "Clean entered value", + tint = TangemTheme.colors.icon.secondary, + ) + } } } + + // This is a hack because Compose can't show the keyboard if the input field is not found. + // So first I request focus and make a delay and then show the keyboard. + val keyboardManager = LocalSoftwareKeyboardController.current + LaunchedEffect(keyboardManager) { + focusRequester.requestFocus() + delay(timeMillis = 100) + keyboardManager?.show() + } } @Composable private fun Hint(value: String) { if (value.isBlank()) { Row( - modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4), + modifier = Modifier.padding(start = TangemTheme.dimens.spacing4), horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing4), verticalAlignment = Alignment.CenterVertically, ) { Icon( painter = painterResource(id = R.drawable.ic_search_24), contentDescription = null, - tint = TangemTheme.colors.icon.secondary, + tint = TangemColorPalette.Dark1, ) Text( text = stringResource(id = R.string.common_search), @@ -164,7 +169,7 @@ private fun Hint(value: String) { private fun Preview_AddTokensToolbar_EditAccess() { TangemTheme { AddTokensToolbar( - state = Title.EditAccess( + state = Title.ManageAccess( titleResId = R.string.main_manage_tokens, onBackButtonClick = {}, onSearchButtonClick = {}, diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt index 868395a094..e44b3def87 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt @@ -1,10 +1,8 @@ package com.tangem.tap.features.tokens.presentation.ui import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -20,7 +18,8 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemState +import com.tangem.tap.features.tokens.presentation.states.NetworkItemState +import kotlinx.collections.immutable.ImmutableCollection /** [REDACTED_AUTHOR] @@ -28,21 +27,19 @@ import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemSt @Composable internal fun BriefNetworksList( isCollapsed: Boolean, - networks: List, + networks: ImmutableCollection, modifier: Modifier = Modifier, ) { AnimatedVisibility( visible = isCollapsed, modifier = modifier, - enter = fadeIn() + expandVertically(), - exit = shrinkVertically() + fadeOut(), + enter = fadeIn(), + exit = fadeOut(), ) { - if (isCollapsed) { - Row(horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4)) { - networks.forEach { - key(it.name) { - BriefNetworkItem(model = it) - } + Row(horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4)) { + networks.forEach { + key(NetworkItemState::name) { + BriefNetworkItem(model = it) } } } @@ -53,7 +50,7 @@ internal fun BriefNetworksList( [REDACTED_AUTHOR] */ @Composable -internal fun BriefNetworkItem(model: AddTokensNetworkItemState) { +internal fun BriefNetworkItem(model: NetworkItemState) { Box(modifier = Modifier.size(size = TangemTheme.dimens.size20)) { Image( painter = painterResource(id = model.iconResId), diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt index 1ad714408f..e404aec20e 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt @@ -5,6 +5,9 @@ import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope @@ -18,8 +21,11 @@ import androidx.compose.material.SwitchDefaults import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.key +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight @@ -28,8 +34,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemState -import com.tangem.wallet.R +import com.tangem.tap.features.tokens.presentation.states.NetworkItemState +import kotlinx.collections.immutable.ImmutableCollection /** [REDACTED_AUTHOR] @@ -37,7 +43,8 @@ import com.tangem.wallet.R @Composable internal fun DetailedNetworksList( isExpanded: Boolean, - networks: List, + tokenId: String?, + networks: ImmutableCollection, modifier: Modifier = Modifier, ) { AnimatedVisibility( @@ -46,38 +53,51 @@ internal fun DetailedNetworksList( enter = fadeIn() + expandVertically(), exit = shrinkVertically() + fadeOut(), ) { - if (isExpanded) { - Column { - networks.forEachIndexed { index, network -> - key(network.name) { - DetailedNetworkItem(model = network, isLastItem = networks.lastIndex == index) - } + Column { + networks.forEachIndexed { index, network -> + key(network.name) { + DetailedNetworkItem(model = network, tokenId = tokenId, isLastItem = networks.size - 1 == index) } } } } } +@OptIn(ExperimentalFoundationApi::class) @Composable -private fun DetailedNetworkItem(model: AddTokensNetworkItemState, isLastItem: Boolean) { +private fun DetailedNetworkItem(model: NetworkItemState, tokenId: String?, isLastItem: Boolean) { + val clipboardManager = LocalClipboardManager.current val itemHeight = TangemTheme.dimens.size50 + Row( modifier = Modifier + .combinedClickable( + enabled = model is NetworkItemState.ManageAccess, + onLongClick = { + if (model is NetworkItemState.ManageAccess && model.contractAddress != null) { + clipboardManager.setText(AnnotatedString(text = model.contractAddress)) + model.onNetworkClick() + } + }, + onClick = {}, + indication = null, + interactionSource = remember { MutableInteractionSource() }, + ) .fillMaxWidth() .heightIn(min = itemHeight) .padding(start = TangemTheme.dimens.spacing38), verticalAlignment = Alignment.CenterVertically, ) { NetworkItemArrow(itemHeight = itemHeight, isLastItem = isLastItem) - Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing14)) + Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing16)) BriefNetworkItem(model = model) Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing6)) NetworkTitle(model = model) - if (model is AddTokensNetworkItemState.EditAccess) { + if (model is NetworkItemState.ManageAccess) { Switch( checked = model.isAdded, - onCheckedChange = { model.onToggleClick(model.networkId) }, + onCheckedChange = { model.onToggleClick(requireNotNull(tokenId), model.networkId) }, modifier = Modifier.padding(start = TangemTheme.dimens.spacing16, end = TangemTheme.dimens.spacing8), colors = SwitchDefaults.colors( checkedThumbColor = TangemColorPalette.Meadow, @@ -88,7 +108,7 @@ private fun DetailedNetworkItem(model: AddTokensNetworkItemState, isLastItem: Bo } @Composable -private fun RowScope.NetworkTitle(model: AddTokensNetworkItemState) { +private fun RowScope.NetworkTitle(model: NetworkItemState) { Text( modifier = Modifier.weight(1f), text = buildAnnotatedString { @@ -105,7 +125,7 @@ private fun RowScope.NetworkTitle(model: AddTokensNetworkItemState) { }, fontWeight = FontWeight.SemiBold, fontSize = 13.sp, - color = if (model is AddTokensNetworkItemState.EditAccess && model.isAdded) { + color = if (model is NetworkItemState.ManageAccess && model.isAdded) { TangemColorPalette.Black } else { TangemColorPalette.Dark2 @@ -115,30 +135,12 @@ private fun RowScope.NetworkTitle(model: AddTokensNetworkItemState) { @Preview @Composable -private fun Preview_DetailedNetworksList_EditAccess() { +private fun Preview_DetailedNetworksList_ManageAccess() { TangemTheme { DetailedNetworksList( - networks = listOf( - AddTokensNetworkItemState.EditAccess( - name = "ETHEREUM", - protocolName = "MAIN", - iconResId = R.drawable.ic_eth_no_color, - isMainNetwork = true, - isAdded = true, - networkId = "", - onToggleClick = {}, - ), - AddTokensNetworkItemState.EditAccess( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_no_color, - isMainNetwork = false, - isAdded = false, - networkId = "", - onToggleClick = {}, - ), - ), - isExpanded = false, + isExpanded = true, + tokenId = null, + networks = TokenListPreviewData.createManageNetworksList(), ) } } @@ -148,21 +150,9 @@ private fun Preview_DetailedNetworksList_EditAccess() { private fun Preview_DetailedNetworksList_ReadAccess() { TangemTheme { DetailedNetworksList( - networks = listOf( - AddTokensNetworkItemState.ReadAccess( - name = "ETHEREUM", - protocolName = "MAIN", - iconResId = R.drawable.ic_eth_no_color, - isMainNetwork = true, - ), - AddTokensNetworkItemState.ReadAccess( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_no_color, - isMainNetwork = false, - ), - ), - isExpanded = false, + isExpanded = true, + tokenId = null, + networks = TokenListPreviewData.createReadNetworksList(), ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt index cdd70f25f3..ba0b7959ec 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt @@ -22,7 +22,7 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -38,16 +38,15 @@ import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.common.compose.extensions.toPx -import com.tangem.tap.features.tokens.presentation.states.AddTokensNetworkItemState -import com.tangem.tap.features.tokens.presentation.states.TokenItemModel +import com.tangem.tap.features.tokens.presentation.states.TokenItemState import com.tangem.wallet.R /** [REDACTED_AUTHOR] */ @Composable -internal fun TokenItem(model: TokenItemModel) { - var isExpanded by remember { mutableStateOf(false) } +internal fun TokenItem(model: TokenItemState) { + var isExpanded by rememberSaveable { mutableStateOf(false) } ConstraintLayout( modifier = Modifier @@ -102,6 +101,7 @@ internal fun TokenItem(model: TokenItemModel) { DetailedNetworksList( isExpanded = isExpanded, + tokenId = (model as? TokenItemState.ManageAccess)?.id, networks = model.networks, modifier = Modifier.constrainAs(detailedNetworksList) { top.linkTo(anchor = availableNetworksText.bottom, margin = spacing16) @@ -115,7 +115,7 @@ internal fun TokenItem(model: TokenItemModel) { onClick = { isExpanded = !isExpanded }, modifier = Modifier.constrainAs(changeNetworksViewButton) { top.linkTo(parent.top) - end.linkTo(anchor = parent.end, margin = spacing16) + end.linkTo(anchor = parent.end, margin = spacing6) if (!isExpanded) bottom.linkTo(parent.bottom) }, ) @@ -205,34 +205,9 @@ private fun ChangeNetworksViewButton(isExpanded: Boolean, onClick: () -> Unit, m @Preview @Composable -private fun Preview_TokenItem_EditAccess() { +private fun Preview_TokenItem_ManageAccess() { TangemTheme { - TokenItem( - TokenItemModel( - name = "Tether (USDT)", - iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", - networks = listOf( - AddTokensNetworkItemState.EditAccess( - name = "Ethereum", - protocolName = "MAIN", - iconResId = R.drawable.ic_eth_no_color, - isMainNetwork = true, - isAdded = true, - networkId = "", - onToggleClick = {}, - ), - AddTokensNetworkItemState.EditAccess( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_no_color, - isMainNetwork = false, - isAdded = false, - networkId = "", - onToggleClick = {}, - ), - ), - ), - ) + TokenItem(model = TokenListPreviewData.createManageToken()) } } @@ -240,49 +215,6 @@ private fun Preview_TokenItem_EditAccess() { @Composable private fun Preview_TokenItem_ReadAccess() { TangemTheme { - TokenItem( - TokenItemModel( - name = "Tether (USDT)", - iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", - networks = listOf( - AddTokensNetworkItemState.ReadAccess( - name = "Ethereum", - protocolName = "MAIN", - iconResId = R.drawable.ic_eth_no_color, - isMainNetwork = true, - ), - AddTokensNetworkItemState.ReadAccess( - name = "BNB SMART CHAIN", - protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_no_color, - isMainNetwork = false, - ), - ), - ), - ) - } -} - -@Preview -@Composable -private fun Preview_TokenItem_EditAccess_LargeNetworkList() { - TangemTheme { - TokenItem( - TokenItemModel( - name = "Tether (USDT)", - iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", - networks = List( - size = 15, - init = { - AddTokensNetworkItemState.ReadAccess( - name = if (it % 2 != 0) "Ethereum" else "BNB SMART CHAIN", - protocolName = if (it % 2 != 0) "MAIN" else "BEP20", - iconResId = if (it % 2 != 0) R.drawable.ic_eth_no_color else R.drawable.ic_bsc_no_color, - isMainNetwork = it % 2 != 0, - ) - }, - ), - ), - ) + TokenItem(model = TokenListPreviewData.createReadToken()) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt new file mode 100644 index 0000000000..8eb5cd50ee --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt @@ -0,0 +1,74 @@ +package com.tangem.tap.features.tokens.presentation.ui + +import com.tangem.tap.features.tokens.presentation.states.NetworkItemState +import com.tangem.tap.features.tokens.presentation.states.TokenItemState +import com.tangem.wallet.R +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +/** +[REDACTED_AUTHOR] + */ +object TokenListPreviewData { + + fun createManageToken(): TokenItemState.ManageAccess { + return TokenItemState.ManageAccess( + name = "Tether (USDT)", + iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", + networks = createManageNetworksList(), + id = "", + ) + } + + fun createReadToken(): TokenItemState.ReadAccess { + return TokenItemState.ReadAccess( + name = "Tether (USDT)", + iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", + networks = createReadNetworksList(), + ) + } + + fun createManageNetworksList(): ImmutableList { + return persistentListOf( + NetworkItemState.ManageAccess( + name = "Ethereum", + protocolName = "MAIN", + iconResId = R.drawable.ic_eth_no_color, + isMainNetwork = true, + isAdded = true, + networkId = "", + contractAddress = null, + onToggleClick = { _, _ -> }, + onNetworkClick = {}, + ), + NetworkItemState.ManageAccess( + name = "BNB SMART CHAIN", + protocolName = "BEP20", + iconResId = R.drawable.ic_bsc_no_color, + isMainNetwork = false, + isAdded = false, + networkId = "", + contractAddress = null, + onToggleClick = { _, _ -> }, + onNetworkClick = {}, + ), + ) + } + + fun createReadNetworksList(): ImmutableList { + return persistentListOf( + NetworkItemState.ReadAccess( + name = "Ethereum", + protocolName = "MAIN", + iconResId = R.drawable.ic_eth_no_color, + isMainNetwork = true, + ), + NetworkItemState.ReadAccess( + name = "BNB SMART CHAIN", + protocolName = "BEP20", + iconResId = R.drawable.ic_bsc_no_color, + isMainNetwork = false, + ), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/AddTokensViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/AddTokensViewModel.kt deleted file mode 100644 index 828ace57c6..0000000000 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/AddTokensViewModel.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.tangem.tap.features.tokens.presentation.viewmodels - -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.ViewModel -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.features.tokens.presentation.router.AddTokensRouter -import com.tangem.tap.features.tokens.presentation.states.AddTokensStateHolder -import com.tangem.tap.features.tokens.presentation.states.AddTokensToolbarState -import com.tangem.tap.features.tokens.redux.TokensAction -import com.tangem.tap.features.tokens.redux.TokensState -import com.tangem.tap.store -import com.tangem.wallet.R -import dagger.hilt.android.lifecycle.HiltViewModel -import org.rekotlin.StoreSubscriber -import javax.inject.Inject - -/** - * ViewModel for add tokens screen - * - * @property router feature router - * -[REDACTED_AUTHOR] - */ -@HiltViewModel -internal class AddTokensViewModel @Inject constructor( - private val router: AddTokensRouter, -) : ViewModel(), DefaultLifecycleObserver, StoreSubscriber { - - var uiState by mutableStateOf(getInitialUiState()) - private set - - init { - loadContent() - } - - override fun onStop(owner: LifecycleOwner) { - store.unsubscribe(subscriber = this) - } - - override fun onDestroy(owner: LifecycleOwner) { - store.dispatch(TokensAction.ResetState) - } - - override fun newState(state: TokensState) { - uiState = uiState.copySealed( - toolbarState = getToolbarState(hasEditAccess = state.allowToAdd), - ) - } - - private fun loadContent() { - store.subscribe(subscriber = this) { state -> - state - .skipRepeats { old, new -> old.tokensState == new.tokensState } - .select(AppState::tokensState) - } - } - - private fun getInitialUiState(): AddTokensStateHolder { - return AddTokensStateHolder.Loading(toolbarState = getToolbarState(store.state.tokensState.allowToAdd)) - } - - private fun getToolbarState(hasEditAccess: Boolean): AddTokensToolbarState { - return if (hasEditAccess) { - AddTokensToolbarState.Title.EditAccess( - titleResId = R.string.main_manage_tokens, - onBackButtonClick = router::popBackStack, - onSearchButtonClick = ::onSearchButtonClick, - onAddCustomTokenClick = router::openAddCustomTokenScreen, - ) - } else { - AddTokensToolbarState.Title.ReadAccess( - titleResId = R.string.search_tokens_title, - onBackButtonClick = router::popBackStack, - onSearchButtonClick = ::onSearchButtonClick, - ) - } - } - - private fun onSearchButtonClick() { - uiState = when (val state = uiState.toolbarState) { - is AddTokensToolbarState.Title -> { - uiState.copySealed( - toolbarState = AddTokensToolbarState.SearchInputField( - onBackButtonClick = uiState.toolbarState.onBackButtonClick, - onSearchButtonClick = ::onSearchButtonClick, - value = "", - onValueChange = ::onValueChange, - onCleanButtonClick = { onValueChange(newValue = "") }, - ), - ) - } - is AddTokensToolbarState.SearchInputField -> { - store.dispatch(TokensAction.SetSearchInput(state.value)) - uiState.copySealed( - getToolbarState(store.state.tokensState.allowToAdd), - ) - } - } - } - - private fun onValueChange(newValue: String) { - val state = requireNotNull( - value = uiState.toolbarState as? AddTokensToolbarState.SearchInputField, - lazyMessage = { "Impossible to change value in another state" }, - ) - - uiState = uiState.copySealed(toolbarState = state.copy(value = newValue)) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt new file mode 100644 index 0000000000..1b7c1fc3c0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt @@ -0,0 +1,453 @@ +package com.tangem.tap.features.tokens.presentation.viewmodels + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token +import com.tangem.core.analytics.Analytics +import com.tangem.core.ui.extensions.getActiveIconRes +import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.ManageTokens +import com.tangem.tap.common.extensions.dispatchDialogShow +import com.tangem.tap.common.extensions.dispatchNotification +import com.tangem.tap.common.extensions.fullNameWithoutTestnet +import com.tangem.tap.common.extensions.getGreyedOutIconRes +import com.tangem.tap.common.extensions.getNetworkName +import com.tangem.tap.common.redux.AppDialog +import com.tangem.tap.common.redux.AppState +import com.tangem.tap.domain.tokens.Contract +import com.tangem.tap.domain.tokens.Currency +import com.tangem.tap.features.tokens.presentation.router.AddTokensRouter +import com.tangem.tap.features.tokens.presentation.states.NetworkItemState +import com.tangem.tap.features.tokens.presentation.states.TokenItemState +import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder +import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState +import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.redux.TokensAction +import com.tangem.tap.features.tokens.redux.TokensState +import com.tangem.tap.features.tokens.ui.compose.fullName +import com.tangem.tap.features.wallet.redux.models.WalletDialog +import com.tangem.tap.store +import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider +import com.tangem.wallet.R +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.rekotlin.StoreSubscriber +import javax.inject.Inject + +/** + * ViewModel for add tokens screen + * + * @property router feature router + * @property dispatchers coroutine dispatchers provider + * +[REDACTED_AUTHOR] + */ +@HiltViewModel +internal class TokensListViewModel @Inject constructor( + private val router: AddTokensRouter, + private val dispatchers: AppCoroutineDispatcherProvider, +) : ViewModel() { + + private val uiStateBuilder = UiStateBuilder() + + var uiState by mutableStateOf(uiStateBuilder.getInitialUiState()) + private set + + private val reduxSubscriber = ReduxSubscriber() + private var debounceJob: Job? = null + + private var originalAddedTokenList: List? = null + private var originalAddedBlockchainList: List? = null + private var addedTokenList: List? = null + private var addedBlockchainList: List? = null + + fun subscribeOnReduxEvents(lifecycle: Lifecycle) { + lifecycle.addObserver(reduxSubscriber) + } + + private object AnalyticsSender { + fun sendWhenTokenAdded(token: Token) { + Analytics.send( + event = ManageTokens.TokenSwitcherChanged( + type = AnalyticsParam.CurrencyType.Token(token), + state = AnalyticsParam.OnOffState.On, + ), + ) + } + + fun sendWhenBlockchainAdded(blockchain: Blockchain) { + Analytics.send( + event = ManageTokens.TokenSwitcherChanged( + type = AnalyticsParam.CurrencyType.Blockchain(blockchain), + state = AnalyticsParam.OnOffState.On, + ), + ) + } + + fun sendWhenTokenRemoved(token: Token) { + Analytics.send( + event = ManageTokens.TokenSwitcherChanged( + type = AnalyticsParam.CurrencyType.Token(token), + state = AnalyticsParam.OnOffState.Off, + ), + ) + } + + fun sendWhenBlockchainRemoved(blockchain: Blockchain) { + Analytics.send( + event = ManageTokens.TokenSwitcherChanged( + type = AnalyticsParam.CurrencyType.Blockchain(blockchain), + state = AnalyticsParam.OnOffState.Off, + ), + ) + } + + fun sendWhenSaveButtonClicked() { + Analytics.send(ManageTokens.ButtonSaveChanges()) + } + } + + private inner class ReduxSubscriber : DefaultLifecycleObserver, StoreSubscriber { + + override fun onStart(owner: LifecycleOwner) { + store.subscribe( + subscriber = this, + transform = { state -> + state + .skipRepeats { old, new -> old.tokensState == new.tokensState } + .select(AppState::tokensState) + }, + ) + } + + override fun onStop(owner: LifecycleOwner) { + store.unsubscribe(subscriber = this) + } + + override fun newState(state: TokensState) { + val isNotOriginalListsInitialized = originalAddedTokenList == null || originalAddedBlockchainList == null + val isNotCurrentListsInitialized = addedTokenList == null || addedBlockchainList == null + + if (isNotOriginalListsInitialized || isNotCurrentListsInitialized) { + originalAddedTokenList = state.addedTokens + originalAddedBlockchainList = state.addedBlockchains + addedTokenList = state.addedTokens + addedBlockchainList = state.addedBlockchains + } + + uiStateBuilder.updateStateByReduxState(state) + } + } + + private inner class UiStateBuilder { + + fun getInitialUiState(): TokensListStateHolder { + return TokensListStateHolder.Loading(toolbarState = getToolbarState()) + } + + fun updateStateByReduxState(state: TokensState) { + uiState = if (state.currencies.isEmpty()) { + TokensListStateHolder.Loading(toolbarState = getToolbarState(reduxState = state)) + } else if (state.allowToAdd) { + TokensListStateHolder.ManageAccess( + toolbarState = getToolbarState(reduxState = state), + tokens = state.currencies.map(::toManageTokenItemState).toImmutableList(), + onSaveButtonClick = { + val notNullAddedTokens = addedTokenList ?: return@ManageAccess + val notNullAddedBlockchains = addedBlockchainList ?: return@ManageAccess + + AnalyticsSender.sendWhenSaveButtonClicked() + store.dispatch(TokensAction.SaveChanges(notNullAddedTokens, notNullAddedBlockchains)) + }, + ) + } else { + TokensListStateHolder.ReadAccess( + toolbarState = getToolbarState(state), + tokens = state.currencies.map(::toReadTokenItemState).toImmutableList(), + ) + } + } + + private fun getToolbarState(reduxState: TokensState = store.state.tokensState): TokensListToolbarState { + val toolbarState = uiState.toolbarState + + return if (reduxState.searchInput != null && toolbarState is TokensListToolbarState.SearchInputField) { + TokensListToolbarState.SearchInputField( + onBackButtonClick = router::popBackStack, + onSearchButtonClick = ::onSearchButtonClick, + value = toolbarState.value, + onValueChange = ::onSearchValueChange, + onCleanButtonClick = ::onCleanButtonClick, + ) + } else if (reduxState.allowToAdd) { + TokensListToolbarState.Title.ManageAccess( + titleResId = R.string.main_manage_tokens, + onBackButtonClick = router::popBackStack, + onSearchButtonClick = ::onSearchButtonClick, + onAddCustomTokenClick = router::openAddCustomTokenScreen, + ) + } else { + TokensListToolbarState.Title.ReadAccess( + titleResId = R.string.search_tokens_title, + onBackButtonClick = router::popBackStack, + onSearchButtonClick = ::onSearchButtonClick, + ) + } + } + + private fun onSearchButtonClick() { + uiState = when (val state = uiState.toolbarState) { + is TokensListToolbarState.Title -> { + uiState.copySealed( + toolbarState = TokensListToolbarState.SearchInputField( + onBackButtonClick = uiState.toolbarState.onBackButtonClick, + onSearchButtonClick = uiState.toolbarState.onSearchButtonClick, + value = "", + onValueChange = ::onSearchValueChange, + onCleanButtonClick = ::onCleanButtonClick, + ), + ) + } + is TokensListToolbarState.SearchInputField -> { + store.dispatch(TokensAction.SetSearchInput(searchInput = state.value)) + uiState.copySealed(toolbarState = getToolbarState()) + } + } + } + + private fun onSearchValueChange(newValue: String) { + (uiState.toolbarState as? TokensListToolbarState.SearchInputField)?.let { state -> + uiState = uiState.copySealed(toolbarState = state.copy(value = newValue)) + } + + debounceJob?.cancel() + debounceJob = viewModelScope.launch(dispatchers.io) { + delay(timeMillis = 800L) + store.dispatch(TokensAction.SetSearchInput(searchInput = newValue)) + } + } + + private fun onCleanButtonClick() { + (uiState.toolbarState as? TokensListToolbarState.SearchInputField)?.let { state -> + if (state.value.isEmpty()) { + uiState = uiState.copySealed(toolbarState = getToolbarState()) + } else { + onSearchValueChange(newValue = "") + } + } + } + + private fun onToggleClick(tokenId: String, networkId: String) { + (uiState as? TokensListStateHolder.ManageAccess)?.let { state -> + val switchedToken = state.tokens.firstOrNull { it.id == tokenId } + val contractAddress = switchedToken?.networks + ?.firstOrNull { it.networkId == networkId } + ?.contractAddress + + val blockchain = Blockchain.fromNetworkId( + networkId = if (contractAddress == null) networkId else tokenId, + ) + + if (blockchain != null && contractAddress == null) { + onBlockchainToggleClick(blockchain) + } else if (contractAddress != null) { + onTokenToggleClick(tokenId, networkId, switchedToken, contractAddress) + } + + updateTokensList() + } + } + + private fun onBlockchainToggleClick(blockchain: Blockchain) { + val isRemoveAction = addedBlockchainList?.contains(blockchain) + + if (isRemoveAction == true) { + val isTokenWithSameBlockchainFound = addedTokenList?.any { it.blockchain == blockchain } + val isAddedOnMainScreen = originalAddedBlockchainList?.contains(blockchain) + + if (isTokenWithSameBlockchainFound == true) { + store.dispatchDialogShow( + WalletDialog.TokensAreLinkedDialog( + currencyTitle = blockchain.name, + currencySymbol = blockchain.currency, + ), + ) + } else if (isAddedOnMainScreen == true) { + store.dispatchDialogShow( + WalletDialog.RemoveWalletDialog( + currencyTitle = blockchain.name, + onOk = { + AnalyticsSender.sendWhenBlockchainAdded(blockchain) + addedBlockchainList = addedBlockchainList?.minus(blockchain) + updateTokensList() + }, + ), + ) + } else { + AnalyticsSender.sendWhenBlockchainRemoved(blockchain) + addedBlockchainList = addedBlockchainList?.minus(blockchain) + } + } else { + AnalyticsSender.sendWhenBlockchainAdded(blockchain) + addedBlockchainList = addedBlockchainList?.plus(blockchain) + } + } + + private fun onTokenToggleClick( + tokenId: String, + networkId: String, + switchedToken: TokenItemState.ManageAccess, + contractAddress: String, + ) { + val currency = store.state.tokensState.currencies.firstOrNull { it.id == tokenId } ?: return + val contract = currency.contracts.firstOrNull { it.networkId == networkId } ?: return + val token = TokenWithBlockchain( + token = Token( + id = switchedToken.id, + name = switchedToken.name, + symbol = currency.symbol, + contractAddress = contractAddress, + decimals = requireNotNull(contract.decimalCount), + ), + blockchain = contract.blockchain, + ) + val isUnsupportedToken = !store.state.tokensState.canHandleToken(token) + val isRemoveAction = addedTokenList?.contains(token) + val isAddedOnMainScreen = originalAddedTokenList?.contains(token) + if (isRemoveAction == true) { + if (isAddedOnMainScreen == true) { + store.dispatchDialogShow( + WalletDialog.RemoveWalletDialog( + currencyTitle = token.token.name, + onOk = { + AnalyticsSender.sendWhenTokenRemoved(token.token) + addedTokenList = addedTokenList?.minus(token) + updateTokensList() + }, + ), + ) + } else { + AnalyticsSender.sendWhenTokenRemoved(token.token) + addedTokenList = addedTokenList?.minus(token) + } + } else { + if (isUnsupportedToken) { + store.dispatchDialogShow( + AppDialog.SimpleOkDialogRes( + headerId = R.string.common_warning, + messageId = R.string.alert_manage_tokens_unsupported_message, + ), + ) + } else { + AnalyticsSender.sendWhenTokenAdded(token.token) + addedTokenList = addedTokenList?.plus(token) + } + } + } + + private fun updateTokensList() { + (uiState as? TokensListStateHolder.ManageAccess)?.let { state -> + val tokens = store.state.tokensState.currencies.mapNotNull { currency -> + state.tokens.firstOrNull { it.id == currency.id }?.copy( + networks = currency.contracts.mapNotNull { contract -> + state.tokens.firstOrNull { it.id == currency.id } + ?.networks?.firstOrNull { it.networkId == contract.networkId } + ?.copy( + isAdded = contract.isAdded(), + iconResId = if (contract.isAdded()) { + getActiveIconRes(contract.blockchain.id) + } else { + contract.blockchain.getGreyedOutIconRes() + }, + ) + }.toImmutableList(), + ) + }.toImmutableList() + + uiState = state.copy(tokens = tokens) + } + } + + private fun toManageTokenItemState(currency: Currency): TokenItemState.ManageAccess { + return TokenItemState.ManageAccess( + name = currency.fullName, + iconUrl = currency.iconUrl, + networks = currency.contracts.map(::toManageNetworkItemState).toImmutableList(), + id = currency.id, + ) + } + + private fun toManageNetworkItemState(contract: Contract): NetworkItemState.ManageAccess { + val isAdded = contract.isAdded() + return NetworkItemState.ManageAccess( + name = contract.blockchain.fullNameWithoutTestnet.uppercase(), + protocolName = if (contract.address == null) { + MAIN_NETWORK_LABEL + } else { + contract.blockchain.getNetworkName().uppercase() + }, + iconResId = if (isAdded) { + getActiveIconRes(contract.blockchain.id) + } else { + contract.blockchain.getGreyedOutIconRes() + }, + isMainNetwork = contract.address == null, + isAdded = isAdded, + networkId = contract.networkId, + contractAddress = contract.address, + onToggleClick = ::onToggleClick, + onNetworkClick = { store.dispatchNotification(R.string.contract_address_copied_message) }, + ) + } + + private fun toReadTokenItemState(currency: Currency): TokenItemState.ReadAccess { + return TokenItemState.ReadAccess( + name = currency.fullName, + iconUrl = currency.iconUrl, + networks = currency.contracts.map(::toReadNetworkItemState).toImmutableList(), + ) + } + + private fun toReadNetworkItemState(contract: Contract): NetworkItemState.ReadAccess { + return NetworkItemState.ReadAccess( + name = contract.blockchain.fullNameWithoutTestnet.uppercase(), + protocolName = if (contract.address == null) { + MAIN_NETWORK_LABEL + } else { + contract.blockchain.getNetworkName().uppercase() + }, + iconResId = if (contract.isAdded()) { + getActiveIconRes(contract.blockchain.id) + } else { + contract.blockchain.getGreyedOutIconRes() + }, + isMainNetwork = contract.address == null, + ) + } + + private fun Contract.isAdded(): Boolean { + return if (address != null) { + addedTokenList?.any { addedToken -> + address == addedToken.token.contractAddress && blockchain == addedToken.blockchain + } + } else { + addedBlockchainList?.contains(blockchain) + } ?: false + } + } + + private companion object { + const val MAIN_NETWORK_LABEL = "MAIN" + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt index 26189619df..7a5dcfec58 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt @@ -80,6 +80,7 @@ data class TangemDimens internal constructor( val spacing18: Dp = 18.dp, val spacing20: Dp = 20.dp, val spacing24: Dp = 24.dp, + val spacing26: Dp = 26.dp, val spacing28: Dp = 28.dp, val spacing32: Dp = 32.dp, val spacing34: Dp = 34.dp, diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index f61ac7485b..c39054104a 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -46,6 +46,7 @@ hilt = "2.44" hilt-navigation = "1.0.0" jodatime = "2.12.1" krateSharedPref = "2.0.0" +kotlin-immutable-collections = "0.3.5" kotsonGsonExt = "2.5.0" lottie = "3.4.0" moshi = "1.12.0" @@ -168,6 +169,7 @@ appsflyer = { module = "com.appsflyer:af-android-sdk", version.ref = "appsflyer" armadillo = { module = "at.favre.lib:armadillo", version.ref = "armadillo" } coil = { module = "io.coil-kt:coil", version.ref = "coil" } kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutine" } +kotlin-immutable-collections = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlin-immutable-collections" } desugar = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugarJdkLibs" } googlePlay-core = { module = "com.google.android.play:core", version.ref = "googlePlayCore" } googlePlay-core-ktx = { module = "com.google.android.play:core-ktx", version.ref = "googlePlayCoreKtx" } From a3a0d325da7b96ec2fcca19fdc4e4330404e537e Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 10 Apr 2023 21:23:27 +0900 Subject: [PATCH 05/30] Updated on 2026-08-14 --- app/src/main/assets/testnet_tokens.json | 5 +-- .../di/TestnetTokensStorageModule.kt | 27 ++++++++++++ .../testnet/DefaultTestnetTokensStorage.kt | 31 ++++++++++++++ .../local/testnet/TestnetTokensStorage.kt | 14 +++++++ .../testnet/models/TestnetTokensConfig.kt | 42 +++++++++++++++++++ 5 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 core/datasource/src/main/java/com/tangem/datasource/di/TestnetTokensStorageModule.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/testnet/DefaultTestnetTokensStorage.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/testnet/TestnetTokensStorage.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/testnet/models/TestnetTokensConfig.kt diff --git a/app/src/main/assets/testnet_tokens.json b/app/src/main/assets/testnet_tokens.json index f1f1b8ce59..8b227fde97 100644 --- a/app/src/main/assets/testnet_tokens.json +++ b/app/src/main/assets/testnet_tokens.json @@ -463,8 +463,5 @@ } ] } - ], - - "total" : 0, - "imageHost" : "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/" + ] } diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/TestnetTokensStorageModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/TestnetTokensStorageModule.kt new file mode 100644 index 0000000000..229722e50d --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/di/TestnetTokensStorageModule.kt @@ -0,0 +1,27 @@ +package com.tangem.datasource.di + +import com.squareup.moshi.Moshi +import com.squareup.moshi.adapter +import com.tangem.datasource.asset.AssetReader +import com.tangem.datasource.local.testnet.DefaultTestnetTokensStorage +import com.tangem.datasource.local.testnet.TestnetTokensStorage +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +/** +[REDACTED_AUTHOR] + */ +@Module +@InstallIn(SingletonComponent::class) +object TestnetTokensStorageModule { + + @OptIn(ExperimentalStdlibApi::class) + @Provides + @Singleton + fun providesTestnetTokensStorage(assetReader: AssetReader, @SdkMoshi moshi: Moshi): TestnetTokensStorage { + return DefaultTestnetTokensStorage(assetReader = assetReader, adapter = moshi.adapter()) + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/testnet/DefaultTestnetTokensStorage.kt b/core/datasource/src/main/java/com/tangem/datasource/local/testnet/DefaultTestnetTokensStorage.kt new file mode 100644 index 0000000000..d4a3a066e1 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/testnet/DefaultTestnetTokensStorage.kt @@ -0,0 +1,31 @@ +package com.tangem.datasource.local.testnet + +import com.squareup.moshi.JsonAdapter +import com.tangem.datasource.asset.AssetReader +import com.tangem.datasource.local.testnet.models.TestnetTokensConfig + +/** + * Default implementation for storing testnet tokens data + * + * @property assetReader file reader from assets + * @property adapter adapter for parsing testnet tokens config + * +[REDACTED_AUTHOR] + */ +internal class DefaultTestnetTokensStorage( + private val assetReader: AssetReader, + private val adapter: JsonAdapter, +) : TestnetTokensStorage { + + override fun getConfig(): TestnetTokensConfig { + return requireNotNull( + value = adapter.fromJson( + assetReader.readJson(fileName = LOCAL_CONFIG_PATH), + ), + ) + } + + private companion object { + const val LOCAL_CONFIG_PATH: String = "testnet_tokens" + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/testnet/TestnetTokensStorage.kt b/core/datasource/src/main/java/com/tangem/datasource/local/testnet/TestnetTokensStorage.kt new file mode 100644 index 0000000000..7f091e98e6 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/testnet/TestnetTokensStorage.kt @@ -0,0 +1,14 @@ +package com.tangem.datasource.local.testnet + +import com.tangem.datasource.local.testnet.models.TestnetTokensConfig + +/** + * Storage of testnet tokens data + * +[REDACTED_AUTHOR] + */ +interface TestnetTokensStorage { + + /** Get a testnet tokens data */ + fun getConfig(): TestnetTokensConfig +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/testnet/models/TestnetTokensConfig.kt b/core/datasource/src/main/java/com/tangem/datasource/local/testnet/models/TestnetTokensConfig.kt new file mode 100644 index 0000000000..1e619014cf --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/testnet/models/TestnetTokensConfig.kt @@ -0,0 +1,42 @@ +package com.tangem.datasource.local.testnet.models + +import com.squareup.moshi.Json + +/** + * Config model with testnet tokens list + * + * @property tokens testnet tokens list + */ +data class TestnetTokensConfig( + @Json(name = "coins") val tokens: List, +) { + + /** + * Testnet token model + * + * @property id token id + * @property name token name + * @property symbol token brief name. Example, "BTC" + * @property networks networks of testnet token + */ + data class Token( + @Json(name = "id") val id: String, + @Json(name = "name") val name: String, + @Json(name = "symbol") val symbol: String, + @Json(name = "networks") val networks: List? = null, + ) { + + /** + * Network model of testnet token + * + * @property id network id + * @property address network address + * @property decimalCount decimal count + */ + data class Network( + @Json(name = "networkId") val id: String, + @Json(name = "contractAddress") val address: String?, + @Json(name = "decimalCount") val decimalCount: Int?, + ) + } +} \ No newline at end of file From c683506ffac2319e829afac6dfbe3bc8251b80d4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 11 Apr 2023 19:24:29 +0900 Subject: [PATCH 06/30] Updated on 2026-08-14 --- app/build.gradle.kts | 2 + .../tokens/LoadAvailableCoinsService.kt | 40 ++++++------ .../data/DefaultTokensListRepository.kt | 53 ++++++++++++++++ .../data/TangemApiTokensPagingSource.kt | 62 +++++++++++++++++++ .../tokens/data/TestnetTokensPagingSource.kt | 43 +++++++++++++ .../data/converters/CoinsResponseConverter.kt | 37 +++++++++++ .../TestnetTokensConfigConverter.kt | 37 +++++++++++ .../tokens/di/TokensListRepositoryModule.kt | 37 +++++++++++ .../tokens/domain/TokensListRepository.kt | 20 ++++++ .../features/tokens/domain/models/Token.kt | 40 ++++++++++++ .../tap/features/tokens/redux/TokensAction.kt | 5 +- .../features/tokens/redux/TokensMiddleware.kt | 53 +++++++--------- .../features/tokens/redux/TokensReducer.kt | 1 - .../tap/features/tokens/redux/TokensState.kt | 19 +++--- .../wallet/ui/wallet/MultiWalletView.kt | 12 +--- gradle/dependencies.toml | 4 ++ 16 files changed, 389 insertions(+), 76 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/data/DefaultTokensListRepository.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/data/TangemApiTokensPagingSource.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/data/TestnetTokensPagingSource.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListRepository.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b3831aa789..f3691ec571 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -40,6 +40,7 @@ dependencies { implementation(deps.androidx.constraintLayout) implementation(deps.androidx.activity.compose) implementation(deps.androidx.browser) + implementation(deps.androidx.paging.runtime) implementation(deps.lifecycle.runtime.ktx) implementation(deps.lifecycle.common.java8) implementation(deps.lifecycle.viewModel.ktx) @@ -56,6 +57,7 @@ dependencies { implementation(deps.compose.shimmer) implementation(deps.compose.ui) implementation(deps.compose.ui.tooling) + implementation(deps.compose.paging) /** Firebase libraries */ implementation(platform(deps.firebase.bom)) diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt index 51c4c304e2..39e845f7b2 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt @@ -20,10 +20,10 @@ class LoadAvailableCoinsService( MoshiConverter.networkMoshi.adapter(CurrenciesFromJson::class.java) suspend fun getSupportedTokens( - isTestNet: Boolean = false, + isTestNet: Boolean, supportedBlockchains: List, page: Int, - searchInput: String? = null, + searchInput: String?, ): Result { if (isTestNet) { return Result.Success( @@ -33,15 +33,17 @@ class LoadAvailableCoinsService( ), ) } - val offset = page * LOAD_PER_PAGE - val result = loadCoins(supportedBlockchains, offset, searchInput) - return when (result) { + val offset = page * LOAD_PER_PAGE + return when (val result = loadCoins(supportedBlockchains, offset, searchInput)) { is Result.Success -> { val data = result.data + Result.Success( LoadedCoins( - currencies = data.coins.map { Currency.fromCoinResponse(it, data.imageHost) }, + currencies = data.coins.map { + Currency.fromCoinResponse(currency = it, imageHost = data.imageHost) + }, moreAvailable = data.total > offset + LOAD_PER_PAGE, ), ) @@ -55,22 +57,24 @@ class LoadAvailableCoinsService( private suspend fun loadCoins( supportedBlockchains: List, offset: Int, - searchInput: String? = null, + searchInput: String?, ): Result { return withContext(dispatchers.io) { runCatching { tangemTechApi.getCoins( - networkIds = supportedBlockchains.toSet().joinToString(",", transform = Blockchain::toNetworkId), + networkIds = supportedBlockchains.joinToString( + separator = ",", + transform = Blockchain::toNetworkId, + ), active = true, searchText = searchInput, offset = offset, limit = LOAD_PER_PAGE, ) - } - .onSuccess { return@withContext Result.Success(it) } - .onFailure { return@withContext Result.Failure(it) } - - error("Unreachable code because runCatching must return result") + }.fold( + onSuccess = { Result.Success(it) }, + onFailure = { Result.Failure(it) }, + ) } } @@ -83,15 +87,15 @@ class LoadAvailableCoinsService( private fun List.filter(searchInput: String?): List { if (searchInput.isNullOrBlank()) return this - return filter { - it.symbol.contains(searchInput, ignoreCase = true) || - it.name.contains(searchInput, ignoreCase = true) + return filter { currency -> + currency.symbol.contains(searchInput, ignoreCase = true) || + currency.name.contains(searchInput, ignoreCase = true) } } - companion object { + private companion object { const val LOAD_PER_PAGE = 100 - private const val FILE_NAME_TESTNET_COINS = "testnet_tokens" + const val FILE_NAME_TESTNET_COINS = "testnet_tokens" } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/DefaultTokensListRepository.kt b/app/src/main/java/com/tangem/tap/features/tokens/data/DefaultTokensListRepository.kt new file mode 100644 index 0000000000..ba522709c6 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/data/DefaultTokensListRepository.kt @@ -0,0 +1,53 @@ +package com.tangem.tap.features.tokens.data + +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.local.testnet.TestnetTokensStorage +import com.tangem.domain.common.TapWorkarounds.isTestCard +import com.tangem.tap.features.tokens.domain.TokensListRepository +import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.proxy.AppStateHolder +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.Flow + +/** + * Default repository implementation of tokens list feature + * + * @property tangemTechApi Tangem Tech API + * @property dispatchers coroutine dispatchers provider + * @property reduxStateHolder redux state holder + * @property testnetTokensStorage storage for getting testnet tokens data + * +[REDACTED_AUTHOR] + */ +internal class DefaultTokensListRepository( + private val tangemTechApi: TangemTechApi, + private val dispatchers: CoroutineDispatcherProvider, + private val reduxStateHolder: AppStateHolder, + private val testnetTokensStorage: TestnetTokensStorage, +) : TokensListRepository { + + override fun getAvailableTokens(searchText: String?): Flow> { + return Pager( + config = PagingConfig( + pageSize = 100, + prefetchDistance = 70, + enablePlaceholders = false, + ), + pagingSourceFactory = { + if (reduxStateHolder.scanResponse?.card?.isTestCard == true) { + TestnetTokensPagingSource(testnetTokensStorage, searchText) + } else { + TangemApiTokensPagingSource( + api = tangemTechApi, + dispatchers = dispatchers, + reduxStateHolder = reduxStateHolder, + searchText = searchText, + ) + } + }, + ).flow + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/TangemApiTokensPagingSource.kt b/app/src/main/java/com/tangem/tap/features/tokens/data/TangemApiTokensPagingSource.kt new file mode 100644 index 0000000000..d9d63213bd --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/data/TangemApiTokensPagingSource.kt @@ -0,0 +1,62 @@ +package com.tangem.tap.features.tokens.data + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.tangem.blockchain.common.Blockchain +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.domain.common.extensions.supportedBlockchains +import com.tangem.domain.common.extensions.toNetworkId +import com.tangem.tap.features.tokens.data.converters.CoinsResponseConverter +import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.proxy.AppStateHolder +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.runCatching + +/** + * Paging source that get tokens by Tangem Tech API + * + * @property api Tangem Tech API + * @property dispatchers coroutine dispatchers provider + * @property reduxStateHolder redux state holder + * @property searchText search text + */ +internal class TangemApiTokensPagingSource( + private val api: TangemTechApi, + private val dispatchers: CoroutineDispatcherProvider, + private val reduxStateHolder: AppStateHolder, + private val searchText: String?, +) : PagingSource() { + + override fun getRefreshKey(state: PagingState): Int? { + return state.anchorPosition?.let { anchorPosition -> + state.closestPageToPosition(anchorPosition)?.prevKey?.plus(other = 1) + ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(other = 1) + } + } + + override suspend fun load(params: LoadParams): LoadResult { + val page = params.key ?: 0 + + return runCatching(dispatchers.io) { + val supportedBlockchains = reduxStateHolder.scanResponse?.card?.supportedBlockchains() + ?: Blockchain.values().toList() + + api.getCoins( + networkIds = supportedBlockchains.joinToString(separator = ",", transform = Blockchain::toNetworkId), + active = true, + searchText = searchText, + offset = page * params.loadSize, + limit = params.loadSize, + ) + }.fold( + onSuccess = { response -> + LoadResult.Page( + data = CoinsResponseConverter.convert(response), + prevKey = if (page == 0) null else page.minus(other = 1), + nextKey = if (response.coins.isEmpty()) null else page.plus(other = 1), + ) + }, + onFailure = { LoadResult.Error(it) }, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/TestnetTokensPagingSource.kt b/app/src/main/java/com/tangem/tap/features/tokens/data/TestnetTokensPagingSource.kt new file mode 100644 index 0000000000..87943ee140 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/data/TestnetTokensPagingSource.kt @@ -0,0 +1,43 @@ +package com.tangem.tap.features.tokens.data + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.tangem.datasource.local.testnet.TestnetTokensStorage +import com.tangem.datasource.local.testnet.models.TestnetTokensConfig +import com.tangem.tap.features.tokens.data.converters.TestnetTokensConfigConverter +import com.tangem.tap.features.tokens.domain.models.Token + +/** + * Paging source that get tokens by testnet tokens config + * + * @property testnetTokensStorage testnet tokens config storage + * @property searchText search text + */ +internal class TestnetTokensPagingSource( + private val testnetTokensStorage: TestnetTokensStorage, + private val searchText: String?, +) : PagingSource() { + + override fun getRefreshKey(state: PagingState): Int? = null + + override suspend fun load(params: LoadParams): LoadResult { + return LoadResult.Page( + data = TestnetTokensConfigConverter.convert( + value = testnetTokensStorage.getConfig().searchByText(searchText), + ), + prevKey = null, + nextKey = null, + ) + } + + private fun TestnetTokensConfig.searchByText(searchText: String?): TestnetTokensConfig { + if (searchText.isNullOrBlank()) return this + + return copy( + tokens = tokens.filter { token -> + token.symbol.contains(other = searchText, ignoreCase = true) || + token.name.contains(other = searchText, ignoreCase = true) + }, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt new file mode 100644 index 0000000000..9fa6492d80 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt @@ -0,0 +1,37 @@ +package com.tangem.tap.features.tokens.data.converters + +import com.tangem.blockchain.common.Blockchain +import com.tangem.datasource.api.tangemTech.models.CoinsResponse +import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.tap.domain.tokens.getIconUrl +import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.utils.converter.Converter + +/** + * Converter from data model [CoinsResponse] to list of domain models [Token] + * +[REDACTED_AUTHOR] + */ +internal object CoinsResponseConverter : Converter> { + + override fun convert(value: CoinsResponse): List { + return value.coins.map { token -> + Token( + id = token.id, + name = token.name, + symbol = token.symbol, + iconUrl = getIconUrl(token.id, value.imageHost), + networks = token.networks.mapNotNull { network -> + val blockchain = Blockchain.fromNetworkId(network.networkId) ?: return@mapNotNull null + + Token.Network( + id = network.networkId, + blockchain = blockchain, + address = network.contractAddress, + iconUrl = getIconUrl(network.networkId, value.imageHost), + ) + }, + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt new file mode 100644 index 0000000000..6a3b684b51 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt @@ -0,0 +1,37 @@ +package com.tangem.tap.features.tokens.data.converters + +import com.tangem.blockchain.common.Blockchain +import com.tangem.datasource.local.testnet.models.TestnetTokensConfig +import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.tap.domain.tokens.getIconUrl +import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.utils.converter.Converter + +/** + * Converter from data model [TestnetTokensConfig] to list of domain models [Token] + * +[REDACTED_AUTHOR] + */ +internal object TestnetTokensConfigConverter : Converter> { + + override fun convert(value: TestnetTokensConfig): List { + return value.tokens.map { token -> + Token( + id = token.id, + name = token.name, + symbol = token.symbol, + iconUrl = getIconUrl(id = token.id, imageHost = null), + networks = token.networks?.mapNotNull { network -> + val blockchain = Blockchain.fromNetworkId(network.id) ?: return@mapNotNull null + + Token.Network( + id = network.id, + blockchain = blockchain, + address = network.address, + iconUrl = getIconUrl(id = network.id, imageHost = null), + ) + }.orEmpty(), + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt new file mode 100644 index 0000000000..e71a3a6531 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt @@ -0,0 +1,37 @@ +package com.tangem.tap.features.tokens.di + +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.local.testnet.TestnetTokensStorage +import com.tangem.tap.features.tokens.data.DefaultTokensListRepository +import com.tangem.tap.features.tokens.domain.TokensListRepository +import com.tangem.tap.proxy.AppStateHolder +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +/** +[REDACTED_AUTHOR] + */ +@Module +@InstallIn(SingletonComponent::class) +internal object TokensListRepositoryModule { + + @Provides + @Singleton + fun providesTokensListRepository( + tangemTechApi: TangemTechApi, + dispatchers: CoroutineDispatcherProvider, + reduxStateHolder: AppStateHolder, + testnetTokensStorage: TestnetTokensStorage, + ): TokensListRepository { + return DefaultTokensListRepository( + tangemTechApi = tangemTechApi, + dispatchers = dispatchers, + reduxStateHolder = reduxStateHolder, + testnetTokensStorage = testnetTokensStorage, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListRepository.kt b/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListRepository.kt new file mode 100644 index 0000000000..95fdde59ff --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListRepository.kt @@ -0,0 +1,20 @@ +package com.tangem.tap.features.tokens.domain + +import androidx.paging.PagingData +import com.tangem.tap.features.tokens.domain.models.Token +import kotlinx.coroutines.flow.Flow + +/** + * Repository of tokens list feature + * +[REDACTED_AUTHOR] + */ +internal interface TokensListRepository { + + /** + * Get available tokens list + * + * @param searchText search text + */ + fun getAvailableTokens(searchText: String?): Flow> +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt b/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt new file mode 100644 index 0000000000..d5724c314c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt @@ -0,0 +1,40 @@ +package com.tangem.tap.features.tokens.domain.models + +import com.tangem.blockchain.common.Blockchain + +/** + * Domain model of token for tokens list screen + * + * @property id token id + * @property name token name + * @property symbol token brief name. Example, "BTC" + * @property iconUrl token icon url + * @property networks token networks + * +[REDACTED_AUTHOR] + */ +internal data class Token( + val id: String, + val name: String, + val symbol: String, + val iconUrl: String, + val networks: List, +) { + + /** + * Domain model of network for tokens list screen + * + * @property id network id + * @property blockchain blockchain + * @property address address. If address equals null, it means it is the main network of token + * @property iconUrl network icon url + * +[REDACTED_AUTHOR] + */ + data class Network( + val id: String, + val blockchain: Blockchain, + val address: String?, + val iconUrl: String, + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt index 612a51e449..78cfc5ac9e 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt @@ -13,10 +13,7 @@ sealed class TokensAction : Action { data class AllowToAddTokens(val allow: Boolean) : TokensAction() - data class LoadCurrencies( - val supportedBlockchains: List? = null, - val scanResponse: ScanResponse? = null, - ) : TokensAction() { + data class LoadCurrencies(val scanResponse: ScanResponse? = null) : TokensAction() { data class Success(val currencies: List, val loadMore: Boolean) : TokensAction() object Failure : TokensAction() } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index 305df3393e..9b3be6dca7 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -76,11 +76,8 @@ class TokensMiddleware { private fun handleLoadCurrencies(scanResponse: ScanResponse?, newSearchInput: String? = null) { val tokensState = store.state.tokensState - val isTestcard = scanResponse?.card?.isTestCard ?: false - - val supportedBlockchains: List = - scanResponse?.card?.supportedBlockchains() ?: Blockchain.values().toList() - .filter { !it.isTestnet() } + val supportedBlockchains: List = scanResponse?.card?.supportedBlockchains() + ?: Blockchain.values().toList().filterNot(Blockchain::isTestnet) val loadCoinsService = LoadAvailableCoinsService( tangemTechApi = store.state.domainNetworks.tangemTechService.api, @@ -89,34 +86,26 @@ class TokensMiddleware { ) scope.launch { - val loadCoinsResult = if (newSearchInput == null) { - loadCoinsService.getSupportedTokens( - isTestcard, - supportedBlockchains, - tokensState.pageToLoad, - tokensState.searchInput, - ) - } else { - loadCoinsService.getSupportedTokens( - isTestNet = isTestcard, - supportedBlockchains = supportedBlockchains, - page = 0, - searchInput = newSearchInput.ifBlank { null }, - ) - } - when (loadCoinsResult) { - is Result.Success -> { - val currencies = loadCoinsResult.data.currencies - .filter(supportedBlockchains.toSet()) - store.dispatchOnMain( + val result = loadCoinsService.getSupportedTokens( + isTestNet = scanResponse?.card?.isTestCard ?: false, + supportedBlockchains = supportedBlockchains, + page = if (newSearchInput == null) tokensState.pageToLoad else 0, + searchInput = if (newSearchInput == null) tokensState.searchInput else newSearchInput.ifBlank { null }, + ) + + store.dispatchOnMain( + action = when (result) { + is Result.Success -> { TokensAction.LoadCurrencies.Success( - currencies, - loadCoinsResult.data.moreAvailable, - ), - ) - } - is Result.Failure -> store.dispatchOnMain(TokensAction.LoadCurrencies.Failure) - } + currencies = result.data.currencies.filter(supportedBlockchains.toSet()), + loadMore = result.data.moreAvailable, + ) + } + is Result.Failure -> { + TokensAction.LoadCurrencies.Failure + } + }, + ) } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt index e8ab2383d8..c792805d9b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt @@ -37,7 +37,6 @@ private fun internalReduce(action: Action, state: AppState): TokensState { addedBlockchains = action.wallets.toNonCustomBlockchains(action.derivationStyle), addedTokens = action.wallets.toNonCustomTokensWithBlockchains(action.derivationStyle), addedWallets = action.wallets, - derivationStyle = action.derivationStyle, ) } is TokensAction.AllowToAddTokens -> { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt index 5c4f723467..3cb59514c8 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt @@ -18,7 +18,6 @@ data class TokensState( val currencies: List = emptyList(), val searchInput: String? = null, val allowToAdd: Boolean = true, - val derivationStyle: DerivationStyle? = null, val scanResponse: ScanResponse? = null, val needToLoadMore: Boolean = true, val pageToLoad: Int = 0, @@ -67,19 +66,19 @@ data class TokenWithBlockchain( fun List.filter(supportedBlockchains: Set?): List { if (supportedBlockchains == null) return this - return map { - it.copy( - contracts = - it.contracts.filter { - supportedBlockchains.contains(it.blockchain) && - (it.blockchain.canHandleTokens() || it.address == null) + + return map { currency -> + currency.copy( + contracts = currency.contracts.filter { contract -> + supportedBlockchains.contains(contract.blockchain) && + (contract.blockchain.canHandleTokens() || contract.address == null) }, ) - }.filterNot { - it.contracts.isNullOrEmpty() && !supportedBlockchains.contains(Blockchain.fromNetworkId(it.id)) + }.filterNot { currency -> + currency.contracts.isEmpty() && !supportedBlockchains.contains(Blockchain.fromNetworkId(currency.id)) } } enum class LoadCoinsState { - LOADING, LOADED, ERROR + LOADING, LOADED, } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index fd920555a0..d735ef9615 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -6,7 +6,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.badoo.mvicore.modelWatcher import com.tangem.core.analytics.Analytics import com.tangem.domain.common.TapWorkarounds.derivationStyle -import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.analytics.events.Portfolio @@ -15,7 +14,6 @@ import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.domain.tokens.CurrenciesRepository import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.redux.WalletAction @@ -110,15 +108,7 @@ class MultiWalletView : WalletView() { binding.btnAddToken.setOnClickListener { val card = store.state.globalState.scanResponse!!.card Analytics.send(Portfolio.ButtonManageTokens()) - store.dispatch( - TokensAction.LoadCurrencies( - supportedBlockchains = CurrenciesRepository.getBlockchains( - card.firmwareVersion, - card.isTestCard, - ), - scanResponse = store.state.globalState.scanResponse, - ), - ) + store.dispatch(TokensAction.LoadCurrencies(scanResponse = store.state.globalState.scanResponse)) store.dispatch(TokensAction.AllowToAddTokens(true)) store.dispatch( TokensAction.SetAddedCurrencies( diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index c39054104a..940a09f956 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -17,6 +17,7 @@ androidxConstraintLayout = "2.1.4" androidxCore = "1.9.0" androidxFragment = "1.5.3" androidxLifecycle = "2.5.1" +androidx-paging = "3.1.1" # endregion AndroidX # region Compose @@ -27,6 +28,7 @@ compose-material = "1.3.1" compose-constraint = "1.0.1" compose-navigation = "2.5.3" compose-accompanist = "0.28.0" +compose-paging = "1.0.0-alpha18" # endregion Compose # region Other libraries @@ -116,6 +118,7 @@ androidx-browser = { module = "androidx.browser:browser", version.ref = "android androidx-constraintLayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidxConstraintLayout" } androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" } androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "androidxFragment" } +androidx-paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "androidx-paging" } lifecycle-common-java8 = { module = "androidx.lifecycle:lifecycle-common-java8", version.ref = "androidxLifecycle" } lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidxLifecycle" } lifecycle-viewModel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidxLifecycle" } @@ -135,6 +138,7 @@ compose-navigation-hilt = { module = "androidx.hilt:hilt-navigation-compose", ve compose-accompanist-appCompatTheme = { module = "com.google.accompanist:accompanist-appcompat-theme", version.ref = "compose-accompanist" } compose-accompanist-systemUiController = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "compose-accompanist" } compose-accompanist-webView = { module = "com.google.accompanist:accompanist-webview", version.ref = "compose-accompanist" } +compose-paging = { module = "androidx.paging:paging-compose", version.ref = "compose-paging" } # endregion Compose # region Firebase From 55e30c880b4b7a2a248bf475e6ac1b7dd5572f1f Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 11 Apr 2023 19:35:22 +0300 Subject: [PATCH 07/30] Updated on 2026-08-14 --- .../send/redux/reducers/TransactionExtrasReducer.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt index 7f918d72b3..a62a6e361e 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt @@ -145,11 +145,7 @@ class TransactionExtrasReducer : SendInternalReducer { return updateLastState(sendState.copy(transactionExtrasState = result), result) } - private fun handleTonMemo( - action: TonMemo, - sendState: SendState, - infoState: TransactionExtrasState, - ): SendState { + private fun handleTonMemo(action: TonMemo, sendState: SendState, infoState: TransactionExtrasState): SendState { val result = when (action) { is TonMemo.HandleUserInput -> { val memo = action.data From cb5f018d2ad749ccb74250d45bb5810ebe2104cb Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 12 Apr 2023 16:33:33 +0900 Subject: [PATCH 08/30] Updated on 2026-08-14 --- .../data/converters/CoinsResponseConverter.kt | 1 + .../TestnetTokensConfigConverter.kt | 1 + .../tokens/di/TokensListInteractorModule.kt | 40 +++++++++++++++++++ .../tokens/di/TokensListRepositoryModule.kt | 37 ----------------- ...terModule.kt => TokensListRouterModule.kt} | 8 ++-- .../domain/DefaultTokensListInteractor.kt | 17 ++++++++ .../tokens/domain/TokensListInteractor.kt | 16 ++++++++ .../features/tokens/domain/models/Token.kt | 10 +++-- ...nsRouter.kt => DefaultTokensListRouter.kt} | 7 +--- ...AddTokensRouter.kt => TokensListRouter.kt} | 4 +- .../viewmodels/TokensListViewModel.kt | 4 +- 11 files changed, 91 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/di/TokensListInteractorModule.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt rename app/src/main/java/com/tangem/tap/features/tokens/di/{AddTokensRouterModule.kt => TokensListRouterModule.kt} (64%) create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/domain/DefaultTokensListInteractor.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt rename app/src/main/java/com/tangem/tap/features/tokens/presentation/router/{DefaultAddTokensRouter.kt => DefaultTokensListRouter.kt} (65%) rename app/src/main/java/com/tangem/tap/features/tokens/presentation/router/{AddTokensRouter.kt => TokensListRouter.kt} (73%) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt index 9fa6492d80..d8b9477c16 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt @@ -29,6 +29,7 @@ internal object CoinsResponseConverter : Converter> { blockchain = blockchain, address = network.contractAddress, iconUrl = getIconUrl(network.networkId, value.imageHost), + decimalCount = network.decimalCount?.toInt(), ) }, ) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt index 6a3b684b51..b010b81704 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt @@ -29,6 +29,7 @@ internal object TestnetTokensConfigConverter : Converter> { + return repository.getAvailableTokens(searchText = searchText.ifBlank(defaultValue = { null })) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt b/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt new file mode 100644 index 0000000000..1fab924630 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt @@ -0,0 +1,16 @@ +package com.tangem.tap.features.tokens.domain + +import androidx.paging.PagingData +import com.tangem.tap.features.tokens.domain.models.Token +import kotlinx.coroutines.flow.Flow + +/** + * Interactor of tokens list feature + * +[REDACTED_AUTHOR] + */ +internal interface TokensListInteractor { + + /** Get tokens list using filter by text [searchText] */ + fun getTokensList(searchText: String): Flow> +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt b/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt index d5724c314c..750dfc94f5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt @@ -24,10 +24,11 @@ internal data class Token( /** * Domain model of network for tokens list screen * - * @property id network id - * @property blockchain blockchain - * @property address address. If address equals null, it means it is the main network of token - * @property iconUrl network icon url + * @property id network id + * @property blockchain blockchain + * @property address address. If address equals null, it means it is the main network of token + * @property iconUrl network icon url + * @property decimalCount decimal count * [REDACTED_AUTHOR] */ @@ -36,5 +37,6 @@ internal data class Token( val blockchain: Blockchain, val address: String?, val iconUrl: String, + val decimalCount: Int?, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultAddTokensRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt similarity index 65% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultAddTokensRouter.kt rename to app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt index c2543a86cb..a016e91a00 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultAddTokensRouter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt @@ -1,17 +1,15 @@ package com.tangem.tap.features.tokens.presentation.router -import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.store /** - * Router implementation for add tokens feature + * Default implementation of tokens list router * [REDACTED_AUTHOR] */ -internal class DefaultAddTokensRouter : AddTokensRouter { +internal class DefaultTokensListRouter : TokensListRouter { override fun popBackStack() { store.dispatch(NavigationAction.PopBackTo()) @@ -19,7 +17,6 @@ internal class DefaultAddTokensRouter : AddTokensRouter { } override fun openAddCustomTokenScreen() { - Analytics.send(ManageTokens.ButtonCustomToken()) store.dispatch(TokensAction.PrepareAndNavigateToAddCustomToken) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/AddTokensRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt similarity index 73% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/router/AddTokensRouter.kt rename to app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt index c0a4d91316..1ed3a068dc 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/AddTokensRouter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt @@ -1,7 +1,7 @@ package com.tangem.tap.features.tokens.presentation.router -/** Add tokens feature router */ -internal interface AddTokensRouter { +/** Tokens list feature router */ +internal interface TokensListRouter { /** Return to last screen */ fun popBackStack() diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt index 1b7c1fc3c0..a56973ee89 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt @@ -24,7 +24,7 @@ import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.tokens.Contract import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.tokens.presentation.router.AddTokensRouter +import com.tangem.tap.features.tokens.presentation.router.TokensListRouter import com.tangem.tap.features.tokens.presentation.states.NetworkItemState import com.tangem.tap.features.tokens.presentation.states.TokenItemState import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder @@ -55,7 +55,7 @@ import javax.inject.Inject */ @HiltViewModel internal class TokensListViewModel @Inject constructor( - private val router: AddTokensRouter, + private val router: TokensListRouter, private val dispatchers: AppCoroutineDispatcherProvider, ) : ViewModel() { From e38ac4b0b8b9659ba79f136e697b82dc8f5ee39a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 12 Apr 2023 14:01:15 +0500 Subject: [PATCH 09/30] Updated on 2026-08-14 --- app/src/main/assets/testnet_tokens.json | 11 +++++++++++ .../com/tangem/tap/common/extensions/Blockchain.kt | 1 + app/src/main/res/drawable/ic_kava_no_color.xml | 13 +++++++++++++ .../tangem/core/ui/extensions/BlockchainIcons.kt | 2 ++ core/ui/src/main/res/drawable/img_kava_22.xml | 13 +++++++++++++ .../tangem/domain/common/extensions/Blockchain.kt | 5 +++++ gradle/dependencies.toml | 2 +- 7 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/ic_kava_no_color.xml create mode 100644 core/ui/src/main/res/drawable/img_kava_22.xml diff --git a/app/src/main/assets/testnet_tokens.json b/app/src/main/assets/testnet_tokens.json index 8b227fde97..1e44bd5dfd 100644 --- a/app/src/main/assets/testnet_tokens.json +++ b/app/src/main/assets/testnet_tokens.json @@ -462,6 +462,17 @@ "networkId": "optimistic-ethereum/test" } ] + }, + { + "id": "kava", + "symbol": "KAVA", + "name": "Kava EVM", + "networks": + [ + { + "networkId": "kava/test" + } + ] } ] } diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt index e99dcef57b..c8b2e0e8d2 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt @@ -38,6 +38,7 @@ fun Blockchain.getGreyedOutIconRes(): Int { Blockchain.Dash -> R.drawable.ic_dash_no_color Blockchain.Kaspa -> R.drawable.ic_kaspa_no_color Blockchain.TON, Blockchain.TONTestnet -> R.drawable.ic_ton_no_color + Blockchain.Kava, Blockchain.KavaTestnet -> R.drawable.ic_kava_no_color else -> R.drawable.ic_tangem_logo } } diff --git a/app/src/main/res/drawable/ic_kava_no_color.xml b/app/src/main/res/drawable/ic_kava_no_color.xml new file mode 100644 index 0000000000..d48b77cede --- /dev/null +++ b/app/src/main/res/drawable/ic_kava_no_color.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt index 9c11cb37dc..0a834aa773 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt @@ -34,6 +34,7 @@ fun getActiveIconRes(blockchainId: String): Int { "DASH" -> R.drawable.img_dash_22 "KAS" -> R.drawable.img_kaspa_22 "The-Open-Network", "The-Open-Network/test" -> R.drawable.img_ton_22 + "KAVA", "KAVA/test" -> R.drawable.img_kava_22 else -> R.drawable.ic_alert_24 } } @@ -74,6 +75,7 @@ fun getActiveIconResByCoinId(coinId: String, networkId: String): Int { "dash" -> R.drawable.img_dash_22 "kaspa" -> R.drawable.img_kaspa_22 "ton" -> R.drawable.img_ton_22 + "kava"-> R.drawable.img_kava_22 else -> R.drawable.ic_alert_24 } } \ No newline at end of file diff --git a/core/ui/src/main/res/drawable/img_kava_22.xml b/core/ui/src/main/res/drawable/img_kava_22.xml new file mode 100644 index 0000000000..1e84002918 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_kava_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/domain/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt b/domain/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt index 88d48c6e29..40bb83cc64 100644 --- a/domain/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt +++ b/domain/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt @@ -52,6 +52,8 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? { "kaspa" -> Blockchain.Kaspa "the-open-network" -> Blockchain.TON "the-open-network/test" -> Blockchain.TONTestnet + "kava" -> Blockchain.Kava + "kava/test" -> Blockchain.KavaTestnet else -> null } } @@ -108,6 +110,8 @@ fun Blockchain.toNetworkId(): String { Blockchain.Kaspa -> "kaspa" Blockchain.TON -> "the-open-network" Blockchain.TONTestnet -> "the-open-network/test" + Blockchain.Kava -> "kava" + Blockchain.KavaTestnet -> "kava/test" } } @@ -144,6 +148,7 @@ fun Blockchain.toCoinId(): String { Blockchain.Kaspa -> "kaspa" Blockchain.TON, Blockchain.TONTestnet -> "the-open-network" Blockchain.Unknown -> "unknown" + Blockchain.Kava, Blockchain.KavaTestnet -> "kava" } } diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index f6c1447110..b9e4b097a9 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -71,7 +71,7 @@ kotlinSerialization = "1.4.1" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-189" +tangemBlockchainSdk = "develop-190" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-209" # tangemCardSdk = "0.0.1" # Keep it! - used for local builds From e0107e215c74a3de8f13aa1486779fffb0a02e0a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 12 Apr 2023 14:14:54 +0300 Subject: [PATCH 10/30] Updated on 2026-08-14 --- .../main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt | 2 +- gradle/dependencies.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt index 0a834aa773..2c13836580 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt @@ -75,7 +75,7 @@ fun getActiveIconResByCoinId(coinId: String, networkId: String): Int { "dash" -> R.drawable.img_dash_22 "kaspa" -> R.drawable.img_kaspa_22 "ton" -> R.drawable.img_ton_22 - "kava"-> R.drawable.img_kava_22 + "kava" -> R.drawable.img_kava_22 else -> R.drawable.ic_alert_24 } } \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index b9e4b097a9..cf36dd1b1f 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -71,7 +71,7 @@ kotlinSerialization = "1.4.1" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-190" +tangemBlockchainSdk = "develop-193" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-209" # tangemCardSdk = "0.0.1" # Keep it! - used for local builds From e1aee494ef71358507ee162b746eeab28d331db2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 11 Apr 2023 11:42:09 +0300 Subject: [PATCH 11/30] Updated on 2026-08-14 --- .../tap/domain/model/WalletDataModel.kt | 18 +++++++++++-- .../tap/domain/model/WalletStoreModel.kt | 1 + .../model/builders/WalletStoreBuilder.kt | 24 ++++++++++++++--- .../domain/walletStores/WalletStoresError.kt | 15 ++++------- .../walletStores/WalletStoresManager.kt | 9 +++++++ .../DefaultWalletStoresManager.kt | 17 ++++++++++++ .../DummyWalletStoresManager.kt | 10 +++++++ .../repository/WalletStoresRepository.kt | 14 ++++++++++ .../DefaultWalletStoresRepository.kt | 19 +++++++++++++ .../utils/WalletDataOperations.kt | 27 ++++++++++++++++++- .../utils/WalletStoreOperations.kt | 8 ++++++ .../wallet/redux/middlewares/Mapper.kt | 12 ++++++--- .../redux/middlewares/WalletMiddleware.kt | 20 ++++++++++++++ .../wallet/redux/reducers/WalletReducer.kt | 16 ----------- 14 files changed, 174 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt b/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt index 5f2e67153b..fe751acee5 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt @@ -1,10 +1,11 @@ package com.tangem.tap.domain.model import com.tangem.blockchain.common.TransactionData +import com.tangem.blockchain.common.address.AddressType +import com.tangem.tap.domain.model.WalletDataModel.AddressData import com.tangem.tap.domain.model.WalletDataModel.Status import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction -import com.tangem.tap.features.wallet.redux.AddressData import java.math.BigDecimal /** @@ -21,7 +22,8 @@ import java.math.BigDecimal data class WalletDataModel( val currency: Currency, val status: Status, - val walletAddresses: List, + // FIXME: Left only selected wallet address here and move list of wallet addresses to WalletStoreModel + val walletAddresses: WalletAddresses?, val existentialDeposit: BigDecimal?, val fiatRate: BigDecimal?, val isCardSingleToken: Boolean, @@ -29,6 +31,18 @@ data class WalletDataModel( val historyTransactions: List?, ) { + data class WalletAddresses( + val selectedAddress: AddressData, + val list: List, + ) + + data class AddressData( + val address: String, + val type: AddressType, + val shareUrl: String, + val exploreUrl: String, + ) + /** * Represent current status of currency * @property amount Currency amount diff --git a/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt b/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt index 7bca1028c0..01da397e3c 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt @@ -9,6 +9,7 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency import java.math.BigDecimal +// FIXME: Move list of wallet addresses from WalletDataModel to this class /** * Contains info about the blockchain and its currencies * diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index 921e8ccc3e..ebc45e991e 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -4,6 +4,7 @@ import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle import com.tangem.blockchain.common.Token +import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.common.WalletManager import com.tangem.common.hdWallet.DerivationPath import com.tangem.domain.common.TapWorkarounds.derivationStyle @@ -107,7 +108,7 @@ private fun BlockchainNetwork.getBlockchainWalletData( return WalletDataModel( currency = currency, status = WalletDataModel.Loading, - walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), + walletAddresses = walletManager?.wallet?.getWalletAddresses(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = false, @@ -131,7 +132,7 @@ private fun BlockchainNetwork.getTokensWalletsData( WalletDataModel( currency = currency, status = WalletDataModel.Loading, - walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), + walletAddresses = walletManager?.wallet?.getWalletAddresses(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = token == primaryToken, @@ -149,7 +150,7 @@ private fun Blockchain.toBlockchainWalletData(walletManager: WalletManager): Wal derivationPath = wallet.publicKey.derivationPath?.rawPath, ), status = WalletDataModel.Loading, - walletAddresses = wallet.createAddressesData(), + walletAddresses = wallet.getWalletAddresses(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = false, @@ -167,7 +168,7 @@ private fun Token.toTokenWalletData(walletManager: WalletManager, primaryToken: derivationPath = wallet.publicKey.derivationPath?.rawPath, ), status = WalletDataModel.Loading, - walletAddresses = wallet.createAddressesData(), + walletAddresses = wallet.getWalletAddresses(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = this == primaryToken, @@ -178,4 +179,19 @@ private fun Token.toTokenWalletData(walletManager: WalletManager, primaryToken: private fun getExistentialDeposit(walletManager: WalletManager?): BigDecimal? { return (walletManager as? ExistentialDepositProvider)?.getExistentialDeposit() +} + +private fun Wallet.getWalletAddresses(): WalletDataModel.WalletAddresses? { + return this.createAddressesData() + .takeIf { it.isNotEmpty() } + ?.map { + // TODO: Will be removed in next MR + with(it) { WalletDataModel.AddressData(address, type, shareUrl, exploreUrl) } + } + ?.let { addresses -> + WalletDataModel.WalletAddresses( + list = addresses, + selectedAddress = addresses.first(), + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresError.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresError.kt index 20fe0b0848..32097cfcdf 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresError.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresError.kt @@ -11,34 +11,29 @@ sealed class WalletStoresError(code: Int) : TangemError(code) { override val message: String? get() = customMessage - @Suppress("MagicNumber") class FetchFiatRatesError( currencies: List, override val cause: Throwable?, - ) : WalletStoresError(60011) { + ) : WalletStoresError(code = 60011) { override var customMessage: String = "Failed to fetch fiat rates for currencies $currencies" } - @Suppress("MagicNumber") - class UnknownBlockchain : WalletStoresError(60012) { + class UnknownBlockchain : WalletStoresError(code = 60012) { override var customMessage: String = "Unknown blockchain" } - @Suppress("MagicNumber") - object NoInternetConnection : WalletStoresError(60013) { + object NoInternetConnection : WalletStoresError(code = 60013) { override var customMessage: String = "No internet connection" } - @Suppress("MagicNumber") - class WalletManagerNotCreated(blockchain: Blockchain) : WalletStoresError(60014) { + class WalletManagerNotCreated(blockchain: Blockchain) : WalletStoresError(code = 60014) { override var customMessage: String = "Wallet manager can not be created for $blockchain" } - @Suppress("MagicNumber") class UpdateWalletManagerTokensError( blockchain: Blockchain, override val cause: Throwable, - ) : WalletStoresError(600015) { + ) : WalletStoresError(code = 600015) { override var customMessage: String = "Unable to update wallet manager tokens for currency $blockchain: $cause" } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt index 503bfe5cc0..867e75e174 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt @@ -1,9 +1,11 @@ package com.tangem.tap.domain.walletStores +import com.tangem.blockchain.common.address.AddressType import com.tangem.common.CompletionResult import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletStoreModel +import com.tangem.tap.features.wallet.models.Currency import kotlinx.coroutines.flow.Flow interface WalletStoresManager { @@ -22,6 +24,7 @@ interface WalletStoresManager { * @return [Flow] with [WalletStoreModel] list * */ fun get(userWalletId: UserWalletId): Flow> + suspend fun getSync(userWalletId: UserWalletId): List /** @@ -71,6 +74,12 @@ interface WalletStoresManager { * */ suspend fun updateAmounts(userWallets: List): CompletionResult + suspend fun updateSelectedAddress( + userWalletId: UserWalletId, + currency: Currency, + addressType: AddressType, + ): CompletionResult + // For provider companion object } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt index e6abbc56c7..6081a25788 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt @@ -1,6 +1,7 @@ package com.tangem.tap.domain.walletStores.implementation import com.tangem.blockchain.common.WalletManager +import com.tangem.blockchain.common.address.AddressType import com.tangem.common.CompletionResult import com.tangem.common.doOnSuccess import com.tangem.common.flatMap @@ -18,6 +19,7 @@ import com.tangem.tap.domain.walletStores.WalletStoresManager import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository +import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateSelectedAddress import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.toBlockchainNetworks import kotlinx.coroutines.Dispatchers @@ -103,6 +105,21 @@ internal class DefaultWalletStoresManager( } } + override suspend fun updateSelectedAddress( + userWalletId: UserWalletId, + currency: Currency, + addressType: AddressType, + ): CompletionResult { + return walletStoresRepository.update(userWalletId) { walletStores -> + walletStores + .firstOrNull { + it.blockchain == currency.blockchain && + it.derivationPath?.rawPath == currency.derivationPath + } + ?.updateSelectedAddress(currency, addressType) + } + } + private suspend fun fetchWalletsIfNeeded(userWallet: UserWallet): CompletionResult { return if (userWallet.isMultiCurrency) { fetchMultiWallets(userWallet) diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DummyWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DummyWalletStoresManager.kt index 7657f2d47b..98fa34d296 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DummyWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DummyWalletStoresManager.kt @@ -1,10 +1,12 @@ package com.tangem.tap.domain.walletStores.implementation +import com.tangem.blockchain.common.address.AddressType import com.tangem.common.CompletionResult import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.walletStores.WalletStoresManager +import com.tangem.tap.features.wallet.models.Currency import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow @@ -40,4 +42,12 @@ internal class DummyWalletStoresManager : WalletStoresManager { override suspend fun updateAmounts(userWallets: List): CompletionResult { return CompletionResult.Success(Unit) } + + override suspend fun updateSelectedAddress( + userWalletId: UserWalletId, + currency: Currency, + addressType: AddressType, + ): CompletionResult { + return CompletionResult.Success(Unit) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletStoresRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletStoresRepository.kt index 8359759a0a..ad80694e1e 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletStoresRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletStoresRepository.kt @@ -24,5 +24,19 @@ interface WalletStoresRepository { suspend fun storeOrUpdate(userWalletId: UserWalletId, walletStore: WalletStoreModel): CompletionResult + /** + * Updates [WalletStoreModel] in storage for user wallet with provided [UserWalletId] + * + * @param userWalletId [UserWalletId] of user wallet + * @param operation Lambda which receives list of [WalletStoreModel] assigned to user wallet with [userWalletId] + * and returns updated [WalletStoreModel]. If null returned then do nothing + * + * @return [CompletionResult] of operation + * */ + suspend fun update( + userWalletId: UserWalletId, + operation: (List) -> WalletStoreModel?, + ): CompletionResult + companion object } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletStoresRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletStoresRepository.kt index dba9881976..89997208ba 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletStoresRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletStoresRepository.kt @@ -69,6 +69,25 @@ internal class DefaultWalletStoresRepository : WalletStoresRepository { } } + override suspend fun update( + userWalletId: UserWalletId, + operation: (List) -> WalletStoreModel?, + ): CompletionResult = catching { + val walletStores = getSync(userWalletId).toMutableList() + val updatedWalletStore = operation(walletStores) ?: return CompletionResult.Success(Unit) + + val index = walletStores.indexOfFirst { it.isSameWalletStore(updatedWalletStore) } + if (index == -1 || updatedWalletStore == walletStores[index]) return CompletionResult.Success(Unit) + + walletStores[index] = updatedWalletStore + + walletStoresStorage.update { prevStores -> + prevStores.apply { + this[userWalletId] = walletStores + } + } + } + private suspend fun HashMap>.addOrUpdate( userWalletId: UserWalletId, walletStore: WalletStoreModel, diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt index 849aad6056..a522228976 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt @@ -3,6 +3,7 @@ package com.tangem.tap.domain.walletStores.repository.implementation.utils import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.common.address.AddressType import com.tangem.common.core.TangemError import com.tangem.tap.common.extensions.getBlockchainTxHistory import com.tangem.tap.common.extensions.getTokenTxHistory @@ -155,7 +156,6 @@ internal fun WalletDataModel.updateWithSelf(newWalletData: WalletDataModel): Wal is WalletDataModel.VerifiedOnline, -> newStatus }, - walletAddresses = newWalletData.walletAddresses, existentialDeposit = newWalletData.existentialDeposit, fiatRate = newWalletData.fiatRate ?: oldWalletData.fiatRate, ) @@ -193,6 +193,31 @@ internal fun List.updateWithSelf(newWalletsData: List.updateSelectedAddress( + currency: Currency, + addressType: AddressType, +): List { + val index = this.indexOfFirst { it.currency == currency } + if (index == -1) return this + + val oldWalletData = this[index] + val addresses = oldWalletData.walletAddresses + ?: return this + val selectedAddress = addresses.list + .firstOrNull { it.type == addressType } + ?: addresses.selectedAddress + val updatedWalletData = oldWalletData.copy( + walletAddresses = addresses.copy( + selectedAddress = selectedAddress, + ), + ) + if (oldWalletData == updatedWalletData) return this + + return this.toMutableList().apply { + this[index] = updatedWalletData + } +} + internal fun WalletDataModel.isSameWalletData(other: WalletDataModel): Boolean { return this.currency == other.currency } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt index f77470a6f0..627c5f93d3 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt @@ -1,9 +1,11 @@ package com.tangem.tap.domain.walletStores.repository.implementation.utils import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.common.address.AddressType import com.tangem.common.core.TangemError import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.domain.model.WalletStoreModel +import com.tangem.tap.features.wallet.models.Currency import timber.log.Timber internal inline fun HashMap>.replaceWalletStore( @@ -91,6 +93,12 @@ internal fun WalletStoreModel.updateWithRent(rent: WalletStoreModel.WalletRent?) ) } +internal fun WalletStoreModel.updateSelectedAddress(currency: Currency, addressType: AddressType): WalletStoreModel { + return this.copy( + walletsData = walletsData.updateSelectedAddress(currency, addressType), + ) +} + private inline fun List.replaceWalletStores( walletStoresToUpdate: List, update: (walletStore: WalletStoreModel) -> WalletStoreModel, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt index 84bb0f1212..cd9ac58574 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt @@ -11,6 +11,7 @@ import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.models.WalletRent +import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAddresses import com.tangem.tap.features.wallet.redux.WalletData @@ -76,10 +77,15 @@ private fun WalletDataModel.mapToReduxModel( return WalletData( currency = currency, - walletAddresses = walletAddresses.getOrNull(0)?.let { selectedAddress -> + // TODO: Will be updated in next MR + walletAddresses = walletAddresses?.let { addresses -> WalletAddresses( - selectedAddress = selectedAddress, - list = walletAddresses, + selectedAddress = with(addresses.selectedAddress) { + AddressData(address, type, shareUrl, exploreUrl) + }, + list = addresses.list.map { + with(it) { AddressData(address, type, shareUrl, exploreUrl) } + }, ) }, existentialDepositString = existentialDeposit?.toPlainString(), diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 2c4ad663cb..7893c448c5 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -3,6 +3,7 @@ package com.tangem.tap.features.wallet.redux.middlewares import com.google.firebase.crashlytics.FirebaseCrashlytics import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.address.AddressType import com.tangem.common.CompletionResult import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics @@ -42,6 +43,7 @@ import com.tangem.tap.store import com.tangem.tap.tangemSdkManager import com.tangem.tap.totalFiatBalanceCalculator import com.tangem.tap.userWalletsListManager +import com.tangem.tap.walletStoresManager import com.tangem.utils.coroutines.ifActive import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers @@ -204,6 +206,24 @@ class WalletMiddleware { store.dispatchOnMain(NavigationAction.PopBackTo(screen)) } + is WalletAction.ChangeSelectedAddress -> { + changeSelectedWalletAddress(action.type, walletState) + } + } + } + + private fun changeSelectedWalletAddress(type: AddressType, state: WalletState) { + val selectedUserWalletId = userWalletsListManager.selectedUserWalletSync?.walletId.guard { + Timber.e("Unable to change selected wallet address, no user wallet selected") + return + } + val selectedCurrency = state.selectedCurrency.guard { + Timber.e("Unable to change selected wallet address, no currency selected") + return + } + + scope.launch(Dispatchers.Default) { + walletStoresManager.updateSelectedAddress(selectedUserWalletId, selectedCurrency, type) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index d95339a75b..49c0035b5a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -13,7 +13,6 @@ import com.tangem.tap.features.wallet.redux.Artwork import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.redux.WalletAddresses import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.WalletStore @@ -102,21 +101,6 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS ) } is WalletAction.TradeCryptoAction -> return newState - is WalletAction.ChangeSelectedAddress -> { - val walletAddresses = newState.getWalletData(newState.selectedCurrency)?.walletAddresses - ?: return newState - val address = walletAddresses.list.firstOrNull { it.type == action.type } - ?: return newState - - newState = newState.updateWalletData( - newState.selectedWalletData?.copy( - walletAddresses = WalletAddresses( - selectedAddress = address, - list = walletAddresses.list, - ), - ), - ) - } is WalletAction.AppCurrencyAction -> { newState = appCurrencyReducer.reduce(action, newState) } From a2b3c22e5338b4cd7fb921be47ba5fb946e287bb Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 11 Apr 2023 12:42:05 +0300 Subject: [PATCH 12/30] Updated on 2026-08-14 --- .../common/analytics/topup/TopUpController.kt | 6 +- .../tap/common/extensions/WalletManager.kt | 10 +- .../tangem/tap/common/redux/StateDialog.kt | 4 +- .../model/builders/WalletStoreBuilder.kt | 4 - .../AddressInfoBottomSheetDialog.kt | 7 +- .../send/redux/reducers/ReceiptReducer.kt | 4 +- .../stateSubscribers/SendStateSubscriber.kt | 4 +- .../tap/features/tokens/redux/TokensAction.kt | 4 +- .../tap/features/tokens/redux/TokensState.kt | 20 +-- .../features/wallet/models/WalletWarning.kt | 4 +- .../tap/features/wallet/redux/WalletAction.kt | 12 +- .../tap/features/wallet/redux/WalletData.kt | 3 +- .../tap/features/wallet/redux/WalletState.kt | 125 ++++-------------- .../wallet/redux/middlewares/Mapper.kt | 2 +- .../redux/middlewares/WalletMiddleware.kt | 38 +----- .../wallet/redux/reducers/WalletReducer.kt | 57 ++------ .../features/wallet/redux/utils/Constants.kt | 5 + 17 files changed, 85 insertions(+), 224 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/redux/utils/Constants.kt diff --git a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt index 42d9e80686..2435646fed 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt @@ -9,6 +9,7 @@ import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.common.analytics.converters.TopUpEventConverter import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.extensions.copy +import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel @@ -17,7 +18,6 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager import com.tangem.tap.domain.walletStores.WalletStoresManager import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.persistence.ToppedUpWalletStorage import com.tangem.tap.scope import kotlinx.coroutines.launch @@ -60,8 +60,8 @@ class TopUpController( hadMissedDerivations = blockchains.isNotEmpty() } - fun totalBalanceStateChanged(state: ProgressState) { - if (state == ProgressState.Done) tryToSend() + fun totalBalanceStateChanged(totalFiatBalance: TotalFiatBalance) { + if (totalFiatBalance is TotalFiatBalance.Loaded) tryToSend() } fun loadDataSuccess() { diff --git a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt index 0930704d50..925cb0c728 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt @@ -12,9 +12,8 @@ import com.tangem.tap.common.TestActions import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.amountToCreateAccount import com.tangem.tap.domain.getFirstToken +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.demo.isDemoCard -import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.reducers.createAddressesData import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager import com.tangem.tap.proxy.redux.DaggerGraphState @@ -81,7 +80,7 @@ fun WalletManager.getTopUpUrl(): String? { ) } -fun WalletManager?.getAddressData(): AddressData? { +fun WalletManager?.getAddressData(): WalletDataModel.AddressData? { val wallet = this?.wallet ?: return null val addressDataList = wallet.createAddressesData() @@ -100,11 +99,6 @@ fun WalletManager.Companion.stub(): T { } as T } -fun Wallet.getTxHistory(currency: Currency): List { - return (currency as? Currency.Token)?.let { this.getTokenTxHistory(it.token) } - ?: getBlockchainTxHistory() -} - fun Wallet.getBlockchainTxHistory(): List { return historyTransactions.filter { it.contractAddress.isNullOrEmpty() diff --git a/app/src/main/java/com/tangem/tap/common/redux/StateDialog.kt b/app/src/main/java/com/tangem/tap/common/redux/StateDialog.kt index e216493dd6..ab957b81b1 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/StateDialog.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/StateDialog.kt @@ -2,8 +2,8 @@ package com.tangem.tap.common.redux import com.tangem.common.extensions.VoidCallback import com.tangem.tap.common.TestAction +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.redux.AddressData /** [REDACTED_AUTHOR] @@ -24,7 +24,7 @@ sealed class AppDialog : StateDialog { data class AddressInfoDialog( val currency: Currency, - val addressData: AddressData, + val addressData: WalletDataModel.AddressData, ) : AppDialog() data class TestActionsDialog( diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index ebc45e991e..65405fa242 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -184,10 +184,6 @@ private fun getExistentialDeposit(walletManager: WalletManager?): BigDecimal? { private fun Wallet.getWalletAddresses(): WalletDataModel.WalletAddresses? { return this.createAddressesData() .takeIf { it.isNotEmpty() } - ?.map { - // TODO: Will be removed in next MR - with(it) { WalletDataModel.AddressData(address, type, shareUrl, exploreUrl) } - } ?.let { addresses -> WalletDataModel.WalletAddresses( list = addresses, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt index 66e30fe595..280ca66499 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt @@ -12,8 +12,9 @@ import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.extensions.dispatchShare import com.tangem.tap.common.extensions.dispatchToastNotification import com.tangem.tap.common.extensions.getString +import com.tangem.tap.common.extensions.toQrCode import com.tangem.tap.common.redux.AppDialog -import com.tangem.tap.features.wallet.redux.AddressData +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.store import com.tangem.wallet.R import com.tangem.wallet.databinding.DialogOnboardingAddressInfoBinding @@ -46,12 +47,12 @@ class AddressInfoBottomSheetDialog( showData(data = stateDialog.addressData) } - private fun showData(data: AddressData) = with(binding!!) { + private fun showData(data: WalletDataModel.AddressData) = with(binding!!) { pseudoToolbar.imvClose.setOnClickListener { dismissWithAnimation = true cancel() } - imvQrCode.setImageBitmap(data.qrCode) + imvQrCode.setImageBitmap(data.shareUrl.toQrCode()) tvAddress.text = data.address btnFlCopyAddress.setOnClickListener { Analytics.send(Token.Receive.ButtonCopyAddress()) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt index 3f403ea92c..ebfa2a391a 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt @@ -17,8 +17,8 @@ import com.tangem.tap.features.send.redux.states.ReceiptSymbols import com.tangem.tap.features.send.redux.states.ReceiptTokenCrypto import com.tangem.tap.features.send.redux.states.ReceiptTokenFiat import com.tangem.tap.features.send.redux.states.SendState -import com.tangem.tap.features.wallet.redux.WalletState.Companion.CAN_BE_LOWER_SIGN -import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN +import com.tangem.tap.features.wallet.redux.utils.CAN_BE_LOWER_SIGN +import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN import com.tangem.tap.store import java.math.BigDecimal diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index e250ad075e..6e2bf1f5e9 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -38,8 +38,8 @@ import com.tangem.tap.features.send.ui.dialogs.RequestFeeErrorDialog import com.tangem.tap.features.send.ui.dialogs.SendTransactionFailsDialog import com.tangem.tap.features.send.ui.dialogs.TezosWarningDialog import com.tangem.tap.features.wallet.redux.ProgressState -import com.tangem.tap.features.wallet.redux.WalletState.Companion.ROUGH_SIGN -import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN +import com.tangem.tap.features.wallet.redux.utils.ROUGH_SIGN +import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter import com.tangem.wallet.R diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt index 78cfc5ac9e..0c87bc313a 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt @@ -3,8 +3,8 @@ package com.tangem.tap.features.tokens.redux import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle import com.tangem.domain.common.ScanResponse +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.wallet.redux.WalletData import org.rekotlin.Action sealed class TokensAction : Action { @@ -23,7 +23,7 @@ sealed class TokensAction : Action { ) : TokensAction() data class SetAddedCurrencies( - val wallets: List, + val wallets: List, val derivationStyle: DerivationStyle?, ) : TokensAction() diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt index 3cb59514c8..8015b9d1d5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt @@ -6,13 +6,13 @@ import com.tangem.blockchain.common.Token import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.extensions.canHandleToken import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.wallet.redux.WalletData import org.rekotlin.StateType import com.tangem.tap.features.wallet.models.Currency.Token as CurrencyToken data class TokensState( - val addedWallets: List = emptyList(), + val addedWallets: List = emptyList(), val addedTokens: List = emptyList(), val addedBlockchains: List = emptyList(), val currencies: List = emptyList(), @@ -31,17 +31,9 @@ data class TokensState( typealias ContractAddress = String -fun List.toTokensContractAddresses(): List { - return mapNotNull { (it.currency as? CurrencyToken)?.token?.contractAddress }.distinct() -} - -fun List.toNonCustomTokens(derivationStyle: DerivationStyle?): List { - return filter { !it.currency.isCustomCurrency(derivationStyle) } - .mapNotNull { (it.currency as? CurrencyToken)?.token } - .distinct() -} - -fun List.toNonCustomTokensWithBlockchains(derivationStyle: DerivationStyle?): List { +fun List.toNonCustomTokensWithBlockchains( + derivationStyle: DerivationStyle?, +): List { return mapNotNull { if (it.currency !is CurrencyToken) return@mapNotNull null if (it.currency.isCustomCurrency(derivationStyle)) return@mapNotNull null @@ -49,7 +41,7 @@ fun List.toNonCustomTokensWithBlockchains(derivationStyle: Derivatio }.distinct() } -fun List.toNonCustomBlockchains(derivationStyle: DerivationStyle?): List { +fun List.toNonCustomBlockchains(derivationStyle: DerivationStyle?): List { return mapNotNull { if (it.currency.isCustomCurrency(derivationStyle)) { null diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt index 951d4f1e10..421bfa85fe 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt @@ -1,5 +1,7 @@ package com.tangem.tap.features.wallet.models +import com.tangem.tap.domain.model.WalletStoreModel + sealed class WalletWarning(val showingPosition: Int) { data class ExistentialDeposit( @@ -15,7 +17,7 @@ sealed class WalletWarning(val showingPosition: Int) { val blockchainSymbol: String, ) : WalletWarning(showingPosition = 30) - data class Rent(val walletRent: WalletRent) : WalletWarning(showingPosition = 40) + data class Rent(val walletRent: WalletStoreModel.WalletRent) : WalletWarning(showingPosition = 40) } data class WalletWarningDescription(val title: String, val message: String) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index 390b337f30..c026cc9e0f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -8,11 +8,12 @@ import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.domain.TapError import com.tangem.tap.domain.configurable.warningMessage.WarningMessage +import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.model.UserWallet +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.wallet.R import org.rekotlin.Action @@ -38,7 +39,6 @@ sealed class WalletAction : Action { data class RemoveWallet(val currency: Currency) : MultiWallet() object BackupWallet : MultiWallet() - object ScheduleCheckForMissingDerivation : MultiWallet() data class AddMissingDerivations(val blockchains: List) : MultiWallet() object ScanToGetDerivations : MultiWallet() } @@ -78,7 +78,7 @@ sealed class WalletAction : Action { sealed class DialogAction : WalletAction() { data class QrCode( val currency: Currency, - val selectedAddress: AddressData, + val selectedAddress: WalletDataModel.AddressData, ) : DialogAction() object SignedHashesMultiWalletDialog : DialogAction() @@ -127,9 +127,7 @@ sealed class WalletAction : Action { } data class UserWalletChanged(val userWallet: UserWallet) : WalletAction() - data class WalletStoresChanged(val walletStores: List) : WalletAction() { - data class UpdateWalletStores(val reduxWalletStores: List) : WalletAction() - } + data class WalletStoresChanged(val walletStores: List) : WalletAction() - data class TotalFiatBalanceChanged(val balance: TotalBalance) : WalletAction() + data class TotalFiatBalanceChanged(val balance: TotalFiatBalance) : WalletAction() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletData.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletData.kt index e4e5f8e78c..423306eec6 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletData.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletData.kt @@ -85,7 +85,8 @@ data class WalletData( walletWarnings.add(WalletWarning.TransactionInProgress(currency.currencyName)) } if (walletRent != null) { - walletWarnings.add(WalletWarning.Rent(walletRent)) + // TODO: Will be removed in next MR + // walletWarnings.add(WalletWarning.Rent(walletRent)) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index b55d54277d..6d4a5c788a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -9,29 +9,30 @@ import com.tangem.tap.common.extensions.toQrCode import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.common.toggleWidget.WidgetState import com.tangem.tap.domain.configurable.warningMessage.WarningMessage +import com.tangem.tap.domain.model.TotalFiatBalance +import com.tangem.tap.domain.model.UserWallet +import com.tangem.tap.domain.model.WalletDataModel +import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.models.TotalBalance -import com.tangem.tap.features.wallet.redux.reducers.findProgressState -import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.store import org.rekotlin.StateType import kotlin.properties.ReadOnlyProperty data class WalletState( - val cardId: String = "", + val userWallet: UserWallet? = null, val state: ProgressState = ProgressState.Done, val error: ErrorType? = null, val cardImage: Artwork? = null, val hashesCountVerified: Boolean? = null, val mainWarningsList: List = mutableListOf(), - val walletsStores: List = listOf(), + val walletsStores: List = listOf(), val isMultiwalletAllowed: Boolean = false, val cardCurrency: CryptoCurrencyName? = null, val selectedCurrency: Currency? = null, val isTestnet: Boolean = false, - val totalBalance: TotalBalance? = null, + val totalBalance: TotalFiatBalance? = null, val showBackupWarning: Boolean = false, val missingDerivations: List = emptyList(), val loadingUserTokens: Boolean = false, @@ -39,10 +40,10 @@ data class WalletState( val canSaveUserWallets: Boolean = false, ) : StateType { - val walletsDataFromStores: List - get() = walletsStores.map { it.walletsData }.flatten() + val walletsDataFromStores: List + get() = walletsStores.flatMap { it.walletsData } - val selectedWalletData: WalletData? + val selectedWalletData: WalletDataModel? get() = walletsDataFromStores.firstOrNull { it.currency == selectedCurrency } // if you do not delegate - the application crashes on startup, @@ -66,7 +67,7 @@ data class WalletState( val walletManagers: List get() = walletsStores.mapNotNull { it.walletManager } - private val primaryWalletStore: WalletStore? + private val primaryWalletStore: WalletStoreModel? get() = if (isMultiwalletAllowed || walletsStores.isEmpty() || walletsStores.size > 1) { null } else { @@ -76,17 +77,15 @@ data class WalletState( val primaryWalletManager: WalletManager? get() = primaryWalletStore?.walletManager - val primaryWalletData: WalletData? - get() = primaryWalletStore?.walletsData?.firstOrNull() + val primaryWalletData: WalletDataModel? + get() = primaryWalletStore?.blockchainWalletData - val primaryTokenData: WalletData? - get() = primaryWalletStore?.walletsData?.toMutableList() - ?.apply { remove(primaryWalletData) } - ?.firstOrNull() + val primaryTokenData: WalletDataModel? + get() = primaryWalletStore?.walletsData + ?.firstOrNull { it.currency !is Currency.Blockchain } val shouldShowDetails: Boolean = - primaryWalletData?.currencyData?.status != BalanceStatus.EmptyCard && - primaryWalletData?.currencyData?.status != BalanceStatus.UnknownBlockchain + primaryWalletData?.status !is WalletDataModel.Unreachable fun getWalletManager(currency: Currency?): WalletManager? { if (currency?.blockchain == null) return null @@ -94,95 +93,27 @@ data class WalletState( } fun getWalletManager(blockchain: BlockchainNetwork): WalletManager? { - return walletsStores.find { it.blockchainNetwork == blockchain }?.walletManager + return walletsStores.firstOrNull { + it.blockchain == blockchain.blockchain && + it.derivationPath?.rawPath == blockchain.derivationPath + }?.walletManager } - fun getWalletData(blockchain: BlockchainNetwork?): WalletData? { - if (blockchain == null) return null - return walletsDataFromStores.find { - it.currency is Currency.Blockchain && - it.currency.blockchain == blockchain.blockchain && - it.currency.derivationPath == blockchain.derivationPath - } - } - - fun getWalletStore(currency: Currency?): WalletStore? { + fun getWalletStore(currency: Currency?): WalletStoreModel? { if (currency == null) return null return walletsStores.firstOrNull { - it.blockchainNetwork.derivationPath == currency.derivationPath && - it.blockchainNetwork.blockchain == currency.blockchain + it.blockchain == currency.blockchain && + it.derivationPath?.rawPath == currency.derivationPath } } - - private fun getWalletStore(blockchainNetwork: BlockchainNetwork?): WalletStore? { - if (blockchainNetwork == null) return null - return walletsStores.firstOrNull { - it.blockchainNetwork.derivationPath == blockchainNetwork.derivationPath && - it.blockchainNetwork.blockchain == blockchainNetwork.blockchain - } - } - - fun getWalletData(currency: Currency?): WalletData? { - if (currency == null) return null - return getWalletStore(currency)?.walletsData?.firstOrNull { it.currency == currency } - } - - fun updateWalletData(walletData: WalletData?): WalletState { - if (walletData == null) return this - return updateWalletsData(listOf(walletData)) - } - - private fun updateWalletsData(walletsData: List): WalletState { - val walletStores = walletsData - .map { BlockchainNetwork(it.currency.blockchain, it.currency.derivationPath, emptyList()) } - .distinct().map { getWalletStore(it) }.mapNotNull { it?.updateWallets(walletsData) } - - return updateWalletsStores(walletStores) - } - - private fun updateWalletsStores(walletStores: List): WalletState { - val walletStoresMutable = walletStores.toMutableList() - val updatedWallets = walletsStores.map { oldWalletStore -> - val walletStore = walletStoresMutable.find { - it.blockchainNetwork == oldWalletStore.blockchainNetwork - } - if (walletStore != null) { - walletStoresMutable.remove(walletStore) - walletStore - } else { - oldWalletStore - } - } - return copy(walletsStores = updatedWallets + walletStoresMutable) - .updateProgressState() - } - - private fun updateProgressState(): WalletState { - val walletsData = this.walletsStores - .flatMap(WalletStore::walletsData) - - return if (walletsData.isNotEmpty()) { - val newProgressState = walletsData.findProgressState() - - this.copy( - state = walletsData.findProgressState(), - error = this.error.takeIf { newProgressState == ProgressState.Error }, - ) - } else { - this - } - } - - companion object { - const val UNKNOWN_AMOUNT_SIGN = "—" - const val ROUGH_SIGN = "≈" - const val CAN_BE_LOWER_SIGN = "<" - } } enum class ProgressState : WidgetState { Loading, Refreshing, Done, Error } -enum class ErrorType { NoInternetConnection } +enum class ErrorType { + NoInternetConnection, + UnknownBlockchain, +} sealed class WalletMainButton(enabled: Boolean) : Button(enabled) { class SendButton(enabled: Boolean) : WalletMainButton(enabled) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt index cd9ac58574..e48f89ce52 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt @@ -77,7 +77,7 @@ private fun WalletDataModel.mapToReduxModel( return WalletData( currency = currency, - // TODO: Will be updated in next MR + // TODO: Will be updated in next MRs walletAddresses = walletAddresses?.let { addresses -> WalletAddresses( selectedAddress = with(addresses.selectedAddress) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 7893c448c5..404aa63a43 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -32,10 +32,7 @@ import com.tangem.tap.features.send.redux.PrepareSendScreen import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.getSendableAmounts import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletState -import com.tangem.tap.features.wallet.redux.WalletStore -import com.tangem.tap.features.wallet.redux.reducers.findSelectedCurrency import com.tangem.tap.preferencesStorage import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope @@ -106,7 +103,7 @@ class WalletMiddleware { scope.launch { when (val result = tangemSdkManager.createWallet(globalState.scanResponse?.card?.cardId)) { is CompletionResult.Success -> { - val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { + val selectedUserWallet = walletState.userWallet.guard { Timber.e("Unable to create wallet, no user wallet selected") return@launch } @@ -132,7 +129,7 @@ class WalletMiddleware { is WalletAction.LoadData, is WalletAction.LoadData.Refresh, -> { - val selectedWallet = userWalletsListManager.selectedUserWalletSync.guard { + val selectedWallet = walletState.userWallet.guard { Timber.e("Unable to load/refresh wallets data, no user wallet selected") return } @@ -188,7 +185,6 @@ class WalletMiddleware { is WalletAction.WalletStoresChanged -> { // Cancel update job when new wallet stores received updateWalletStoresJob = scope.launch(Dispatchers.Default) { - ifActive { updateWalletStores(action.walletStores, walletState) } ifActive { fetchTotalFiatBalance(action.walletStores) } ifActive { findMissedDerivations(action.walletStores) } ifActive { tryToShowAppRatingWarning(action.walletStores) } @@ -227,26 +223,8 @@ class WalletMiddleware { } } - private fun updateWalletStores(walletsStores: List, state: WalletState) { - val reduxWalletStores = walletsStores.mapToReduxModels() - if (!state.isMultiwalletAllowed) { - findSelectedCurrency( - walletsStores = reduxWalletStores, - currentSelectedCurrency = null, - isMultiWalletAllowed = false, - )?.let { - store.dispatchOnMain(WalletAction.MultiWallet.SetSingleWalletCurrency(it)) - } - } - store.dispatchOnMain( - WalletAction.WalletStoresChanged.UpdateWalletStores( - reduxWalletStores = reduxWalletStores, - ), - ) - } - private suspend fun fetchTotalFiatBalance(walletStores: List) { - val totalFiatBalance = totalFiatBalanceCalculator.calculateOrNull(walletStores)?.mapToReduxModel() + val totalFiatBalance = totalFiatBalanceCalculator.calculateOrNull(walletStores) if (totalFiatBalance != null) { store.dispatchOnMain(WalletAction.TotalFiatBalanceChanged(totalFiatBalance)) @@ -300,7 +278,7 @@ class WalletMiddleware { return if (amount != null) { if (amount.type is AmountType.Token) { - prepareSendActionForToken(amount, state, selectedWalletData, walletStore) + prepareSendActionForToken(amount, selectedWalletData, walletStore) } else { PrepareSendScreen(amount, selectedWalletData?.fiatRate, walletStore?.walletManager) } @@ -322,7 +300,6 @@ class WalletMiddleware { ?: return WalletAction.DialogAction.ChooseCurrency(amounts) prepareSendActionForToken( amount = amountToSend, - state = state, selectedWalletData = selectedWalletData, walletStore = walletStore, ) @@ -346,11 +323,10 @@ class WalletMiddleware { private fun prepareSendActionForToken( amount: Amount, - state: WalletState?, - selectedWalletData: WalletData?, - walletStore: WalletStore?, + selectedWalletData: WalletDataModel?, + walletStore: WalletStoreModel?, ): PrepareSendScreen { - val coinRate = state?.getWalletData(walletStore?.blockchainNetwork)?.fiatRate + val coinRate = walletStore?.blockchainWalletData?.fiatRate val tokenRate = selectedWalletData?.fiatRate val coinAmount = walletStore?.walletManager?.wallet?.amounts?.get(AmountType.Coin) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 49c0035b5a..b1d7fcfef0 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -1,23 +1,18 @@ package com.tangem.tap.features.wallet.redux.reducers -import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Wallet import com.tangem.domain.common.CardDTO import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.tokens.models.BlockchainNetwork +import com.tangem.tap.domain.model.WalletDataModel +import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.Artwork import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletState -import com.tangem.tap.features.wallet.redux.WalletStore -import com.tangem.tap.features.wallet.ui.BalanceStatus -import com.tangem.tap.features.wallet.ui.BalanceWidgetData import com.tangem.tap.proxy.AppStateHolder import org.rekotlin.Action @@ -41,44 +36,15 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS is WalletAction.LoadData.Failure -> { when (action.error) { is TapError.NoInternetConnection -> { - val wallets = newState.walletsStores - .map { store -> - store.copy( - walletsData = store.walletsData.map { - it.copy( - currencyData = it.currencyData.copy( - status = BalanceStatus.Unreachable, - ), - ) - }, - ) - } - newState = newState.copy( state = ProgressState.Error, error = ErrorType.NoInternetConnection, - walletsStores = wallets, ) } is TapError.UnknownBlockchain -> { newState = newState.copy( - state = ProgressState.Done, - walletsStores = listOf( - WalletStore( - walletManager = null, - blockchainNetwork = BlockchainNetwork( - Blockchain.Unknown, - null, - emptyList(), - ), - walletsData = listOf( - WalletData( - currencyData = BalanceWidgetData(BalanceStatus.UnknownBlockchain), - currency = Currency.Blockchain(Blockchain.Unknown, null), - ), - ), - ), - ), + state = ProgressState.Error, + error = ErrorType.UnknownBlockchain, ) } else -> { @@ -107,7 +73,7 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS is WalletAction.UserWalletChanged -> with(action.userWallet) { val card = scanResponse.card newState = WalletState( - cardId = card.cardId, + userWallet = this, isMultiwalletAllowed = isMultiCurrency, cardImage = Artwork( artworkId = artworkUrl, @@ -126,10 +92,9 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS }, ) } - is WalletAction.WalletStoresChanged.UpdateWalletStores -> { + is WalletAction.WalletStoresChanged -> { newState = newState.copy( - state = action.reduxWalletStores.flatMap { it.walletsData }.findProgressState(newState.state), - walletsStores = action.reduxWalletStores, + walletsStores = action.walletStores, ) } is WalletAction.TotalFiatBalanceChanged -> { @@ -159,7 +124,7 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS } fun findSelectedCurrency( - walletsStores: List, + walletsStores: List, currentSelectedCurrency: Currency?, isMultiWalletAllowed: Boolean, ): Currency? = if (isMultiWalletAllowed) { @@ -175,11 +140,11 @@ private fun CardDTO.findCardsCount(): Int? { return (this.backupStatus as? CardDTO.BackupStatus.Active)?.cardCount?.inc() } -fun Wallet.createAddressesData(): List { - val listOfAddressData = mutableListOf() +fun Wallet.createAddressesData(): List { + val listOfAddressData = mutableListOf() // put a defaultAddress at the first place addresses.forEach { - val addressData = AddressData( + val addressData = WalletDataModel.AddressData( it.value, it.type, getShareUri(it.value), diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/utils/Constants.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/utils/Constants.kt new file mode 100644 index 0000000000..dfab28f18a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/utils/Constants.kt @@ -0,0 +1,5 @@ +package com.tangem.tap.features.wallet.redux.utils + +const val UNKNOWN_AMOUNT_SIGN = "—" +const val ROUGH_SIGN = "≈" +const val CAN_BE_LOWER_SIGN = "<" \ No newline at end of file From 64e6a7609fba79c3a304a0d21b014604848ed481 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 11 Apr 2023 12:49:04 +0300 Subject: [PATCH 13/30] Updated on 2026-08-14 --- .../tap/features/wallet/ui/BalanceWidget.kt | 110 ++++++------- .../wallet/ui/WalletDetailsFragment.kt | 125 ++++++++------- .../tap/features/wallet/ui/WalletFragment.kt | 5 +- .../tap/features/wallet/ui/WalletViewModel.kt | 4 +- .../wallet/ui/WalletWarningConverter.kt | 4 +- .../wallet/ui/adapters/WalletAdapter.kt | 53 ++++--- .../analytics/WalletAnalyticsEventsMapper.kt | 27 ++-- .../wallet/ui/utils/WalletDataOperations.kt | 144 ++++++++++++++++++ .../wallet/ui/view/TotalBalanceCard.kt | 40 ++--- .../wallet/ui/view/WalletDetailsButtonsRow.kt | 2 +- .../wallet/ui/wallet/MultiWalletView.kt | 59 ++----- .../wallet/ui/wallet/SingleWalletView.kt | 27 ++-- .../ui/wallet/saltPay/SaltPayWalletView.kt | 12 +- .../tap/features/walletSelector/ui/Mapper.kt | 2 +- 14 files changed, 380 insertions(+), 234 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt index 0afeb7e3b0..3b8cac1392 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt @@ -3,6 +3,10 @@ package com.tangem.tap.features.wallet.ui import androidx.annotation.IdRes import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show +import com.tangem.tap.domain.model.WalletDataModel +import com.tangem.tap.features.wallet.ui.utils.getFormattedAmount +import com.tangem.tap.features.wallet.ui.utils.getFormattedFiatAmount +import com.tangem.tap.store import com.tangem.wallet.R import com.tangem.wallet.databinding.CardBalanceBinding import java.math.BigDecimal @@ -36,36 +40,37 @@ data class BalanceWidgetData( class BalanceWidget( private val binding: CardBalanceBinding, private val fragment: WalletFragment, - private val data: BalanceWidgetData, - private val token: BalanceWidgetData?, - private val isTwinCard: Boolean, + private val blockchainWalletData: WalletDataModel, + private val tokenWalletData: WalletDataModel?, ) { @Suppress("LongMethod", "ComplexMethod") fun setup() { - when (data.status) { - BalanceStatus.Loading -> { + when (blockchainWalletData.status) { + is WalletDataModel.Loading -> { with(binding) { lBalance.root.show() lBalanceError.root.hide() lBalance.tvFiatAmount.hide() - lBalance.tvCurrency.text = data.currency + lBalance.tvCurrency.text = blockchainWalletData.currency.currencyName lBalance.tvAmount.text = "" } showStatus(R.id.tv_status_loading) - if (token != null) { - showBalanceWithToken(data, false) + if (tokenWalletData != null) { + showBalanceWithToken(blockchainWalletData, false) } else { - showBalanceWithoutToken(data, false) + showBalanceWithoutToken(blockchainWalletData, false) } } - BalanceStatus.VerifiedOnline, BalanceStatus.TransactionInProgress -> with(binding.lBalance) { + is WalletDataModel.VerifiedOnline, + is WalletDataModel.TransactionInProgress, + -> with(binding.lBalance) { root.show() binding.lBalanceError.root.hide() - val statusView = if (data.status == BalanceStatus.VerifiedOnline) { + val statusView = if (blockchainWalletData.status is WalletDataModel.VerifiedOnline) { R.id.tv_status_verified } else { tvStatusError.text = @@ -75,61 +80,62 @@ class BalanceWidget( showStatus(statusView) tvStatusErrorMessage.hide() - if (token != null) { - showBalanceWithToken(data, true) + if (tokenWalletData != null) { + showBalanceWithToken(blockchainWalletData, true) } else { - showBalanceWithoutToken(data, true) + showBalanceWithoutToken(blockchainWalletData, true) } } - BalanceStatus.Unreachable -> with(binding.lBalance) { + is WalletDataModel.Unreachable -> with(binding.lBalance) { root.show() binding.lBalanceError.root.hide() tvFiatAmount.hide() groupBaseCurrency.hide() - val currency = if (token != null) token.currencySymbol else data.currency + val currency = tokenWalletData?.currency?.currencySymbol + ?: blockchainWalletData.currency.currencyName tvCurrency.text = currency tvAmount.text = "" - tvStatusErrorMessage.text = data.errorMessage + tvStatusErrorMessage.text = blockchainWalletData.status.errorMessage tvStatusError.text = fragment.getString(R.string.wallet_balance_blockchain_unreachable) showStatus(R.id.group_error) - tvStatusErrorMessage.show(!data.errorMessage.isNullOrBlank()) + tvStatusErrorMessage.show(!blockchainWalletData.status.errorMessage.isNullOrBlank()) } - BalanceStatus.EmptyCard -> with(binding.lBalanceError) { - binding.lBalance.root.hide() - binding.lBalanceError.root.show() - if (isTwinCard) { - tvErrorTitle.text = fragment.getText(R.string.wallet_error_empty_twin_card) - tvErrorDescriptions.text = - fragment.getText(R.string.wallet_error_empty_twin_card_subtitle) - } else { - tvErrorTitle.text = fragment.getText(R.string.wallet_error_empty_card) - tvErrorDescriptions.text = - fragment.getText(R.string.wallet_error_empty_card_subtitle) - } - } - BalanceStatus.NoAccount -> with(binding.lBalanceError) { + // BalanceStatus.EmptyCard -> with(binding.lBalanceError) { + // binding.lBalance.root.hide() + // binding.lBalanceError.root.show() + // if (isTwinCard) { + // tvErrorTitle.text = fragment.getText(R.string.wallet_error_empty_twin_card) + // tvErrorDescriptions.text = + // fragment.getText(R.string.wallet_error_empty_twin_card_subtitle) + // } else { + // tvErrorTitle.text = fragment.getText(R.string.wallet_error_empty_card) + // tvErrorDescriptions.text = + // fragment.getText(R.string.wallet_error_empty_card_subtitle) + // } + // } + is WalletDataModel.NoAccount -> with(binding.lBalanceError) { binding.lBalance.root.hide() binding.lBalanceError.root.show() tvErrorTitle.text = fragment.getText(R.string.wallet_error_no_account) tvErrorDescriptions.text = fragment.getString( R.string.no_account_generic, - data.amountToCreateAccount, - data.currencySymbol, + blockchainWalletData.status.amountToCreateAccount, + blockchainWalletData.currency.currencySymbol, ) } - BalanceStatus.UnknownBlockchain -> with(binding.lBalanceError) { - binding.lBalance.root.hide() - binding.lBalanceError.root.show() - tvErrorTitle.text = - fragment.getText(R.string.wallet_error_unsupported_blockchain) - tvErrorDescriptions.text = - fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle) - } + // BalanceStatus.UnknownBlockchain -> with(binding.lBalanceError) { + // binding.lBalance.root.hide() + // binding.lBalanceError.root.show() + // tvErrorTitle.text = + // fragment.getText(R.string.wallet_error_unsupported_blockchain) + // tvErrorDescriptions.text = + // fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle) + // } else -> {} } } @@ -140,25 +146,25 @@ class BalanceWidget( tvStatusVerified.show(viewRes == R.id.tv_status_verified) } - private fun showBalanceWithToken(data: BalanceWidgetData, showAmount: Boolean) = with(binding.lBalance) { + private fun showBalanceWithToken(data: WalletDataModel, showAmount: Boolean) = with(binding.lBalance) { groupBaseCurrency.show() - tvCurrency.text = token?.currencySymbol - tvBaseCurrency.text = data.currency - tvAmount.text = if (showAmount) token?.amountFormatted else "" - tvBaseAmount.text = if (showAmount) data.amountFormatted else "" + tvCurrency.text = tokenWalletData?.currency?.currencySymbol + tvBaseCurrency.text = data.currency.currencyName + tvAmount.text = if (showAmount) tokenWalletData?.getFormattedAmount() else "" + tvBaseAmount.text = if (showAmount) data.getFormattedAmount() else "" if (showAmount) { tvFiatAmount.show() - tvFiatAmount.text = token?.fiatAmountFormatted + tvFiatAmount.text = tokenWalletData?.getFormattedFiatAmount(store.state.globalState.appCurrency) } } - private fun showBalanceWithoutToken(data: BalanceWidgetData, showAmount: Boolean) = with(binding.lBalance) { + private fun showBalanceWithoutToken(data: WalletDataModel, showAmount: Boolean) = with(binding.lBalance) { groupBaseCurrency.hide() - tvCurrency.text = data.currency - tvAmount.text = if (showAmount) data.amountFormatted else "" + tvCurrency.text = data.currency.currencyName + tvAmount.text = if (showAmount) data.getFormattedAmount() else "" if (showAmount) { tvFiatAmount.show() - tvFiatAmount.text = data.fiatAmountFormatted + tvFiatAmount.text = data.getFormattedFiatAmount(store.state.globalState.appCurrency) } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index e070d1e5da..9952836ff9 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -41,21 +41,29 @@ import com.tangem.tap.common.extensions.show import com.tangem.tap.common.extensions.toQrCode import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction import com.tangem.tap.features.wallet.models.PendingTransactionType import com.tangem.tap.features.wallet.models.WalletWarning -import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletState -import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN +import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter import com.tangem.tap.features.wallet.ui.adapters.WalletDetailWarningMessagesAdapter import com.tangem.tap.features.wallet.ui.images.load import com.tangem.tap.features.wallet.ui.test.TestWallet +import com.tangem.tap.features.wallet.ui.utils.assembleWarnings +import com.tangem.tap.features.wallet.ui.utils.getAvailableActions +import com.tangem.tap.features.wallet.ui.utils.getFormattedAmount +import com.tangem.tap.features.wallet.ui.utils.getFormattedFiatAmount +import com.tangem.tap.features.wallet.ui.utils.isAvailableToBuy +import com.tangem.tap.features.wallet.ui.utils.isAvailableToSell +import com.tangem.tap.features.wallet.ui.utils.isAvailableToSwap +import com.tangem.tap.features.wallet.ui.utils.mainButton +import com.tangem.tap.features.wallet.ui.utils.shouldShowMultipleAddress import com.tangem.tap.store import com.tangem.tap.userWalletsListManagerSafe import com.tangem.tap.walletCurrenciesManager @@ -85,31 +93,19 @@ class WalletDetailsFragment : private val binding: FragmentWalletDetailsBinding by viewBinding(FragmentWalletDetailsBinding::bind) - private val walletDataWatcher: ModelWatcher = modelWatcher { - val addressCardStrategy: DiffStrategy = { old, new -> - old.currency != new.currency || - old.walletAddresses?.selectedAddress != new.walletAddresses?.selectedAddress || - old.shouldShowMultipleAddress() != new.shouldShowMultipleAddress() + private val walletDataWatcher: ModelWatcher = modelWatcher { + val addressCardStrategy: DiffStrategy = { old, new -> + old.currency != new.currency || old.walletAddresses != new.walletAddresses } - WalletData::pendingTransactions { - showPendingTransactionsIfPresent(it) - } - WalletData::currency { + WalletDataModel::currency { handleCurrencyIcon(it) } - WalletData::currencyData { - setupBalanceData(it) - } - WalletData::walletAddresses { walletAddresses -> + WalletDataModel::walletAddresses { walletAddresses -> setupCopyAndShareButtons(walletAddresses?.selectedAddress?.address) } - WalletData::assembleWarnings { warnings -> - handleWarnings(warnings) - } - (WalletData::currencyData or WalletData::currency) { walletData -> - setupCurrency(walletData.currencyData, walletData.currency) - setupSwipeRefresh(walletData.currencyData, walletData.currency) + WalletDataModel::currency { currency -> + setupCurrency(currency) } watch({ it }, addressCardStrategy) { walletData -> setupAddressCard( @@ -121,9 +117,28 @@ class WalletDetailsFragment : } private val walletStateWatcher: ModelWatcher = modelWatcher { - WalletState::selectedWalletData { selectedWallet -> + val walletDataStrategy: DiffStrategy = { old, new -> + new.walletsStores.isNotEmpty() && + new.selectedCurrency != null && + (old.selectedCurrency != new.selectedCurrency || old.walletsStores != new.walletsStores) + } + + watch({ it }, walletDataStrategy) { state -> + val selectedWallet = state.selectedWalletData if (selectedWallet != null) { + setupBalanceData(selectedWallet) + setupSwipeRefresh(selectedWallet) walletDataWatcher.invoke(selectedWallet) + + val walletStore = state.getWalletStore(state.selectedCurrency) + if (walletStore != null) { + handleWarnings( + selectedWallet.assembleWarnings( + blockchainAmount = walletStore.blockchainWalletData.status.amount, + blockchainWalletRent = walletStore.walletRent, + ), + ) + } } } (WalletState::selectedWalletData or WalletState::isExchangeServiceFeatureOn) { state -> @@ -234,8 +249,8 @@ class WalletDetailsFragment : ) } - private fun setupCurrency(currencyData: BalanceWidgetData, currency: Currency) = with(binding) { - tvCurrencyTitle.text = currencyData.currency + private fun setupCurrency(currency: Currency) = with(binding) { + tvCurrencyTitle.text = currency.currencyName if (currency is Currency.Token) { tvCurrencySubtitle.text = tvCurrencySubtitle.getString( @@ -248,16 +263,17 @@ class WalletDetailsFragment : } } - private fun setupSwipeRefresh(currencyData: BalanceWidgetData, currency: Currency) { + private fun setupSwipeRefresh(walletData: WalletDataModel) { binding.srlWalletDetails.setOnRefreshListener { - if (currencyData.status != BalanceStatus.Loading && currencyData.status != BalanceStatus.Refreshing) { + if (walletData.status !is WalletDataModel.Loading) { Analytics.send(Token.Refreshed()) + val selectedUserWallet = userWalletsListManagerSafe?.selectedUserWalletSync.guard { + Timber.e("Unable to refresh wallet details screen, no user wallet selected") + return@setOnRefreshListener + } + binding.srlWalletDetails.isRefreshing = true lifecycleScope.launch(Dispatchers.Default) { - val selectedUserWallet = userWalletsListManagerSafe?.selectedUserWalletSync.guard { - Timber.e("Unable to refresh wallet details screen, no user wallet selected") - return@launch - } - walletCurrenciesManager.update(selectedUserWallet, currency) + walletCurrenciesManager.update(selectedUserWallet, walletData.currency) .doOnResult { withMainContext { binding.srlWalletDetails.isRefreshing = false @@ -266,9 +282,6 @@ class WalletDetailsFragment : } } } - - binding.srlWalletDetails.isRefreshing = currencyData.status == BalanceStatus.Loading || - currencyData.status == BalanceStatus.Refreshing } private fun setupCopyAndShareButtons(walletAddress: String?) { @@ -284,7 +297,7 @@ class WalletDetailsFragment : } } - private fun setupButtonsRow(selectedWallet: WalletData, isExchangeServiceFeatureOn: Boolean) { + private fun setupButtonsRow(selectedWallet: WalletDataModel, isExchangeServiceFeatureOn: Boolean) { val exchangeManager = store.state.globalState.exchangeManager binding.rowButtons.apply { onBuyClick = { store.dispatch(WalletAction.TradeCryptoAction.Buy()) } @@ -340,7 +353,7 @@ class WalletDetailsFragment : private fun setupAddressCard( shouldShowMultipleAddress: Boolean, - selectedAddress: AddressData?, + selectedAddress: WalletDataModel.AddressData?, currency: Currency, ) = with(binding.lWalletDetails) { if (selectedAddress == null) return@with @@ -371,7 +384,7 @@ class WalletDetailsFragment : private fun setupAddressTypeChips( shouldShowMultipleAddress: Boolean, - selectedAddress: AddressData, + selectedAddress: WalletDataModel.AddressData, currency: Currency, ) = with(binding.lWalletDetails) { if (shouldShowMultipleAddress && currency is Currency.Blockchain) { @@ -408,54 +421,58 @@ class WalletDetailsFragment : } } - private fun setupBalanceData(data: BalanceWidgetData) = with(binding.lWalletDetails) { - when (data.status) { - BalanceStatus.Loading -> { + private fun setupBalanceData(walletData: WalletDataModel) = with(binding.lWalletDetails) { + when (val status = walletData.status) { + is WalletDataModel.Loading -> { lBalanceError.root.hide() lBalance.root.show() lBalance.groupBalance.show() lBalance.tvError.hide() - lBalance.tvAmount.text = data.amountFormatted - lBalance.tvFiatAmount.text = data.fiatAmountFormatted ?: UNKNOWN_AMOUNT_SIGN + lBalance.tvAmount.text = walletData.getFormattedAmount() + lBalance.tvFiatAmount.text = walletData.getFormattedFiatAmount(store.state.globalState.appCurrency) lBalance.tvStatus.setLoadingStatus(R.string.wallet_balance_loading) } - BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress, - BalanceStatus.TransactionInProgress, + is WalletDataModel.VerifiedOnline, + is WalletDataModel.SameCurrencyTransactionInProgress, + is WalletDataModel.TransactionInProgress, -> { lBalanceError.root.hide() lBalance.root.show() lBalance.groupBalance.show() lBalance.tvError.hide() - lBalance.tvAmount.text = data.amountFormatted - lBalance.tvFiatAmount.text = data.fiatAmountFormatted ?: UNKNOWN_AMOUNT_SIGN - when (data.status) { - BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress -> { + lBalance.tvAmount.text = walletData.getFormattedAmount() + lBalance.tvFiatAmount.text = walletData.getFormattedFiatAmount(store.state.globalState.appCurrency) + when (status) { + is WalletDataModel.VerifiedOnline, + is WalletDataModel.SameCurrencyTransactionInProgress, + -> { lBalance.tvStatus.setVerifiedBalanceStatus(R.string.wallet_balance_verified) } else -> { lBalance.tvStatus.setWarningStatus(R.string.wallet_balance_tx_in_progress) } } + showPendingTransactionsIfPresent(status.pendingTransactions) } - BalanceStatus.Unreachable -> { + is WalletDataModel.Unreachable -> { lBalanceError.root.hide() lBalance.root.show() lBalance.groupBalance.hide() lBalance.tvError.show() lBalance.tvError.setWarningStatus( R.string.wallet_balance_blockchain_unreachable, - data.errorMessage, + status.errorMessage, ) } - BalanceStatus.NoAccount -> { + is WalletDataModel.NoAccount -> { lBalance.root.hide() lBalanceError.root.show() lBalanceError.tvErrorTitle.text = getText(R.string.wallet_error_no_account) lBalanceError.tvErrorDescriptions.text = getString( R.string.no_account_generic, - data.amountToCreateAccount, - data.currencySymbol, + status.amountToCreateAccount, + walletData.currency.currencySymbol, ) } else -> {} diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 571653ff77..ca1149d987 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -68,7 +68,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber - totalBalance?.state?.let { + totalBalance?.let { viewModel.onBalanceLoaded(totalBalance) store.state.globalState.topUpController?.totalBalanceStateChanged(it) } @@ -159,8 +159,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber { + state.isMultiwalletAllowed && walletView !is MultiWalletView -> { walletView.onViewDestroy() walletView = MultiWalletView() walletView.changeWalletView(this, binding) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt index 2be9db11ee..bba9814685 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt @@ -9,8 +9,8 @@ import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.extensions.dispatchOnMain +import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.userWalletList.UserWalletsListManager -import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.ui.analytics.WalletAnalyticsEventsMapper import com.tangem.tap.store @@ -88,7 +88,7 @@ internal class WalletViewModel @Inject constructor( bootstrapShowSaveWalletIfNeeded() } - fun onBalanceLoaded(totalBalance: TotalBalance?) { + fun onBalanceLoaded(totalBalance: TotalFiatBalance?) { if (totalBalance != null) { walletAnalyticsEventsMapper.convert(totalBalance)?.let { balanceParam -> analyticsEventHandler.send( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt index 8e9e9c6219..afbf3bff5a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt @@ -41,8 +41,8 @@ class WalletWarningConverter( is WalletWarning.Rent -> { context.getString( R.string.solana_rent_warning, - message.walletRent.minRentValue, - message.walletRent.rentExemptValue, + message.walletRent.rent, + message.walletRent.exemptionAmount, ) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt index 98f4fbecee..cbb32572e7 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt @@ -12,18 +12,20 @@ import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.redux.WalletData -import com.tangem.tap.features.wallet.ui.BalanceStatus +import com.tangem.tap.features.wallet.ui.utils.getFormattedAmount +import com.tangem.tap.features.wallet.ui.utils.getFormattedFiatAmount +import com.tangem.tap.features.wallet.ui.utils.getFormattedFiatRate import com.tangem.tap.features.wallet.ui.images.load import com.tangem.tap.store import com.tangem.wallet.R import com.tangem.wallet.databinding.ItemCurrencyWalletBinding -class WalletAdapter : ListAdapter(DiffUtilCallback) { +class WalletAdapter : ListAdapter(DiffUtilCallback) { override fun getItemId(position: Int): Long { - return currentList[position].currencyData.currencySymbol?.hashCode()?.toLong() ?: 0 + return currentList[position].currency.currencySymbol.hashCode().toLong() } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WalletsViewHolder { @@ -39,34 +41,33 @@ class WalletAdapter : ListAdapter(D holder.bind(currentList[position]) } - object DiffUtilCallback : DiffUtil.ItemCallback() { - override fun areContentsTheSame(oldItem: WalletData, newItem: WalletData) = oldItem == newItem + object DiffUtilCallback : DiffUtil.ItemCallback() { + override fun areContentsTheSame(oldItem: WalletDataModel, newItem: WalletDataModel) = oldItem == newItem - override fun areItemsTheSame(oldItem: WalletData, newItem: WalletData) = oldItem == newItem + override fun areItemsTheSame(oldItem: WalletDataModel, newItem: WalletDataModel) = oldItem == newItem } class WalletsViewHolder(val binding: ItemCurrencyWalletBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(wallet: WalletData) = with(binding) { - val status = wallet.currencyData.status - // Skip changes when on refreshing status - if (status == BalanceStatus.Refreshing) return@with + fun bind(wallet: WalletDataModel) = with(binding) { + val status = wallet.status + val fiatCurrency = store.state.globalState.appCurrency val statusMessage = when (status) { - BalanceStatus.TransactionInProgress -> { + is WalletDataModel.TransactionInProgress -> { root.getString(R.string.wallet_balance_tx_in_progress) } - BalanceStatus.Unreachable -> { + is WalletDataModel.Unreachable -> { root.getString(R.string.wallet_balance_blockchain_unreachable) } - BalanceStatus.MissedDerivation -> { + is WalletDataModel.MissedDerivation -> { root.getString(R.string.wallet_balance_missing_derivation) } else -> null } - if (status == null || status == BalanceStatus.Loading) { + if (status is WalletDataModel.Loading) { lContent.root.hide() lShimmer.root.veil() } else { @@ -82,24 +83,22 @@ class WalletAdapter : ListAdapter(D ?.derivationStyle, ) - lContent.tvCurrency.text = wallet.currencyData.currency - lContent.tvAmountFiat.text = wallet.currencyData.fiatAmountFormatted ?: "—" - lContent.tvAmount.text = wallet.currencyData.amountFormatted ?: "—" + lContent.tvCurrency.text = wallet.currency.currencyName + lContent.tvAmountFiat.text = wallet.getFormattedFiatAmount(fiatCurrency) + lContent.tvAmount.text = wallet.getFormattedAmount() lContent.tvStatus.isVisible = statusMessage != null lContent.tvStatus.text = statusMessage lContent.tvExchangeRate.isVisible = statusMessage == null - lContent.tvExchangeRate.text = wallet.fiatRateString - ?: root.getString(id = R.string.token_item_no_rate) + lContent.tvExchangeRate.text = wallet.getFormattedFiatRate( + fiatCurrency = fiatCurrency, + noRateValue = root.getString(id = R.string.token_item_no_rate), + ) - if (wallet.walletAddresses != null) { - cardWallet.setOnClickListener { - Analytics.send(Portfolio.TokenTapped()) - store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet.currency)) - } - } else { - cardWallet.setOnClickListener(null) + cardWallet.setOnClickListener { + Analytics.send(Portfolio.TokenTapped()) + store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet.currency)) } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/analytics/WalletAnalyticsEventsMapper.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/analytics/WalletAnalyticsEventsMapper.kt index 6c750a5368..277ce8471c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/analytics/WalletAnalyticsEventsMapper.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/analytics/WalletAnalyticsEventsMapper.kt @@ -2,22 +2,16 @@ package com.tangem.tap.features.wallet.ui.analytics import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.extensions.isGreaterThan -import com.tangem.tap.features.wallet.models.TotalBalance -import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.utils.converter.Converter import java.math.BigDecimal -class WalletAnalyticsEventsMapper : Converter { +class WalletAnalyticsEventsMapper : Converter { - override fun convert(value: TotalBalance): AnalyticsParam.CardBalanceState? { - return when (value.state) { - ProgressState.Done -> if (value.fiatAmount?.isGreaterThan(BigDecimal.ZERO) == true) { - AnalyticsParam.CardBalanceState.Full - } else { - AnalyticsParam.CardBalanceState.Empty - } - ProgressState.Error -> { - if (value.fiatAmount == null) { + override fun convert(value: TotalFiatBalance): AnalyticsParam.CardBalanceState? { + return when (value) { + is TotalFiatBalance.Error -> { + if (value.amount == null) { // if fiatAmount is null while ProgressState.Error it means error occurs when loading blockchain AnalyticsParam.CardBalanceState.BlockchainError } else { @@ -25,7 +19,14 @@ class WalletAnalyticsEventsMapper : Converter null + is TotalFiatBalance.Loaded -> { + if (value.amount.isGreaterThan(BigDecimal.ZERO)) { + AnalyticsParam.CardBalanceState.Full + } else { + AnalyticsParam.CardBalanceState.Empty + } + } + is TotalFiatBalance.Loading -> null } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt new file mode 100644 index 0000000000..6b08921a5d --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt @@ -0,0 +1,144 @@ +package com.tangem.tap.features.wallet.ui.utils + +import com.tangem.blockchain.common.Blockchain +import com.tangem.common.extensions.isZero +import com.tangem.domain.common.extensions.toNetworkId +import com.tangem.feature.swap.api.SwapFeatureToggleManager +import com.tangem.feature.swap.domain.SwapInteractor +import com.tangem.tap.common.entities.FiatCurrency +import com.tangem.tap.common.extensions.toFiatRateString +import com.tangem.tap.common.extensions.toFiatValue +import com.tangem.tap.common.extensions.toFormattedCurrencyString +import com.tangem.tap.common.extensions.toFormattedFiatValue +import com.tangem.tap.domain.model.WalletDataModel +import com.tangem.tap.domain.model.WalletStoreModel +import com.tangem.tap.features.wallet.models.WalletWarning +import com.tangem.tap.features.wallet.redux.WalletMainButton +import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN +import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager +import java.math.BigDecimal + +internal val WalletDataModel.mainButton: WalletMainButton + get() = WalletMainButton.SendButton( + enabled = !status.amount.isZero() && status.pendingTransactions.isEmpty(), + ) + +internal fun WalletDataModel.getFormattedAmount(): String { + return status.amount.toFormattedCurrencyString( + decimals = currency.decimals, + currency = currency.currencySymbol, + ) +} + +internal fun WalletDataModel.getFormattedFiatAmount( + fiatCurrency: FiatCurrency, + unknownAmountSign: String = UNKNOWN_AMOUNT_SIGN, +): String { + return this.fiatRate?.let { status.amount.toFiatValue(it) } + ?.takeIf { !status.isErrorStatus } + ?.toFormattedFiatValue(fiatCurrency.symbol) + ?: unknownAmountSign +} + +internal fun WalletDataModel.getFormattedFiatRate(fiatCurrency: FiatCurrency, noRateValue: String): String { + return fiatRate?.toFiatRateString(fiatCurrency.symbol) + ?: noRateValue +} + +internal fun WalletDataModel.isAvailableToBuy(exchangeManager: CurrencyExchangeManager): Boolean { + return exchangeManager.availableForBuy(currency) +} + +internal fun WalletDataModel.isAvailableToSell(exchangeManager: CurrencyExchangeManager): Boolean { + return exchangeManager.availableForSell(currency) +} + +internal fun WalletDataModel.isAvailableToSwap( + swapFeatureToggleManager: SwapFeatureToggleManager, + swapInteractor: SwapInteractor, +): Boolean { + if (currency.blockchain.id == Blockchain.Optimism.id && !swapFeatureToggleManager.isOptimismSwapEnabled) { + return false + } + return swapInteractor.isAvailableToSwap(currency.blockchain.toNetworkId()) && + !currency.isCustomCurrency(null) +} + +internal fun WalletDataModel.getAvailableActions( + swapInteractor: SwapInteractor, + exchangeManager: CurrencyExchangeManager, + swapFeatureToggleManager: SwapFeatureToggleManager, +): Set { + return setOfNotNull( + if (isAvailableToBuy(exchangeManager)) CurrencyAction.Buy else null, + if (isAvailableToSell(exchangeManager)) CurrencyAction.Sell else null, + if (isAvailableToSwap(swapFeatureToggleManager, swapInteractor)) CurrencyAction.Swap else null, + ) +} + +internal fun WalletDataModel.shouldShowMultipleAddress(): Boolean { + val listOfAddresses = walletAddresses?.list.orEmpty() + return listOfAddresses.size > 1 +} + +internal fun WalletDataModel.assembleWarnings( + blockchainAmount: BigDecimal, + blockchainWalletRent: WalletStoreModel.WalletRent?, +): List { + val walletWarnings = mutableListOf() + assembleNonTypedWarnings(walletWarnings, blockchainWalletRent) + assembleBlockchainWarnings(walletWarnings) + assembleTokenWarnings(walletWarnings, blockchainAmount) + + return walletWarnings.sortedBy { it.showingPosition } +} + +private fun WalletDataModel.assembleNonTypedWarnings( + walletWarnings: MutableList, + walletRent: WalletStoreModel.WalletRent?, +) { + if (this.status is WalletDataModel.SameCurrencyTransactionInProgress) { + walletWarnings.add(WalletWarning.TransactionInProgress(currency.currencyName)) + } + if (walletRent != null) { + walletWarnings.add(WalletWarning.Rent(walletRent)) + } +} + +private fun WalletDataModel.assembleBlockchainWarnings(walletWarnings: MutableList) { + with(currency) { + if (!isBlockchain()) return + + if (existentialDeposit != null) { + val warning = WalletWarning.ExistentialDeposit( + currencyName = currencyName, + edStringValueWithSymbol = "${existentialDeposit.toPlainString()} $currencySymbol", + ) + walletWarnings.add(warning) + } + } +} + +private fun WalletDataModel.assembleTokenWarnings( + walletWarnings: MutableList, + blockchainAmount: BigDecimal, +) { + if (!currency.isToken()) return + + if (!this.isEmptyAmount && blockchainAmount.isZero()) { + walletWarnings.add( + WalletWarning.BalanceNotEnoughForFee( + currencyName = currency.currencyName, + blockchainFullName = currency.blockchain.fullName, + blockchainSymbol = currency.blockchain.currency, + ), + ) + } +} + +private val WalletDataModel.isEmptyAmount: Boolean + get() = this.status.amount.isZero() + +enum class CurrencyAction { + Buy, Sell, Swap +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt index 4efe5659b4..4eab1313a5 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt @@ -35,9 +35,8 @@ import com.tangem.core.ui.components.SpacerW4 import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.formatWithSpaces -import com.tangem.tap.features.wallet.models.TotalBalance -import com.tangem.tap.features.wallet.redux.ProgressState -import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN +import com.tangem.tap.domain.model.TotalFiatBalance +import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN import com.tangem.wallet.R import com.valentinilk.shimmer.shimmer import java.math.BigDecimal @@ -52,18 +51,25 @@ internal class TotalBalanceCard @JvmOverloads constructor( ) : AbstractComposeView(context, attrs, defStyleAttr) { private var state by mutableStateOf(TotalBalanceCardState.Empty) - var status: TotalBalance? = null + var status: TotalFiatBalance? = null set(value) { if (field == value) return field = value - updateState(value, onChangeFiatCurrencyClick) + updateState(value, fiatCurrency, onChangeFiatCurrencyClick) } var onChangeFiatCurrencyClick: () -> Unit = { /* no-op */ } set(value) { if (field == value) return field = value - updateState(status, value) + updateState(status, fiatCurrency, value) + } + + var fiatCurrency: FiatCurrency = FiatCurrency.Default + set(value) { + if (field == value) return + field = value + updateState(status, value, onChangeFiatCurrencyClick) } @Composable @@ -77,23 +83,21 @@ internal class TotalBalanceCard @JvmOverloads constructor( return javaClass.name } - private fun updateState(status: TotalBalance?, onChangeCurrencyClick: () -> Unit) { - state = when (status?.state) { + private fun updateState(status: TotalFiatBalance?, fiatCurrency: FiatCurrency, onChangeCurrencyClick: () -> Unit) { + state = when (status) { null -> TotalBalanceCardState.Empty - ProgressState.Loading -> TotalBalanceCardState.Loading( - fiatCurrency = status.fiatCurrency, + is TotalFiatBalance.Error -> TotalBalanceCardState.Failure( + amount = status.amount, + fiatCurrency = fiatCurrency, onChangeFiatCurrencyClick = onChangeCurrencyClick, ) - ProgressState.Error -> TotalBalanceCardState.Failure( - amount = status.fiatAmount, - fiatCurrency = status.fiatCurrency, + is TotalFiatBalance.Loading -> TotalBalanceCardState.Loading( + fiatCurrency = fiatCurrency, onChangeFiatCurrencyClick = onChangeCurrencyClick, ) - ProgressState.Refreshing, - ProgressState.Done, - -> TotalBalanceCardState.Success( - amount = status.fiatAmount ?: BigDecimal.ZERO, - fiatCurrency = status.fiatCurrency, + is TotalFiatBalance.Loaded -> TotalBalanceCardState.Success( + amount = status.amount, + fiatCurrency = fiatCurrency, onChangeFiatCurrencyClick = onChangeCurrencyClick, ) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/WalletDetailsButtonsRow.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/WalletDetailsButtonsRow.kt index c7457f1158..d9bf31f00c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/WalletDetailsButtonsRow.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/WalletDetailsButtonsRow.kt @@ -9,7 +9,7 @@ import androidx.core.view.isVisible import com.google.android.material.button.MaterialButton import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show -import com.tangem.tap.features.wallet.redux.CurrencyAction +import com.tangem.tap.features.wallet.ui.utils.CurrencyAction import com.tangem.wallet.databinding.ViewWalletDetailsButtonsRowBinding internal class WalletDetailsButtonsRow @JvmOverloads constructor( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index d735ef9615..f981a8beca 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -1,6 +1,5 @@ package com.tangem.tap.features.wallet.ui.wallet -import android.widget.Button import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import com.badoo.mvicore.modelWatcher @@ -14,14 +13,13 @@ import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.features.tokens.redux.TokensAction -import com.tangem.tap.features.wallet.models.TotalBalance +import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState -import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.features.wallet.ui.WalletFragment import com.tangem.tap.features.wallet.ui.adapters.WalletAdapter -import com.tangem.tap.features.wallet.ui.view.WalletDetailsButtonsRow import com.tangem.tap.store import com.tangem.wallet.R import com.tangem.wallet.databinding.FragmentWalletBinding @@ -151,35 +149,29 @@ class MultiWalletView : WalletView() { } } - private fun handleTotalBalance(binding: FragmentWalletBinding, totalBalance: TotalBalance?, walletsCount: Int) = - with(binding.lCardTotalBalance) { - isVisible = walletsCount > 0 + private fun handleTotalBalance( + binding: FragmentWalletBinding, + totalBalance: TotalFiatBalance?, + walletsCount: Int, + ) = with(binding.lCardTotalBalance) { + isVisible = walletsCount > 0 - onChangeFiatCurrencyClick = { - store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) - } - status = totalBalance + onChangeFiatCurrencyClick = { + store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) } + status = totalBalance + } private fun handleErrorStates(state: WalletState, binding: FragmentWalletBinding, fragment: WalletFragment) { - when (state.primaryWalletData?.currencyData?.status) { - BalanceStatus.EmptyCard -> { - showErrorState( - binding, - fragment.getText(R.string.wallet_error_empty_card), - fragment.getString(R.string.wallet_error_empty_card_subtitle), - ) - configureButtonsForEmptyWalletState(binding) - } - BalanceStatus.UnknownBlockchain -> { + when (state.error) { + ErrorType.UnknownBlockchain -> { showErrorState( binding, fragment.getText(R.string.wallet_error_unsupported_blockchain), fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle), ) } - else -> { /* no-op */ - } + else -> { /* no-op */ } } } @@ -199,27 +191,8 @@ class MultiWalletView : WalletView() { } } - private fun configureButtonsForEmptyWalletState(binding: FragmentWalletBinding) = with(binding) { - rowButtons.btnBuy.hide() - rowButtons.btnSell.hide() - rowButtons.btnTrade.hide() - rowButtons.show() - - rowButtons.btnSend.text = fragment?.getText(R.string.wallet_button_create_wallet) - rowButtons.onSendClick = { store.dispatch(WalletAction.CreateWallet) } - } - override fun onDestroyFragment() { super.onDestroyFragment() watcher.clear() } -} - -private val WalletDetailsButtonsRow.btnBuy: Button - get() = this.findViewById(R.id.btn_buy) -private val WalletDetailsButtonsRow.btnSell: Button - get() = this.findViewById(R.id.btn_sell) -private val WalletDetailsButtonsRow.btnTrade: Button - get() = this.findViewById(R.id.btn_trade) -private val WalletDetailsButtonsRow.btnSend: Button - get() = this.findViewById(R.id.btn_send) \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt index f29df37ca0..744fc34601 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt @@ -11,14 +11,19 @@ import com.tangem.tap.common.extensions.getQuantityString import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction import com.tangem.tap.features.wallet.models.PendingTransactionType import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletMainButton import com.tangem.tap.features.wallet.redux.WalletState +import com.tangem.tap.features.wallet.ui.utils.getAvailableActions +import com.tangem.tap.features.wallet.ui.utils.isAvailableToBuy +import com.tangem.tap.features.wallet.ui.utils.isAvailableToSell +import com.tangem.tap.features.wallet.ui.utils.mainButton +import com.tangem.tap.features.wallet.ui.utils.shouldShowMultipleAddress import com.tangem.tap.features.wallet.ui.BalanceWidget import com.tangem.tap.features.wallet.ui.MultipleAddressUiHelper import com.tangem.tap.features.wallet.ui.WalletFragment @@ -71,7 +76,7 @@ class SingleWalletView : WalletView() { setupTwinCards(state.twinCardsState, binding) setupButtons(primaryWalletData, binding, state.isExchangeServiceFeatureOn) setupAddressCard(state, binding) - showPendingTransactionsIfPresent(primaryWalletData.pendingTransactions) + showPendingTransactionsIfPresent(primaryWalletData.status.pendingTransactions) setupBalance(state, primaryWalletData) } @@ -83,32 +88,30 @@ class SingleWalletView : WalletView() { binding?.rvPendingTransaction?.show(knownTransactions.isNotEmpty()) } - private fun setupBalance(state: WalletState, primaryWallet: WalletData) { + private fun setupBalance(state: WalletState, primaryWallet: WalletDataModel) { val fragment = fragment ?: return binding?.apply { lCardBalance.lBalance.root.show() BalanceWidget( binding = this.lCardBalance, fragment = fragment, - data = primaryWallet.currencyData, - token = state.primaryTokenData?.currencyData, - isTwinCard = state.isTangemTwins, + blockchainWalletData = primaryWallet, + tokenWalletData = state.primaryTokenData, ).setup() } } private fun setupTwinCards(twinCardsState: TwinCardsState?, binding: FragmentWalletBinding) = with(binding) { - twinCardsState?.cardNumber?.let { cardNumber -> - tvTwinCardNumber.show() - tvTwinCardNumber.text = tvTwinCardNumber.getQuantityString(R.plurals.card_label_card_count, 2) - } if (twinCardsState?.cardNumber == null) { tvTwinCardNumber.hide() + } else { + tvTwinCardNumber.show() + tvTwinCardNumber.text = tvTwinCardNumber.getQuantityString(R.plurals.card_label_card_count, 2) } } private fun setupButtons( - walletData: WalletData, + walletData: WalletDataModel, binding: FragmentWalletBinding, isExchangeServiceFeatureEnabled: Boolean, ) = with(binding) { @@ -134,7 +137,7 @@ class SingleWalletView : WalletView() { } private fun setupRowButtons( - walletData: WalletData, + walletData: WalletDataModel, rowButtons: WalletDetailsButtonsRow, isExchangeServiceFeatureEnabled: Boolean, ) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt index e999ee383a..ef9bf43ffa 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt @@ -8,13 +8,15 @@ import com.tangem.tap.common.ShimmerData import com.tangem.tap.common.ShimmerRecyclerAdapter import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.extensions.animateVisibility -import com.tangem.tap.common.extensions.formatAmountAsSpannedString import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState +import com.tangem.tap.features.wallet.ui.utils.getFormattedAmount +import com.tangem.tap.features.wallet.ui.utils.getFormattedFiatAmount +import com.tangem.tap.features.wallet.ui.utils.isAvailableToBuy import com.tangem.tap.features.wallet.ui.WalletFragment import com.tangem.tap.features.wallet.ui.wallet.WalletView import com.tangem.tap.features.wallet.ui.wallet.saltPay.rv.HistoryItemData @@ -124,16 +126,14 @@ class SaltPayWalletView : WalletView() { tvUnreachable.animateVisibility(show = mainProgressState == ProgressState.Error) veilBalanceCrypto.animateVisibility(show = mainProgressState != ProgressState.Error) - if (tokenData.currencyData.fiatAmount == null) { + if (tokenData.fiatRate == null) { veilBalance.veil() } else { veilBalance.unVeil() - tvBalance.text = tokenData.currencyData.fiatAmount.formatAmountAsSpannedString( - currencySymbol = appCurrency.symbol, - ) + tvBalance.text = tokenData.getFormattedFiatAmount(appCurrency) } - tvBalanceCrypto.text = tokenData.currencyData.amountFormatted + tvBalanceCrypto.text = tokenData.getFormattedAmount() tvCurrencyName.text = appCurrency.code tvCurrencyName.setOnClickListener { diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt index a00447b139..400c4e026e 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt @@ -3,7 +3,7 @@ package com.tangem.tap.features.walletSelector.ui import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.toFormattedFiatValue import com.tangem.tap.domain.model.TotalFiatBalance -import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN +import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN import com.tangem.tap.features.walletSelector.redux.UserWalletModel import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem From 708dc23382165aba29fe99318f1c22b571d9468c Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 11 Apr 2023 12:49:58 +0300 Subject: [PATCH 14/30] Updated on 2026-08-14 --- .../tap/features/wallet/models/Currency.kt | 9 -- .../wallet/models/PendingTransaction.kt | 22 +-- .../features/wallet/models/TotalBalance.kt | 11 -- .../features/wallet/models/WalletWarning.kt | 4 +- .../tap/features/wallet/redux/WalletData.kt | 126 --------------- .../tap/features/wallet/redux/WalletState.kt | 53 ------- .../middlewares/AppCurrencyMiddleware.kt | 2 +- .../wallet/redux/middlewares/Mapper.kt | 145 ------------------ .../redux/reducers/TotalBalanceOperations.kt | 73 --------- .../tap/features/wallet/ui/BalanceWidget.kt | 48 ------ .../wallet/saltPay/HistoryTransactionData.kt | 21 --- 11 files changed, 3 insertions(+), 511 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/wallet/redux/WalletData.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TotalBalanceOperations.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/HistoryTransactionData.kt diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt index 4c4079055c..71cef96432 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/Currency.kt @@ -7,7 +7,6 @@ import com.tangem.domain.common.extensions.toCoinId import com.tangem.domain.features.addCustomToken.CustomCurrency import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.domain.tokens.models.BlockchainNetwork -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain import com.tangem.blockchain.common.Blockchain as SdkBlockchain import com.tangem.blockchain.common.Token as SdkToken @@ -87,14 +86,6 @@ sealed interface Currency { } } - fun fromTokenWithBlockchain(tokenWithBlockchain: TokenWithBlockchain): Token { - return Token( - token = tokenWithBlockchain.token, - blockchain = tokenWithBlockchain.blockchain, - derivationPath = null, - ) - } - fun fromTokenResponse(tokenBody: UserTokensResponse.Token): Currency? { val blockchain = com.tangem.blockchain.common.Blockchain.fromNetworkId(tokenBody.networkId) ?: return null diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt index 0e3aea8db6..e2b74e5ebd 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/PendingTransaction.kt @@ -26,7 +26,7 @@ data class PendingTransaction( val currency: String = transactionData.amount.currencySymbol - fun nullIfUnknown(address: String): String? = if (address == "unknown") null else address + private fun nullIfUnknown(address: String): String? = if (address == "unknown") null else address } enum class PendingTransactionType { Incoming, Outgoing, Unknown } @@ -46,18 +46,10 @@ fun List.toPendingTransactions(walletAddress: String): List.removeUnknownTransactions(): List { - return this.filter { it.type != PendingTransactionType.Unknown } -} - fun List.filterByCoin(): List { return this.filter { it.transactionData.amount.type == AmountType.Coin } } -fun List.filterByToken(token: Token): List { - return this.filter { it.transactionData.amount.currencySymbol == token.symbol } -} - fun TransactionData.toPendingTransactionForToken(token: Token, walletAddress: String): PendingTransaction? { if (this.amount.currencySymbol != token.symbol) return null return this.toPendingTransaction(walletAddress) @@ -79,10 +71,6 @@ fun Wallet.hasPendingTransactions(): Boolean { return getPendingTransactions().isNotEmpty() } -fun Wallet.hasPendingTransactions(token: Token): Boolean { - return getPendingTransactions(token).isNotEmpty() -} - fun Wallet.getSendableAmounts(): List { return amounts.values .filter { it.type != AmountType.Reserve } @@ -93,14 +81,6 @@ fun Wallet.hasSendableAmounts(): Boolean { return getSendableAmounts().isNotEmpty() } -fun Wallet.hasSendableAmountsOrPendingTransactions(): Boolean { - return hasPendingTransactions() || hasSendableAmounts() -} - fun Wallet.isSendableAmount(type: AmountType): Boolean { return amounts[type]?.isAboveZero() == true -} - -fun Wallet.isSendableAmount(token: Token): Boolean { - return isSendableAmount(AmountType.Token(token)) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt deleted file mode 100644 index a57bf4e6da..0000000000 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.tap.features.wallet.models - -import com.tangem.tap.common.entities.FiatCurrency -import com.tangem.tap.features.wallet.redux.ProgressState -import java.math.BigDecimal - -data class TotalBalance( - val state: ProgressState, - val fiatAmount: BigDecimal?, - val fiatCurrency: FiatCurrency, -) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt index 421bfa85fe..ef3c3466c4 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/WalletWarning.kt @@ -20,6 +20,4 @@ sealed class WalletWarning(val showingPosition: Int) { data class Rent(val walletRent: WalletStoreModel.WalletRent) : WalletWarning(showingPosition = 40) } -data class WalletWarningDescription(val title: String, val message: String) - -data class WalletRent(val minRentValue: String, val rentExemptValue: String) \ No newline at end of file +data class WalletWarningDescription(val title: String, val message: String) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletData.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletData.kt deleted file mode 100644 index 423306eec6..0000000000 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletData.kt +++ /dev/null @@ -1,126 +0,0 @@ -package com.tangem.tap.features.wallet.redux - -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.TransactionData -import com.tangem.common.extensions.isZero -import com.tangem.domain.common.extensions.toNetworkId -import com.tangem.feature.swap.api.SwapFeatureToggleManager -import com.tangem.feature.swap.domain.SwapInteractor -import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.models.PendingTransaction -import com.tangem.tap.features.wallet.models.WalletRent -import com.tangem.tap.features.wallet.models.WalletWarning -import com.tangem.tap.features.wallet.ui.BalanceStatus -import com.tangem.tap.features.wallet.ui.BalanceWidgetData -import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager -import java.math.BigDecimal - -data class WalletData( - val pendingTransactions: List = emptyList(), - val historyTransactions: List? = null, - val hashesCountVerified: Boolean? = null, - val walletAddresses: WalletAddresses? = null, - val currencyData: BalanceWidgetData = BalanceWidgetData(), - val updatingWallet: Boolean = false, - val fiatRateString: String? = null, - val fiatRate: BigDecimal? = null, - val mainButton: WalletMainButton = WalletMainButton.SendButton(false), - val currency: Currency, - val walletRent: WalletRent? = null, - val existentialDepositString: String? = null, -) { - fun isAvailableToBuy(exchangeManager: CurrencyExchangeManager): Boolean { - return exchangeManager.availableForBuy(currency) - } - - fun isAvailableToSell(exchangeManager: CurrencyExchangeManager): Boolean { - return exchangeManager.availableForSell(currency) - } - - fun isAvailableToSwap( - swapFeatureToggleManager: SwapFeatureToggleManager, - swapInteractor: SwapInteractor, - ): Boolean { - if (currency.blockchain.id == Blockchain.Optimism.id && !swapFeatureToggleManager.isOptimismSwapEnabled) { - return false - } - return swapInteractor.isAvailableToSwap(currency.blockchain.toNetworkId()) && - !currency.isCustomCurrency(null) - } - - fun getAvailableActions( - swapInteractor: SwapInteractor, - exchangeManager: CurrencyExchangeManager, - swapFeatureToggleManager: SwapFeatureToggleManager, - ): Set { - return setOfNotNull( - if (isAvailableToBuy(exchangeManager)) CurrencyAction.Buy else null, - if (isAvailableToSell(exchangeManager)) CurrencyAction.Sell else null, - if (isAvailableToSwap(swapFeatureToggleManager, swapInteractor)) CurrencyAction.Swap else null, - ) - } - - fun shouldShowMultipleAddress(): Boolean { - val listOfAddresses = walletAddresses?.list ?: return false - return listOfAddresses.size > 1 - } - - fun shouldEnableTokenSendButton(): Boolean = if (blockchainAmountIsEmpty()) { - false - } else { - !tokenAmountIsEmpty() - } - - fun assembleWarnings(): List { - val walletWarnings = mutableListOf() - assembleNonTypedWarnings(walletWarnings) - assembleBlockchainWarnings(walletWarnings) - assembleTokenWarnings(walletWarnings) - - return walletWarnings.sortedBy { it.showingPosition } - } - - private fun assembleNonTypedWarnings(walletWarnings: MutableList) { - if (currencyData.status == BalanceStatus.SameCurrencyTransactionInProgress) { - walletWarnings.add(WalletWarning.TransactionInProgress(currency.currencyName)) - } - if (walletRent != null) { - // TODO: Will be removed in next MR - // walletWarnings.add(WalletWarning.Rent(walletRent)) - } - } - - private fun assembleBlockchainWarnings(walletWarnings: MutableList) = with(currency) { - if (!isBlockchain()) return - - if (existentialDepositString != null) { - val warning = WalletWarning.ExistentialDeposit( - currencyName = currencyName, - edStringValueWithSymbol = "$existentialDepositString $currencySymbol", - ) - walletWarnings.add(warning) - } - } - - private fun assembleTokenWarnings(walletWarnings: MutableList) = with(currency) { - if (!isToken()) return - - if (blockchainAmountIsEmpty() && !tokenAmountIsEmpty()) { - walletWarnings.add( - WalletWarning.BalanceNotEnoughForFee( - currencyName = currencyName, - blockchainFullName = blockchain.fullName, - blockchainSymbol = blockchain.currency, - ), - ) - } - } - - private fun blockchainAmountIsEmpty(): Boolean = currencyData.blockchainAmount?.isZero() == true - - private fun tokenAmountIsEmpty(): Boolean = currencyData.amount?.isZero() == true -} - -enum class CurrencyAction { - Buy, Sell, Swap -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 6d4a5c788a..a1b4340f07 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -3,9 +3,7 @@ package com.tangem.tap.features.wallet.redux import android.graphics.Bitmap import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.WalletManager -import com.tangem.blockchain.common.address.AddressType import com.tangem.tap.common.entities.Button -import com.tangem.tap.common.extensions.toQrCode import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.common.toggleWidget.WidgetState import com.tangem.tap.domain.configurable.warningMessage.WarningMessage @@ -120,20 +118,6 @@ sealed class WalletMainButton(enabled: Boolean) : Button(enabled) { class CreateWalletButton(enabled: Boolean) : WalletMainButton(enabled) } -data class WalletAddresses( - val selectedAddress: AddressData, - val list: List, -) - -data class AddressData( - val address: String, - val type: AddressType, - val shareUrl: String, - val exploreUrl: String, -) { - val qrCode: Bitmap by lazy { shareUrl.toQrCode() } -} - data class Artwork( val artworkId: String, val artwork: Bitmap? = null, @@ -148,41 +132,4 @@ data class Artwork( const val TWIN_CARD_2 = "https://app.tangem.com/cards/card_tg086.png" const val SALT_PAY_URL = "key_for_switch_url_to_drawableId_of_salt_pay_card" } -} - -data class WalletStore( - val walletManager: WalletManager?, - val blockchainNetwork: BlockchainNetwork, - val walletsData: List, -) { - fun updateWallets(walletDataList: List): WalletStore { - val relevantWalletDataList = walletDataList.filter { - it.currency.blockchain == blockchainNetwork.blockchain && - it.currency.derivationPath == blockchainNetwork.derivationPath - }.toMutableList() - val updatedWalletDataList = walletsData.map { walletData -> - val matchingWalletData = relevantWalletDataList.find { it.currency == walletData.currency } - if (matchingWalletData != null) relevantWalletDataList.remove(matchingWalletData) - matchingWalletData ?: walletData - } - return copy(walletsData = updatedWalletDataList + relevantWalletDataList) - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as WalletStore - - if (walletManager != other.walletManager) return false - if (blockchainNetwork != other.blockchainNetwork) return false - - return true - } - - override fun hashCode(): Int { - var result = walletManager?.hashCode() ?: 0 - result = 31 * result + blockchainNetwork.hashCode() - return result - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt index 8c1847b11a..cabb464853 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt @@ -49,7 +49,7 @@ class AppCurrencyMiddleware( runCatching { walletRepository.getCurrencyList() } .onSuccess { val currenciesList = it.currencies - if (currenciesList.isNotEmpty() && !currenciesList.toSet().equals(storedFiatCurrencies.toSet())) { + if (currenciesList.isNotEmpty() && currenciesList.toSet() != storedFiatCurrencies.toSet()) { fiatCurrenciesPrefStorage.save(currenciesList) store.dispatchDialogShow( WalletDialog.CurrencySelectionDialog( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt deleted file mode 100644 index e48f89ce52..0000000000 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt +++ /dev/null @@ -1,145 +0,0 @@ -package com.tangem.tap.features.wallet.redux.middlewares - -import com.tangem.common.extensions.isZero -import com.tangem.tap.common.extensions.stripZeroPlainString -import com.tangem.tap.common.extensions.toFiatRateString -import com.tangem.tap.common.extensions.toFiatValue -import com.tangem.tap.common.extensions.toFormattedCurrencyString -import com.tangem.tap.common.extensions.toFormattedFiatValue -import com.tangem.tap.domain.model.TotalFiatBalance -import com.tangem.tap.domain.model.WalletDataModel -import com.tangem.tap.domain.model.WalletStoreModel -import com.tangem.tap.features.wallet.models.TotalBalance -import com.tangem.tap.features.wallet.models.WalletRent -import com.tangem.tap.features.wallet.redux.AddressData -import com.tangem.tap.features.wallet.redux.ProgressState -import com.tangem.tap.features.wallet.redux.WalletAddresses -import com.tangem.tap.features.wallet.redux.WalletData -import com.tangem.tap.features.wallet.redux.WalletMainButton -import com.tangem.tap.features.wallet.redux.WalletStore -import com.tangem.tap.features.wallet.ui.BalanceStatus -import com.tangem.tap.features.wallet.ui.BalanceWidgetData -import com.tangem.tap.store -import java.math.BigDecimal - -internal fun List.mapToReduxModels(): List { - return this.map { walletStoreModel -> - walletStoreModel.mapToReduxModel() - } -} - -internal fun TotalFiatBalance.mapToReduxModel(): TotalBalance { - return TotalBalance( - state = when (this) { - is TotalFiatBalance.Loading -> ProgressState.Loading - is TotalFiatBalance.Error -> ProgressState.Error - is TotalFiatBalance.Loaded -> ProgressState.Done - }, - fiatAmount = amount, - fiatCurrency = store.state.globalState.appCurrency, - ) -} - -internal fun WalletStoreModel.mapToReduxModel(): WalletStore { - val appCurrencySymbol = store.state.globalState.appCurrency.symbol - return WalletStore( - walletManager = walletManager, - blockchainNetwork = blockchainNetwork, - walletsData = walletsData.mapToReduxModels(walletRent, appCurrencySymbol), - ) - .updateTokenModels(blockchainWalletData.status.amount) -} - -@Suppress("LongMethod", "ComplexMethod") -private fun List.mapToReduxModels( - walletRent: WalletStoreModel.WalletRent?, - appCurrencySymbol: String, -): List { - return this.map { walletDataModel -> - walletDataModel.mapToReduxModel(walletRent, appCurrencySymbol) - } -} - -private fun WalletDataModel.mapToReduxModel( - walletRent: WalletStoreModel.WalletRent?, - appCurrencySymbol: String, -): WalletData { - val amount = status.amount - val amountFormatted = amount.toFormattedCurrencyString( - decimals = currency.decimals, - currency = currency.currencySymbol, - ) - val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) } - val fiatAmountFormatted = fiatAmount - ?.takeIf { !status.isErrorStatus } - ?.toFormattedFiatValue(appCurrencySymbol) - val fiatRateFormatted = fiatRate?.toFiatRateString(appCurrencySymbol) - - return WalletData( - currency = currency, - // TODO: Will be updated in next MRs - walletAddresses = walletAddresses?.let { addresses -> - WalletAddresses( - selectedAddress = with(addresses.selectedAddress) { - AddressData(address, type, shareUrl, exploreUrl) - }, - list = addresses.list.map { - with(it) { AddressData(address, type, shareUrl, exploreUrl) } - }, - ) - }, - existentialDepositString = existentialDeposit?.toPlainString(), - fiatRate = fiatRate, - fiatRateString = fiatRateFormatted, - pendingTransactions = status.pendingTransactions, - mainButton = WalletMainButton.SendButton( - enabled = !status.amount.isZero() && status.pendingTransactions.isEmpty(), - ), - walletRent = walletRent?.let { - WalletRent( - minRentValue = "${it.rent.stripZeroPlainString()} ${currency.blockchain.currency}", - rentExemptValue = "${it.exemptionAmount.stripZeroPlainString()} ${currency.blockchain.currency}", - ) - }, - currencyData = BalanceWidgetData( - status = when (status) { - is WalletDataModel.Loading -> BalanceStatus.Loading - is WalletDataModel.NoAccount -> BalanceStatus.NoAccount - is WalletDataModel.SameCurrencyTransactionInProgress -> BalanceStatus.SameCurrencyTransactionInProgress - is WalletDataModel.TransactionInProgress -> BalanceStatus.TransactionInProgress - is WalletDataModel.Unreachable -> BalanceStatus.Unreachable - is WalletDataModel.MissedDerivation -> BalanceStatus.MissedDerivation - is WalletDataModel.VerifiedOnline -> BalanceStatus.VerifiedOnline - }, - currency = currency.currencyName, - currencySymbol = currency.currencySymbol, - blockchainAmount = BigDecimal.ZERO, - amount = amount, - amountFormatted = amountFormatted, - fiatAmount = fiatAmount, - fiatAmountFormatted = fiatAmountFormatted, - amountToCreateAccount = (status as? WalletDataModel.NoAccount) - ?.amountToCreateAccount - ?.toString(), - errorMessage = status.errorMessage, - ), - historyTransactions = historyTransactions, - ) -} - -private fun WalletStore.updateTokenModels(blockchainAmount: BigDecimal): WalletStore { - val updatedTokensWalletData = walletsData.filter { it.currency.isToken() }.map { - it.copy( - mainButton = when (it.mainButton) { - is WalletMainButton.SendButton -> { - WalletMainButton.SendButton(it.mainButton.enabled && !blockchainAmount.isZero()) - } - is WalletMainButton.CreateWalletButton -> it.mainButton - }, - currencyData = it.currencyData.copy( - blockchainAmount = blockchainAmount, - ), - ) - } - return updateWallets(updatedTokensWalletData) -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TotalBalanceOperations.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TotalBalanceOperations.kt deleted file mode 100644 index ab255c0eb9..0000000000 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TotalBalanceOperations.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.tangem.tap.features.wallet.redux.reducers - -import com.tangem.tap.features.wallet.redux.ProgressState -import com.tangem.tap.features.wallet.redux.WalletData -import com.tangem.tap.features.wallet.ui.BalanceStatus -import java.math.BigDecimal - -fun List.findProgressState(initialState: ProgressState = ProgressState.Done): ProgressState { - if (this.isEmpty()) return initialState - - return this - .mapToProgressState() - .reduce(ProgressState::or) -} - -fun List.calculateTotalCryptoAmount(): BigDecimal { - return this - .map { it.currencyData.amount ?: BigDecimal.ZERO } - .reduce(BigDecimal::plus) -} - -private fun List.mapToProgressState(): List { - return this.map { wallet -> - if (wallet.fiatRate == null) { - ProgressState.Error - } else { - when (wallet.currencyData.status) { - BalanceStatus.Refreshing -> ProgressState.Refreshing - BalanceStatus.VerifiedOnline, - BalanceStatus.SameCurrencyTransactionInProgress, - BalanceStatus.TransactionInProgress, - BalanceStatus.NoAccount, - -> ProgressState.Done - BalanceStatus.Unreachable, - BalanceStatus.EmptyCard, - BalanceStatus.UnknownBlockchain, - BalanceStatus.MissedDerivation, - -> ProgressState.Error - BalanceStatus.Loading, - null, - -> ProgressState.Loading - } - } - } -} - -private infix fun ProgressState.or(newState: ProgressState): ProgressState { - return when (this) { - ProgressState.Loading -> when (newState) { - ProgressState.Loading, - ProgressState.Refreshing, - ProgressState.Error, - ProgressState.Done, - -> this - } - ProgressState.Done, - ProgressState.Error, - -> when (newState) { - ProgressState.Loading, - ProgressState.Refreshing, - ProgressState.Error, - -> newState - ProgressState.Done -> this - } - ProgressState.Refreshing -> when (newState) { - ProgressState.Loading -> this - ProgressState.Refreshing, - ProgressState.Error, - ProgressState.Done, - -> newState - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt index 3b8cac1392..23aa7d9d6e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt @@ -9,33 +9,6 @@ import com.tangem.tap.features.wallet.ui.utils.getFormattedFiatAmount import com.tangem.tap.store import com.tangem.wallet.R import com.tangem.wallet.databinding.CardBalanceBinding -import java.math.BigDecimal - -enum class BalanceStatus { - VerifiedOnline, - TransactionInProgress, - SameCurrencyTransactionInProgress, - Unreachable, - Loading, - Refreshing, - NoAccount, - EmptyCard, - UnknownBlockchain, - MissedDerivation, -} - -data class BalanceWidgetData( - val status: BalanceStatus? = null, - val currency: String? = null, - val currencySymbol: String? = null, - val amount: BigDecimal? = null, - val amountFormatted: String? = null, - val fiatAmount: BigDecimal? = null, - val fiatAmountFormatted: String? = null, - val blockchainAmount: BigDecimal? = BigDecimal.ZERO, - val amountToCreateAccount: String? = null, - val errorMessage: String? = null, -) class BalanceWidget( private val binding: CardBalanceBinding, @@ -104,19 +77,6 @@ class BalanceWidget( showStatus(R.id.group_error) tvStatusErrorMessage.show(!blockchainWalletData.status.errorMessage.isNullOrBlank()) } - // BalanceStatus.EmptyCard -> with(binding.lBalanceError) { - // binding.lBalance.root.hide() - // binding.lBalanceError.root.show() - // if (isTwinCard) { - // tvErrorTitle.text = fragment.getText(R.string.wallet_error_empty_twin_card) - // tvErrorDescriptions.text = - // fragment.getText(R.string.wallet_error_empty_twin_card_subtitle) - // } else { - // tvErrorTitle.text = fragment.getText(R.string.wallet_error_empty_card) - // tvErrorDescriptions.text = - // fragment.getText(R.string.wallet_error_empty_card_subtitle) - // } - // } is WalletDataModel.NoAccount -> with(binding.lBalanceError) { binding.lBalance.root.hide() binding.lBalanceError.root.show() @@ -128,14 +88,6 @@ class BalanceWidget( blockchainWalletData.currency.currencySymbol, ) } - // BalanceStatus.UnknownBlockchain -> with(binding.lBalanceError) { - // binding.lBalance.root.hide() - // binding.lBalanceError.root.show() - // tvErrorTitle.text = - // fragment.getText(R.string.wallet_error_unsupported_blockchain) - // tvErrorDescriptions.text = - // fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle) - // } else -> {} } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/HistoryTransactionData.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/HistoryTransactionData.kt deleted file mode 100644 index 50b80f0b37..0000000000 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/HistoryTransactionData.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.tap.features.wallet.ui.wallet.saltPay - -import com.tangem.blockchain.common.TransactionData -import com.tangem.blockchain.common.TransactionStatus -import com.tangem.tap.features.wallet.models.PendingTransactionType - -/** -[REDACTED_AUTHOR] - */ -data class HistoryTransactionData( - val transactionData: TransactionData, - private val walletAddress: String, -) { - fun isInProgress(): Boolean = transactionData.status == TransactionStatus.Unconfirmed - - fun getTransactionType(): PendingTransactionType = when { - transactionData.sourceAddress.lowercase() == walletAddress.lowercase() -> PendingTransactionType.Outgoing - transactionData.destinationAddress.lowercase() == walletAddress.lowercase() -> PendingTransactionType.Incoming - else -> PendingTransactionType.Unknown - } -} \ No newline at end of file From bfb2338a1ab148a62a5e903bafea779b54ebd350 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Apr 2023 16:19:43 +0900 Subject: [PATCH 15/30] Updated on 2026-08-14 --- .../tokens/di/TokensListRepositoryModule.kt | 37 ++ .../tokens/presentation/TokensListFragment.kt | 9 +- .../presentation/models/TokensListArgs.kt | 22 + .../presentation/states/NetworkItemState.kt | 58 +- .../presentation/states/TokenItemState.kt | 12 +- .../states/TokensListStateHolder.kt | 64 +- .../states/TokensListToolbarState.kt | 32 +- .../states/TokensListVisibility.kt | 10 - .../presentation/ui/BriefNetworksList.kt | 2 +- .../presentation/ui/DetailedNetworksList.kt | 36 +- .../tokens/presentation/ui/TokenItem.kt | 4 +- .../presentation/ui/TokenListPreviewData.kt | 47 +- ...AddTokensScreen.kt => TokensListScreen.kt} | 117 ++-- ...dTokensToolbar.kt => TokensListToolbar.kt} | 26 +- .../viewmodels/TokensListAnalyticsSender.kt | 59 ++ .../viewmodels/TokensListViewModel.kt | 562 ++++++++---------- .../features/tokens/redux/TokensMiddleware.kt | 32 +- 17 files changed, 613 insertions(+), 516 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/models/TokensListArgs.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListVisibility.kt rename app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/{AddTokensScreen.kt => TokensListScreen.kt} (60%) rename app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/{AddTokensToolbar.kt => TokensListToolbar.kt} (91%) create mode 100644 app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListAnalyticsSender.kt diff --git a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt new file mode 100644 index 0000000000..e71a3a6531 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt @@ -0,0 +1,37 @@ +package com.tangem.tap.features.tokens.di + +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.local.testnet.TestnetTokensStorage +import com.tangem.tap.features.tokens.data.DefaultTokensListRepository +import com.tangem.tap.features.tokens.domain.TokensListRepository +import com.tangem.tap.proxy.AppStateHolder +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +/** +[REDACTED_AUTHOR] + */ +@Module +@InstallIn(SingletonComponent::class) +internal object TokensListRepositoryModule { + + @Provides + @Singleton + fun providesTokensListRepository( + tangemTechApi: TangemTechApi, + dispatchers: CoroutineDispatcherProvider, + reduxStateHolder: AppStateHolder, + testnetTokensStorage: TestnetTokensStorage, + ): TokensListRepository { + return DefaultTokensListRepository( + tangemTechApi = tangemTechApi, + dispatchers = dispatchers, + reduxStateHolder = reduxStateHolder, + testnetTokensStorage = testnetTokensStorage, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt index 0c66bbcbea..55615e908b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt @@ -5,13 +5,12 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.core.view.WindowCompat import androidx.fragment.app.Fragment import androidx.hilt.navigation.compose.hiltViewModel import androidx.transition.TransitionInflater import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.ui.AddTokensScreen +import com.tangem.tap.features.tokens.presentation.ui.TokensListScreen import com.tangem.tap.features.tokens.presentation.viewmodels.TokensListViewModel import com.tangem.wallet.R import dagger.hilt.android.AndroidEntryPoint @@ -36,12 +35,10 @@ internal class TokensListFragment : Fragment() { setContent { isTransitionGroup = true - val viewModel = hiltViewModel().apply { - subscribeOnReduxEvents(lifecycle = LocalLifecycleOwner.current.lifecycle) - } + val viewModel = hiltViewModel() TangemTheme { - AddTokensScreen(stateHolder = viewModel.uiState) + TokensListScreen(stateHolder = viewModel.uiState) } } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/models/TokensListArgs.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/models/TokensListArgs.kt new file mode 100644 index 0000000000..de2b9a97bf --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/models/TokensListArgs.kt @@ -0,0 +1,22 @@ +package com.tangem.tap.features.tokens.presentation.models + +import com.tangem.blockchain.common.Blockchain +import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +import com.tangem.tap.store + +/** + * Required data for tokens list screen + * FIXME("Necessary to avoid using redux state") + * +[REDACTED_AUTHOR] + */ +class TokensListArgs { + /** Tokens list screen mode */ + val isManageAccess: Boolean get() = store.state.tokensState.allowToAdd + + /** Tokens list that accessible from the main screen */ + val mainScreenTokenList: List get() = store.state.tokensState.addedTokens + + /** Blockchains list that accessible from the main screen */ + val mainScreenBlockchainList: List get() = store.state.tokensState.addedBlockchains +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt index c11142b85a..c6967c78e4 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt @@ -1,5 +1,9 @@ package com.tangem.tap.features.tokens.presentation.states +import androidx.compose.runtime.MutableState +import com.tangem.blockchain.common.Blockchain +import com.tangem.core.ui.extensions.getActiveIconRes +import com.tangem.tap.common.extensions.getGreyedOutIconRes import com.tangem.tap.features.tokens.redux.ContractAddress /** @@ -16,7 +20,7 @@ sealed interface NetworkItemState { val protocolName: String /** Network icon id from resources */ - val iconResId: Int + val iconResId: MutableState /** Flag that determines if the network is the main network for the token */ val isMainNetwork: Boolean @@ -29,35 +33,51 @@ sealed interface NetworkItemState { * @property iconResId network icon id from resources * @property isMainNetwork flag that determines if the network is the main network for the token */ - data class ReadAccess( + data class ReadContent( override val name: String, override val protocolName: String, - override val iconResId: Int, + override val iconResId: MutableState, override val isMainNetwork: Boolean, ) : NetworkItemState /** * Network item state that is available for read and edit * - * @property name network name - * @property protocolName network protocol name - * @property iconResId network icon id from resources - * @property isMainNetwork flag that determines if the network is the main network for the token - * @property isAdded flag that determines if the user has saved the token - * @property networkId network id - * @property contractAddress contract address - * @property onToggleClick lambda be invoked when switch is been toggled - * @property onNetworkClick lambda be invoked when network item is been clicked + * @property name network name + * @property protocolName network protocol name + * @property iconResId network icon id from resources + * @property isMainNetwork flag that determines if the network is the main network for the token + * @property isAdded flag that determines if the user has saved the token + * @property id network id + * @property address contract address + * @property decimalCount decimal count + * @property blockchain blockchain + * @property onToggleClick lambda be invoked when switch is been toggled + * @property onNetworkClick lambda be invoked when network item is been clicked */ - data class ManageAccess( + data class ManageContent( override val name: String, override val protocolName: String, - override val iconResId: Int, + override val iconResId: MutableState, override val isMainNetwork: Boolean, - val isAdded: Boolean, - val networkId: String, - val contractAddress: ContractAddress?, - val onToggleClick: (String, String) -> Unit, + val isAdded: MutableState, + val id: String, + val address: ContractAddress?, + val decimalCount: Int?, + val blockchain: Blockchain, + val onToggleClick: (TokenItemState.ManageContent, ManageContent) -> Unit, val onNetworkClick: () -> Unit, - ) : NetworkItemState + ) : NetworkItemState { + + /** + * Change toggle state [isAdded]. + * + * It is a hack that helps us to change element of flow + */ + fun changeToggleState() { + val reverseState = !isAdded.value + isAdded.value = reverseState + iconResId.value = if (reverseState) getActiveIconRes(blockchain.id) else blockchain.getGreyedOutIconRes() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt index 5ce98ed4f0..e3ab7e2553 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt @@ -25,24 +25,26 @@ sealed interface TokenItemState { * @property iconUrl token icon url * @property networks list of networks that is available for read */ - data class ReadAccess( + data class ReadContent( override val name: String, override val iconUrl: String, - override val networks: ImmutableList, + override val networks: ImmutableList, ) : TokenItemState /** - * Token item state that is available for read and edit + * Token item state that is available for read and manage * * @property name token name * @property iconUrl token icon url * @property networks list of networks is available for read and edit * @property id token id + * @property symbol token brief name */ - data class ManageAccess( + data class ManageContent( override val name: String, override val iconUrl: String, - override val networks: ImmutableList, + override val networks: ImmutableList, val id: String, + val symbol: String, ) : TokenItemState } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt index 0cf5c4d03a..c4049ddfcc 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt @@ -1,6 +1,8 @@ package com.tangem.tap.features.tokens.presentation.states -import kotlinx.collections.immutable.ImmutableList +import androidx.paging.LoadState +import androidx.paging.PagingData +import kotlinx.coroutines.flow.Flow /** * State holder for screen with list of tokens @@ -12,47 +14,69 @@ internal sealed interface TokensListStateHolder { /** Toolbar state */ val toolbarState: TokensListToolbarState + /** Tokens list */ + val tokens: Flow> + + /** Callback to be invoked when [tokens] loading state is been changed */ + val onTokensLoadStateChanged: (LoadState) -> Unit + /** * Util function that allow to make a copy * - * @param toolbarState toolbar state + * @param toolbarState toolbar state + * @param tokens tokens list + * @param onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed */ - fun copySealed(toolbarState: TokensListToolbarState): TokensListStateHolder { + fun copySealed( + toolbarState: TokensListToolbarState = this.toolbarState, + tokens: Flow> = this.tokens, + onTokensLoadStateChanged: (LoadState) -> Unit = this.onTokensLoadStateChanged, + ): TokensListStateHolder { return when (this) { - is ManageAccess -> copy(toolbarState = toolbarState) - is Loading -> copy(toolbarState = toolbarState) - is ReadAccess -> copy(toolbarState = toolbarState) + is ManageContent -> copy(toolbarState, tokens, onTokensLoadStateChanged) + is Loading -> copy(toolbarState, tokens, onTokensLoadStateChanged) + is ReadContent -> copy(toolbarState, tokens, onTokensLoadStateChanged) } } /** * Loading state * - * @property toolbarState toolbar state + * @property toolbarState toolbar state + * @property tokens tokens list + * @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed */ - data class Loading(override val toolbarState: TokensListToolbarState) : TokensListStateHolder + data class Loading( + override val toolbarState: TokensListToolbarState, + override val tokens: Flow>, + override val onTokensLoadStateChanged: (LoadState) -> Unit, + ) : TokensListStateHolder /** * State screen that is available only for read * - * @property toolbarState toolbar state - * @property tokens tokens list + * @property toolbarState toolbar state + * @property tokens tokens list + * @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed */ - data class ReadAccess( + data class ReadContent( override val toolbarState: TokensListToolbarState, - override val tokens: ImmutableList, - ) : TokensListStateHolder, TokensListVisibility + override val tokens: Flow>, + override val onTokensLoadStateChanged: (LoadState) -> Unit, + ) : TokensListStateHolder /** - * State screen that is available for read and edit + * State screen that is available for read and manage * - * @property toolbarState toolbar state - * @property tokens tokens list - * @property onSaveButtonClick callback to be invoked when SaveButton is being clicked + * @property toolbarState toolbar state + * @property tokens tokens list + * @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed + * @property onSaveButtonClick callback to be invoked when SaveButton is being clicked */ - data class ManageAccess( + data class ManageContent( override val toolbarState: TokensListToolbarState, - override val tokens: ImmutableList, + override val tokens: Flow>, + override val onTokensLoadStateChanged: (LoadState) -> Unit, val onSaveButtonClick: () -> Unit, - ) : TokensListStateHolder, TokensListVisibility + ) : TokensListStateHolder } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt index 532c0739cf..0fff69aabd 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt @@ -6,39 +6,39 @@ sealed interface TokensListToolbarState { /** Callback to be invoked when BackButton is being clicked */ val onBackButtonClick: () -> Unit - /** Callback to be invoked when SearchButton is being clicked */ - val onSearchButtonClick: () -> Unit - /** Toolbar state as title */ sealed interface Title : TokensListToolbarState { /** Toolbar title id from resources */ val titleResId: Int + /** Callback to be invoked when SearchButton is being clicked */ + val onSearchButtonClick: () -> Unit + /** * Title state that is available only for read * - * @property titleResId toolbar title id from resources * @property onBackButtonClick callback to be invoked when BackButton is being clicked + * @property titleResId toolbar title id from resources * @property onSearchButtonClick callback to be invoked when SearchButton is being clicked */ - data class ReadAccess( - override val titleResId: Int, + data class Read( override val onBackButtonClick: () -> Unit, + override val titleResId: Int, override val onSearchButtonClick: () -> Unit, ) : Title /** - * Title state that is available for read and edit + * Title state that is available for read and manage * - * @property titleResId toolbar title id from resources * @property onBackButtonClick callback to be invoked when BackButton is being clicked + * @property titleResId toolbar title id from resources * @property onSearchButtonClick callback to be invoked when SearchButton is being clicked * @property onAddCustomTokenClick callback to be invoked when AddCustomTokenButton is being clicked */ - data class ManageAccess( - override val titleResId: Int, + data class Manage( override val onBackButtonClick: () -> Unit, + override val titleResId: Int, override val onSearchButtonClick: () -> Unit, val onAddCustomTokenClick: () -> Unit, ) : Title @@ -47,15 +47,13 @@ sealed interface TokensListToolbarState { /** * Toolbar state as input field * - * @property onBackButtonClick callback to be invoked when BackButton is being clicked - * @property onSearchButtonClick callback to be invoked when SearchButton is being clicked - * @property value input value - * @property onValueChange lambda to be invoked when search value is being changed - * @property onCleanButtonClick callback to be invoked when CleanButton is being clicked + * @property onBackButtonClick callback to be invoked when BackButton is being clicked + * @property value input value + * @property onValueChange lambda to be invoked when search value is being changed + * @property onCleanButtonClick callback to be invoked when CleanButton is being clicked */ - data class SearchInputField( + data class InputField( override val onBackButtonClick: () -> Unit, - override val onSearchButtonClick: () -> Unit, val value: String, val onValueChange: (String) -> Unit, val onCleanButtonClick: () -> Unit, diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListVisibility.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListVisibility.kt deleted file mode 100644 index 4062066ad3..0000000000 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListVisibility.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.tap.features.tokens.presentation.states - -import kotlinx.collections.immutable.ImmutableList - -/** Marker interface for states that have a list of tokens */ -sealed interface TokensListVisibility { - - /** Tokens list */ - val tokens: ImmutableList -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt index e44b3def87..bd3605c70e 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt @@ -53,7 +53,7 @@ internal fun BriefNetworksList( internal fun BriefNetworkItem(model: NetworkItemState) { Box(modifier = Modifier.size(size = TangemTheme.dimens.size20)) { Image( - painter = painterResource(id = model.iconResId), + painter = painterResource(id = model.iconResId.value), contentDescription = null, modifier = Modifier.size(size = TangemTheme.dimens.size20), ) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt index e404aec20e..bdf39d31e9 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.unit.sp import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.features.tokens.presentation.states.NetworkItemState +import com.tangem.tap.features.tokens.presentation.states.TokenItemState import kotlinx.collections.immutable.ImmutableCollection /** @@ -43,7 +44,7 @@ import kotlinx.collections.immutable.ImmutableCollection @Composable internal fun DetailedNetworksList( isExpanded: Boolean, - tokenId: String?, + token: TokenItemState, networks: ImmutableCollection, modifier: Modifier = Modifier, ) { @@ -56,7 +57,7 @@ internal fun DetailedNetworksList( Column { networks.forEachIndexed { index, network -> key(network.name) { - DetailedNetworkItem(model = network, tokenId = tokenId, isLastItem = networks.size - 1 == index) + DetailedNetworkItem(token = token, network = network, isLastItem = networks.size - 1 == index) } } } @@ -65,18 +66,18 @@ internal fun DetailedNetworksList( @OptIn(ExperimentalFoundationApi::class) @Composable -private fun DetailedNetworkItem(model: NetworkItemState, tokenId: String?, isLastItem: Boolean) { +private fun DetailedNetworkItem(token: TokenItemState, network: NetworkItemState, isLastItem: Boolean) { val clipboardManager = LocalClipboardManager.current val itemHeight = TangemTheme.dimens.size50 Row( modifier = Modifier .combinedClickable( - enabled = model is NetworkItemState.ManageAccess, + enabled = network is NetworkItemState.ManageContent, onLongClick = { - if (model is NetworkItemState.ManageAccess && model.contractAddress != null) { - clipboardManager.setText(AnnotatedString(text = model.contractAddress)) - model.onNetworkClick() + if (network is NetworkItemState.ManageContent && network.address != null) { + clipboardManager.setText(AnnotatedString(text = network.address)) + network.onNetworkClick() } }, onClick = {}, @@ -90,14 +91,19 @@ private fun DetailedNetworkItem(model: NetworkItemState, tokenId: String?, isLas ) { NetworkItemArrow(itemHeight = itemHeight, isLastItem = isLastItem) Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing16)) - BriefNetworkItem(model = model) + BriefNetworkItem(model = network) Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing6)) - NetworkTitle(model = model) + NetworkTitle(model = network) - if (model is NetworkItemState.ManageAccess) { + if (network is NetworkItemState.ManageContent) { Switch( - checked = model.isAdded, - onCheckedChange = { model.onToggleClick(requireNotNull(tokenId), model.networkId) }, + checked = network.isAdded.value, + onCheckedChange = { + network.onToggleClick( + requireNotNull(token as? TokenItemState.ManageContent), + network, + ) + }, modifier = Modifier.padding(start = TangemTheme.dimens.spacing16, end = TangemTheme.dimens.spacing8), colors = SwitchDefaults.colors( checkedThumbColor = TangemColorPalette.Meadow, @@ -125,7 +131,7 @@ private fun RowScope.NetworkTitle(model: NetworkItemState) { }, fontWeight = FontWeight.SemiBold, fontSize = 13.sp, - color = if (model is NetworkItemState.ManageAccess && model.isAdded) { + color = if (model is NetworkItemState.ManageContent && model.isAdded.value) { TangemColorPalette.Black } else { TangemColorPalette.Dark2 @@ -139,7 +145,7 @@ private fun Preview_DetailedNetworksList_ManageAccess() { TangemTheme { DetailedNetworksList( isExpanded = true, - tokenId = null, + token = TokenListPreviewData.createManageToken(), networks = TokenListPreviewData.createManageNetworksList(), ) } @@ -151,7 +157,7 @@ private fun Preview_DetailedNetworksList_ReadAccess() { TangemTheme { DetailedNetworksList( isExpanded = true, - tokenId = null, + token = TokenListPreviewData.createReadToken(), networks = TokenListPreviewData.createReadNetworksList(), ) } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt index ba0b7959ec..bd6b760fd5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt @@ -46,7 +46,7 @@ import com.tangem.wallet.R */ @Composable internal fun TokenItem(model: TokenItemState) { - var isExpanded by rememberSaveable { mutableStateOf(false) } + var isExpanded by rememberSaveable { mutableStateOf(value = false) } ConstraintLayout( modifier = Modifier @@ -101,7 +101,7 @@ internal fun TokenItem(model: TokenItemState) { DetailedNetworksList( isExpanded = isExpanded, - tokenId = (model as? TokenItemState.ManageAccess)?.id, + token = model, networks = model.networks, modifier = Modifier.constrainAs(detailedNetworksList) { top.linkTo(anchor = availableNetworksText.bottom, margin = spacing16) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt index 8eb5cd50ee..efed29fd37 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt @@ -1,5 +1,7 @@ package com.tangem.tap.features.tokens.presentation.ui +import androidx.compose.runtime.mutableStateOf +import com.tangem.blockchain.common.Blockchain import com.tangem.tap.features.tokens.presentation.states.NetworkItemState import com.tangem.tap.features.tokens.presentation.states.TokenItemState import com.tangem.wallet.R @@ -11,62 +13,67 @@ import kotlinx.collections.immutable.persistentListOf */ object TokenListPreviewData { - fun createManageToken(): TokenItemState.ManageAccess { - return TokenItemState.ManageAccess( + fun createManageToken(): TokenItemState.ManageContent { + return TokenItemState.ManageContent( name = "Tether (USDT)", iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", networks = createManageNetworksList(), id = "", + symbol = "", ) } - fun createReadToken(): TokenItemState.ReadAccess { - return TokenItemState.ReadAccess( + fun createReadToken(): TokenItemState.ReadContent { + return TokenItemState.ReadContent( name = "Tether (USDT)", iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", networks = createReadNetworksList(), ) } - fun createManageNetworksList(): ImmutableList { + fun createManageNetworksList(): ImmutableList { return persistentListOf( - NetworkItemState.ManageAccess( + NetworkItemState.ManageContent( name = "Ethereum", protocolName = "MAIN", - iconResId = R.drawable.ic_eth_no_color, + iconResId = mutableStateOf(R.drawable.ic_eth_no_color), isMainNetwork = true, - isAdded = true, - networkId = "", - contractAddress = null, + isAdded = mutableStateOf(true), + id = "", + address = null, onToggleClick = { _, _ -> }, onNetworkClick = {}, + decimalCount = null, + blockchain = Blockchain.Ethereum, ), - NetworkItemState.ManageAccess( + NetworkItemState.ManageContent( name = "BNB SMART CHAIN", protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_no_color, + iconResId = mutableStateOf(R.drawable.ic_bsc_no_color), isMainNetwork = false, - isAdded = false, - networkId = "", - contractAddress = null, + isAdded = mutableStateOf(false), + id = "", + address = null, onToggleClick = { _, _ -> }, onNetworkClick = {}, + decimalCount = null, + blockchain = Blockchain.BSC, ), ) } - fun createReadNetworksList(): ImmutableList { + fun createReadNetworksList(): ImmutableList { return persistentListOf( - NetworkItemState.ReadAccess( + NetworkItemState.ReadContent( name = "Ethereum", protocolName = "MAIN", - iconResId = R.drawable.ic_eth_no_color, + iconResId = mutableStateOf(R.drawable.ic_eth_no_color), isMainNetwork = true, ), - NetworkItemState.ReadAccess( + NetworkItemState.ReadContent( name = "BNB SMART CHAIN", protocolName = "BEP20", - iconResId = R.drawable.ic_bsc_no_color, + iconResId = mutableStateOf(R.drawable.ic_bsc_no_color), isMainNetwork = false, ), ) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt similarity index 60% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt rename to app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt index a691d057e6..977e5705bf 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt @@ -12,58 +12,55 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.FabPosition import androidx.compose.material.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.paging.PagingData +import androidx.paging.compose.LazyPagingItems +import androidx.paging.compose.collectAsLazyPagingItems +import androidx.paging.compose.items import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.common.compose.extensions.OnBottomReached import com.tangem.tap.features.tokens.presentation.states.TokenItemState import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState -import com.tangem.tap.features.tokens.presentation.states.TokensListVisibility -import com.tangem.tap.features.tokens.redux.TokensAction -import com.tangem.tap.store import com.tangem.wallet.R -import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flow /** [REDACTED_AUTHOR] */ @Composable -internal fun AddTokensScreen(stateHolder: TokensListStateHolder) { +internal fun TokensListScreen(stateHolder: TokensListStateHolder) { BackHandler(onBack = stateHolder.toolbarState.onBackButtonClick) Scaffold( - topBar = { AddTokensToolbar(state = stateHolder.toolbarState) }, + topBar = { TokensListToolbar(state = stateHolder.toolbarState) }, floatingActionButton = { - if (stateHolder is TokensListStateHolder.ManageAccess) { + if (stateHolder is TokensListStateHolder.ManageContent) { SaveChangesButton(onClick = stateHolder.onSaveButtonClick) } }, floatingActionButtonPosition = FabPosition.Center, ) { scaffoldPadding -> - // This is a hack because AnimatedContent trigger recomposition if stateHolder content is changed - AnimatedVisibility( - visible = stateHolder is TokensListVisibility, - enter = fadeIn(), - exit = fadeOut(), - ) { - if (stateHolder is TokensListVisibility) { - TokensListContent( - stateHolder = stateHolder, - scaffoldPadding = scaffoldPadding, - ) - } - } + val tokens = stateHolder.tokens.collectAsLazyPagingItems() + + TokensListContent( + tokens = tokens, + scaffoldPadding = scaffoldPadding, + ) + + stateHolder.onTokensLoadStateChanged(tokens.loadState.refresh) AnimatedVisibility( visible = stateHolder is TokensListStateHolder.Loading, @@ -87,24 +84,24 @@ private fun LoadingContent() { } } +@OptIn(ExperimentalComposeUiApi::class) @Composable -private fun TokensListContent(stateHolder: TokensListVisibility, scaffoldPadding: PaddingValues) { - val state = rememberLazyListState().apply { - OnBottomReached(loadMoreThreshold = 40) { - store.dispatch(TokensAction.LoadMore(scanResponse = store.state.globalState.scanResponse)) - } +private fun TokensListContent(tokens: LazyPagingItems, scaffoldPadding: PaddingValues) { + val state = rememberLazyListState() + + if (state.isScrollInProgress) { + LocalSoftwareKeyboardController.current?.hide() } + LazyColumn( modifier = Modifier .fillMaxSize() .padding(scaffoldPadding), - state, + state = state, ) { - items( - items = stateHolder.tokens, - key = TokenItemState::name, - itemContent = { TokenItem(model = it) }, - ) + items(items = tokens, key = TokenItemState::name) { + it?.let { TokenItem(model = it) } + } } } @@ -122,16 +119,18 @@ private fun SaveChangesButton(onClick: () -> Unit) { @Preview @Composable -private fun Preview_AddTokensScreen_Loading() { +private fun Preview_TokensListScreen_Loading() { TangemTheme { - AddTokensScreen( + TokensListScreen( stateHolder = TokensListStateHolder.Loading( - toolbarState = TokensListToolbarState.Title.ManageAccess( + toolbarState = TokensListToolbarState.Title.Manage( titleResId = R.string.main_manage_tokens, onBackButtonClick = {}, onSearchButtonClick = {}, onAddCustomTokenClick = {}, ), + tokens = emptyFlow(), + onTokensLoadStateChanged = {}, ), ) } @@ -139,21 +138,28 @@ private fun Preview_AddTokensScreen_Loading() { @Preview @Composable -private fun Preview_AddTokensScreen_ManageAccess() { +private fun Preview_TokensListScreen_Manage() { TangemTheme { - AddTokensScreen( - stateHolder = TokensListStateHolder.ManageAccess( - toolbarState = TokensListToolbarState.Title.ManageAccess( + TokensListScreen( + stateHolder = TokensListStateHolder.ManageContent( + toolbarState = TokensListToolbarState.Title.Manage( titleResId = R.string.main_manage_tokens, onBackButtonClick = {}, onSearchButtonClick = {}, onAddCustomTokenClick = {}, ), - tokens = persistentListOf( - TokenListPreviewData.createManageToken(), - TokenListPreviewData.createManageToken(), - ), + tokens = flow { + emit( + PagingData.from( + listOf( + TokenListPreviewData.createManageToken(), + TokenListPreviewData.createManageToken(), + ), + ), + ) + }, onSaveButtonClick = {}, + onTokensLoadStateChanged = {}, ), ) } @@ -161,19 +167,26 @@ private fun Preview_AddTokensScreen_ManageAccess() { @Preview @Composable -private fun Preview_AddTokensScreen_ReadAccess() { +private fun Preview_TokensListScreen_Read() { TangemTheme { - AddTokensScreen( - stateHolder = TokensListStateHolder.ReadAccess( - toolbarState = TokensListToolbarState.Title.ReadAccess( + TokensListScreen( + stateHolder = TokensListStateHolder.ReadContent( + toolbarState = TokensListToolbarState.Title.Read( titleResId = R.string.search_tokens_title, onBackButtonClick = {}, onSearchButtonClick = {}, ), - tokens = persistentListOf( - TokenListPreviewData.createReadToken(), - TokenListPreviewData.createReadToken(), - ), + tokens = flow { + emit( + PagingData.from( + listOf( + TokenListPreviewData.createManageToken(), + TokenListPreviewData.createManageToken(), + ), + ), + ) + }, + onTokensLoadStateChanged = {}, ), ) } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListToolbar.kt similarity index 91% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt rename to app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListToolbar.kt index a79d8cb8b4..f3bb8bbafd 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/AddTokensToolbar.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListToolbar.kt @@ -34,7 +34,7 @@ import androidx.compose.ui.unit.sp import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState -import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState.SearchInputField +import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState.InputField import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState.Title import com.tangem.wallet.R import kotlinx.coroutines.delay @@ -43,7 +43,7 @@ import kotlinx.coroutines.delay [REDACTED_AUTHOR] */ @Composable -internal fun AddTokensToolbar(state: TokensListToolbarState) { +internal fun TokensListToolbar(state: TokensListToolbarState) { TopAppBar(backgroundColor = TangemTheme.colors.background.secondary) { IconButton(onClick = state.onBackButtonClick) { Icon( @@ -55,7 +55,7 @@ internal fun AddTokensToolbar(state: TokensListToolbarState) { when (state) { is Title -> TitleContent(state = state, modifier = Modifier.weight(1f)) - is SearchInputField -> InputContent(state = state, modifier = Modifier.weight(1f)) + is InputField -> InputContent(state = state, modifier = Modifier.weight(1f)) } } } @@ -78,7 +78,7 @@ private fun TitleContent(state: Title, modifier: Modifier = Modifier) { ) } - if (state is Title.ManageAccess) { + if (state is Title.Manage) { IconButton(onClick = state.onAddCustomTokenClick) { Icon( painter = painterResource(id = R.drawable.ic_plus_24), @@ -91,8 +91,9 @@ private fun TitleContent(state: Title, modifier: Modifier = Modifier) { @OptIn(ExperimentalComposeUiApi::class) @Composable -private fun InputContent(state: SearchInputField, modifier: Modifier = Modifier) { +private fun InputContent(state: InputField, modifier: Modifier = Modifier) { val focusRequester = remember { FocusRequester() } + val keyboardController = LocalSoftwareKeyboardController.current BasicTextField( value = state.value, @@ -100,7 +101,7 @@ private fun InputContent(state: SearchInputField, modifier: Modifier = Modifier) modifier = modifier.focusRequester(focusRequester), textStyle = TangemTheme.typography.subtitle1.copy(fontWeight = FontWeight.Normal), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Search), - keyboardActions = KeyboardActions(onSearch = { state.onSearchButtonClick() }), + keyboardActions = KeyboardActions(onSearch = { keyboardController?.hide() }), singleLine = true, maxLines = 1, cursorBrush = SolidColor(value = TangemTheme.colors.stroke.secondary), @@ -168,8 +169,8 @@ private fun Hint(value: String) { @Composable private fun Preview_AddTokensToolbar_EditAccess() { TangemTheme { - AddTokensToolbar( - state = Title.ManageAccess( + TokensListToolbar( + state = Title.Manage( titleResId = R.string.main_manage_tokens, onBackButtonClick = {}, onSearchButtonClick = {}, @@ -183,8 +184,8 @@ private fun Preview_AddTokensToolbar_EditAccess() { @Composable private fun Preview_AddTokensToolbar_ReadAccess() { TangemTheme { - AddTokensToolbar( - state = Title.ReadAccess( + TokensListToolbar( + state = Title.Read( titleResId = R.string.search_tokens_title, onBackButtonClick = {}, onSearchButtonClick = {}, @@ -199,10 +200,9 @@ private fun Preview_AddTokensToolbar_SearchInputField() { var value by remember { mutableStateOf("") } TangemTheme { - AddTokensToolbar( - state = SearchInputField( + TokensListToolbar( + state = InputField( onBackButtonClick = {}, - onSearchButtonClick = {}, value = value, onValueChange = { value = it }, onCleanButtonClick = { value = "" }, diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListAnalyticsSender.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListAnalyticsSender.kt new file mode 100644 index 0000000000..615f039a8f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListAnalyticsSender.kt @@ -0,0 +1,59 @@ +package com.tangem.tap.features.tokens.presentation.viewmodels + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.ManageTokens + +/** Analytics sender for tokens list screen */ +class TokensListAnalyticsSender(private val analyticsEventHandler: AnalyticsEventHandler) { + + fun sendWhenTokenAdded(token: Token) { + analyticsEventHandler.send( + event = ManageTokens.TokenSwitcherChanged( + type = AnalyticsParam.CurrencyType.Token(token), + state = AnalyticsParam.OnOffState.On, + ), + ) + } + + fun sendWhenBlockchainAdded(blockchain: Blockchain) { + analyticsEventHandler.send( + event = ManageTokens.TokenSwitcherChanged( + type = AnalyticsParam.CurrencyType.Blockchain(blockchain), + state = AnalyticsParam.OnOffState.On, + ), + ) + } + + fun sendWhenTokenRemoved(token: Token) { + analyticsEventHandler.send( + event = ManageTokens.TokenSwitcherChanged( + type = AnalyticsParam.CurrencyType.Token(token), + state = AnalyticsParam.OnOffState.Off, + ), + ) + } + + fun sendWhenBlockchainRemoved(blockchain: Blockchain) { + analyticsEventHandler.send( + event = ManageTokens.TokenSwitcherChanged( + type = AnalyticsParam.CurrencyType.Blockchain(blockchain), + state = AnalyticsParam.OnOffState.Off, + ), + ) + } + + fun sendWhenSaveButtonClicked() { + analyticsEventHandler.send(ManageTokens.ButtonSaveChanges()) + } + + fun sendWhenTokenSearched() { + analyticsEventHandler.send(ManageTokens.TokenSearched()) + } + + fun sendWhenAddCustomTokenClicked() { + analyticsEventHandler.send(ManageTokens.ButtonCustomToken()) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt index a56973ee89..d09d68b5d5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt @@ -3,27 +3,26 @@ package com.tangem.tap.features.tokens.presentation.viewmodels import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.paging.LoadState +import androidx.paging.PagingData +import androidx.paging.map import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.Token -import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.extensions.getActiveIconRes +import com.tangem.domain.common.extensions.canHandleToken import com.tangem.domain.common.extensions.fromNetworkId -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.extensions.fullNameWithoutTestnet import com.tangem.tap.common.extensions.getGreyedOutIconRes import com.tangem.tap.common.extensions.getNetworkName import com.tangem.tap.common.redux.AppDialog -import com.tangem.tap.common.redux.AppState -import com.tangem.tap.domain.tokens.Contract -import com.tangem.tap.domain.tokens.Currency +import com.tangem.tap.features.tokens.domain.TokensListInteractor +import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.domain.models.Token.Network +import com.tangem.tap.features.tokens.presentation.models.TokensListArgs import com.tangem.tap.features.tokens.presentation.router.TokensListRouter import com.tangem.tap.features.tokens.presentation.states.NetworkItemState import com.tangem.tap.features.tokens.presentation.states.TokenItemState @@ -31,317 +30,328 @@ import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState import com.tangem.tap.features.tokens.redux.TokenWithBlockchain import com.tangem.tap.features.tokens.redux.TokensAction -import com.tangem.tap.features.tokens.redux.TokensState -import com.tangem.tap.features.tokens.ui.compose.fullName import com.tangem.tap.features.wallet.redux.models.WalletDialog +import com.tangem.tap.proxy.AppStateHolder import com.tangem.tap.store import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider +import com.tangem.utils.coroutines.Debouncer import com.tangem.wallet.R import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.rekotlin.StoreSubscriber +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.plus import javax.inject.Inject +import com.tangem.blockchain.common.Token as BlockchainToken /** - * ViewModel for add tokens screen + * ViewModel for tokens list screen * - * @property router feature router - * @property dispatchers coroutine dispatchers provider + * @property interactor feature interactor + * @property router feature router + * @property dispatchers coroutine dispatchers provider + * @property reduxStateHolder redux state holder + * @param analyticsEventHandler analytics event handler * [REDACTED_AUTHOR] */ @HiltViewModel internal class TokensListViewModel @Inject constructor( + private val interactor: TokensListInteractor, private val router: TokensListRouter, private val dispatchers: AppCoroutineDispatcherProvider, + private val reduxStateHolder: AppStateHolder, + analyticsEventHandler: AnalyticsEventHandler, ) : ViewModel() { - private val uiStateBuilder = UiStateBuilder() + private val args = TokensListArgs() + private val analyticsSender = TokensListAnalyticsSender(analyticsEventHandler) + private val actionsHandler = ActionsHandler(router = router, debouncer = Debouncer()) - var uiState by mutableStateOf(uiStateBuilder.getInitialUiState()) + /** Screen state */ + var uiState by mutableStateOf(value = getInitialUiState()) private set - private val reduxSubscriber = ReduxSubscriber() - private var debounceJob: Job? = null + private val addedTokenList: MutableList = args.mainScreenTokenList.toMutableList() + private val addedBlockchainList: MutableList = args.mainScreenBlockchainList.toMutableList() - private var originalAddedTokenList: List? = null - private var originalAddedBlockchainList: List? = null - private var addedTokenList: List? = null - private var addedBlockchainList: List? = null - - fun subscribeOnReduxEvents(lifecycle: Lifecycle) { - lifecycle.addObserver(reduxSubscriber) + private fun getInitialUiState(): TokensListStateHolder { + return TokensListStateHolder.Loading( + toolbarState = getInitialToolbarState(), + tokens = getInitialTokensList(), + onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged, + ) } - private object AnalyticsSender { - fun sendWhenTokenAdded(token: Token) { - Analytics.send( - event = ManageTokens.TokenSwitcherChanged( - type = AnalyticsParam.CurrencyType.Token(token), - state = AnalyticsParam.OnOffState.On, - ), + private fun getInitialToolbarState(): TokensListToolbarState { + return if (args.isManageAccess) { + TokensListToolbarState.Title.Manage( + titleResId = R.string.main_manage_tokens, + onBackButtonClick = actionsHandler::onBackButtonClick, + onSearchButtonClick = actionsHandler::onSearchButtonClick, + onAddCustomTokenClick = actionsHandler::onAddCustomTokenClick, ) - } - - fun sendWhenBlockchainAdded(blockchain: Blockchain) { - Analytics.send( - event = ManageTokens.TokenSwitcherChanged( - type = AnalyticsParam.CurrencyType.Blockchain(blockchain), - state = AnalyticsParam.OnOffState.On, - ), + } else { + TokensListToolbarState.Title.Read( + titleResId = R.string.search_tokens_title, + onBackButtonClick = actionsHandler::onBackButtonClick, + onSearchButtonClick = actionsHandler::onSearchButtonClick, ) } - - fun sendWhenTokenRemoved(token: Token) { - Analytics.send( - event = ManageTokens.TokenSwitcherChanged( - type = AnalyticsParam.CurrencyType.Token(token), - state = AnalyticsParam.OnOffState.Off, - ), - ) - } - - fun sendWhenBlockchainRemoved(blockchain: Blockchain) { - Analytics.send( - event = ManageTokens.TokenSwitcherChanged( - type = AnalyticsParam.CurrencyType.Blockchain(blockchain), - state = AnalyticsParam.OnOffState.Off, - ), - ) - } - - fun sendWhenSaveButtonClicked() { - Analytics.send(ManageTokens.ButtonSaveChanges()) - } } - private inner class ReduxSubscriber : DefaultLifecycleObserver, StoreSubscriber { - - override fun onStart(owner: LifecycleOwner) { - store.subscribe( - subscriber = this, - transform = { state -> - state - .skipRepeats { old, new -> old.tokensState == new.tokensState } - .select(AppState::tokensState) - }, - ) - } - - override fun onStop(owner: LifecycleOwner) { - store.unsubscribe(subscriber = this) - } - - override fun newState(state: TokensState) { - val isNotOriginalListsInitialized = originalAddedTokenList == null || originalAddedBlockchainList == null - val isNotCurrentListsInitialized = addedTokenList == null || addedBlockchainList == null - - if (isNotOriginalListsInitialized || isNotCurrentListsInitialized) { - originalAddedTokenList = state.addedTokens - originalAddedBlockchainList = state.addedBlockchains - addedTokenList = state.addedTokens - addedBlockchainList = state.addedBlockchains + private fun getInitialTokensList(searchText: String = ""): Flow> { + return interactor.getTokensList(searchText = searchText).map { + it.map { token -> + if (args.isManageAccess) createManageTokenContent(token) else createReadTokenContent(token) } - - uiStateBuilder.updateStateByReduxState(state) } } - private inner class UiStateBuilder { + private fun createManageTokenContent(token: Token): TokenItemState.ManageContent { + return TokenItemState.ManageContent( + name = getTokenName(token), + iconUrl = token.iconUrl, + networks = token.networks.map(::createManageNetworkContent).toImmutableList(), + id = token.id, + symbol = token.symbol, + ) + } - fun getInitialUiState(): TokensListStateHolder { - return TokensListStateHolder.Loading(toolbarState = getToolbarState()) + private fun createManageNetworkContent(network: Network): NetworkItemState.ManageContent { + return NetworkItemState.ManageContent( + name = network.blockchain.fullNameWithoutTestnet.uppercase(), + protocolName = getNetworkProtocolName(network), + iconResId = mutableStateOf( + getNetworkIconResId(network.address, network.blockchain), + ), + isMainNetwork = isMainNetwork(network), + isAdded = mutableStateOf( + isAdded(address = network.address, blockchain = network.blockchain), + ), + id = network.id, + address = network.address, + decimalCount = network.decimalCount, + blockchain = network.blockchain, + onToggleClick = actionsHandler::onToggleClick, + onNetworkClick = actionsHandler::onNetworkClick, + ) + } + + private fun createReadTokenContent(token: Token): TokenItemState.ReadContent { + return TokenItemState.ReadContent( + name = getTokenName(token), + iconUrl = token.iconUrl, + networks = token.networks.map(::createReadNetworkContent).toImmutableList(), + ) + } + + private fun createReadNetworkContent(network: Network): NetworkItemState.ReadContent { + return NetworkItemState.ReadContent( + name = network.blockchain.fullNameWithoutTestnet.uppercase(), + protocolName = getNetworkProtocolName(network), + iconResId = mutableStateOf(getNetworkIconResId(network.address, network.blockchain)), + isMainNetwork = isMainNetwork(network), + ) + } + + private fun getTokenName(token: Token) = "${token.name} (${token.symbol})" + + private fun getNetworkProtocolName(network: Network): String { + return if (network.address == null) { + MAIN_NETWORK_LABEL + } else { + network.blockchain.getNetworkName().uppercase() + } + } + + private fun getNetworkIconResId(address: String?, blockchain: Blockchain): Int { + return if (isAdded(address = address, blockchain = blockchain)) { + getActiveIconRes(blockchain.id) + } else { + blockchain.getGreyedOutIconRes() + } + } + + private fun isMainNetwork(network: Network) = network.address == null + + private fun isAdded(address: String?, blockchain: Blockchain?): Boolean { + return if (address != null) { + addedTokenList.any { addedToken -> + address == addedToken.token.contractAddress && blockchain == addedToken.blockchain + } + } else { + addedBlockchainList.contains(blockchain) + } + } + + private inner class ActionsHandler( + private val router: TokensListRouter, + private val debouncer: Debouncer, + ) { + + fun onBackButtonClick() { + router.popBackStack() } - fun updateStateByReduxState(state: TokensState) { - uiState = if (state.currencies.isEmpty()) { - TokensListStateHolder.Loading(toolbarState = getToolbarState(reduxState = state)) - } else if (state.allowToAdd) { - TokensListStateHolder.ManageAccess( - toolbarState = getToolbarState(reduxState = state), - tokens = state.currencies.map(::toManageTokenItemState).toImmutableList(), - onSaveButtonClick = { - val notNullAddedTokens = addedTokenList ?: return@ManageAccess - val notNullAddedBlockchains = addedBlockchainList ?: return@ManageAccess + fun onSearchButtonClick() { + uiState = uiState.copySealed( + toolbarState = TokensListToolbarState.InputField( + onBackButtonClick = this::onBackButtonClick, + value = "", + onValueChange = this::onSearchValueChange, + onCleanButtonClick = this::onCleanButtonClick, + ), + ) + } - AnalyticsSender.sendWhenSaveButtonClicked() - store.dispatch(TokensAction.SaveChanges(notNullAddedTokens, notNullAddedBlockchains)) - }, - ) + fun onAddCustomTokenClick() { + analyticsSender.sendWhenAddCustomTokenClicked() + router.openAddCustomTokenScreen() + } + + fun onToggleClick(toggledToken: TokenItemState.ManageContent, toggledNetwork: NetworkItemState.ManageContent) { + val blockchain = Blockchain.fromNetworkId( + networkId = if (toggledNetwork.address == null) toggledNetwork.id else toggledToken.id, + ) + if (toggledNetwork.address == null && blockchain != null) { + updateBlockchainItem(toggledNetwork, blockchain) } else { - TokensListStateHolder.ReadAccess( - toolbarState = getToolbarState(state), - tokens = state.currencies.map(::toReadTokenItemState).toImmutableList(), - ) + updateTokenItem(toggledToken, toggledNetwork) } } - private fun getToolbarState(reduxState: TokensState = store.state.tokensState): TokensListToolbarState { - val toolbarState = uiState.toolbarState - - return if (reduxState.searchInput != null && toolbarState is TokensListToolbarState.SearchInputField) { - TokensListToolbarState.SearchInputField( - onBackButtonClick = router::popBackStack, - onSearchButtonClick = ::onSearchButtonClick, - value = toolbarState.value, - onValueChange = ::onSearchValueChange, - onCleanButtonClick = ::onCleanButtonClick, - ) - } else if (reduxState.allowToAdd) { - TokensListToolbarState.Title.ManageAccess( - titleResId = R.string.main_manage_tokens, - onBackButtonClick = router::popBackStack, - onSearchButtonClick = ::onSearchButtonClick, - onAddCustomTokenClick = router::openAddCustomTokenScreen, - ) - } else { - TokensListToolbarState.Title.ReadAccess( - titleResId = R.string.search_tokens_title, - onBackButtonClick = router::popBackStack, - onSearchButtonClick = ::onSearchButtonClick, - ) - } + // FIXME("Necessary to avoid using redux actions") + fun onNetworkClick() { + store.dispatchNotification(R.string.contract_address_copied_message) } - private fun onSearchButtonClick() { - uiState = when (val state = uiState.toolbarState) { - is TokensListToolbarState.Title -> { - uiState.copySealed( - toolbarState = TokensListToolbarState.SearchInputField( - onBackButtonClick = uiState.toolbarState.onBackButtonClick, - onSearchButtonClick = uiState.toolbarState.onSearchButtonClick, - value = "", - onValueChange = ::onSearchValueChange, - onCleanButtonClick = ::onCleanButtonClick, - ), - ) + fun onTokensLoadStateChanged(state: LoadState) { + uiState = when (state) { + is LoadState.NotLoading -> { + analyticsSender.sendWhenTokenSearched() + + if (args.isManageAccess) { + TokensListStateHolder.ManageContent( + toolbarState = uiState.toolbarState, + tokens = uiState.tokens, + onTokensLoadStateChanged = uiState.onTokensLoadStateChanged, + onSaveButtonClick = this::onSaveButtonClick, + ) + } else { + TokensListStateHolder.ReadContent( + toolbarState = uiState.toolbarState, + tokens = uiState.tokens, + onTokensLoadStateChanged = uiState.onTokensLoadStateChanged, + ) + } } - is TokensListToolbarState.SearchInputField -> { - store.dispatch(TokensAction.SetSearchInput(searchInput = state.value)) - uiState.copySealed(toolbarState = getToolbarState()) + else -> { + TokensListStateHolder.Loading( + toolbarState = uiState.toolbarState, + tokens = uiState.tokens, + onTokensLoadStateChanged = uiState.onTokensLoadStateChanged, + ) } } } private fun onSearchValueChange(newValue: String) { - (uiState.toolbarState as? TokensListToolbarState.SearchInputField)?.let { state -> - uiState = uiState.copySealed(toolbarState = state.copy(value = newValue)) - } + val state = requireNotNull(uiState.toolbarState as? TokensListToolbarState.InputField) + uiState = uiState.copySealed(toolbarState = state.copy(value = newValue)) - debounceJob?.cancel() - debounceJob = viewModelScope.launch(dispatchers.io) { - delay(timeMillis = 800L) - store.dispatch(TokensAction.SetSearchInput(searchInput = newValue)) + debouncer.debounce(waitMs = 800L, coroutineScope = viewModelScope + dispatchers.io) { + uiState = uiState.copySealed(tokens = getInitialTokensList(newValue)) } } private fun onCleanButtonClick() { - (uiState.toolbarState as? TokensListToolbarState.SearchInputField)?.let { state -> - if (state.value.isEmpty()) { - uiState = uiState.copySealed(toolbarState = getToolbarState()) - } else { - onSearchValueChange(newValue = "") - } + val state = requireNotNull(uiState.toolbarState as? TokensListToolbarState.InputField) + + if (state.value.isEmpty()) { + uiState = uiState.copySealed(toolbarState = getInitialToolbarState()) + } else { + onSearchValueChange(newValue = "") } } - private fun onToggleClick(tokenId: String, networkId: String) { - (uiState as? TokensListStateHolder.ManageAccess)?.let { state -> - val switchedToken = state.tokens.firstOrNull { it.id == tokenId } - val contractAddress = switchedToken?.networks - ?.firstOrNull { it.networkId == networkId } - ?.contractAddress + private fun updateBlockchainItem(toggledNetwork: NetworkItemState.ManageContent, blockchain: Blockchain) { + val isRemoveAction = addedBlockchainList.contains(blockchain) - val blockchain = Blockchain.fromNetworkId( - networkId = if (contractAddress == null) networkId else tokenId, - ) + if (isRemoveAction) { + val isTokenWithSameBlockchainFound = addedTokenList.any { it.blockchain == blockchain } + val isAddedOnMainScreen = args.mainScreenBlockchainList.contains(blockchain) - if (blockchain != null && contractAddress == null) { - onBlockchainToggleClick(blockchain) - } else if (contractAddress != null) { - onTokenToggleClick(tokenId, networkId, switchedToken, contractAddress) - } - - updateTokensList() - } - } - - private fun onBlockchainToggleClick(blockchain: Blockchain) { - val isRemoveAction = addedBlockchainList?.contains(blockchain) - - if (isRemoveAction == true) { - val isTokenWithSameBlockchainFound = addedTokenList?.any { it.blockchain == blockchain } - val isAddedOnMainScreen = originalAddedBlockchainList?.contains(blockchain) - - if (isTokenWithSameBlockchainFound == true) { + if (isTokenWithSameBlockchainFound) { store.dispatchDialogShow( WalletDialog.TokensAreLinkedDialog( currencyTitle = blockchain.name, currencySymbol = blockchain.currency, ), ) - } else if (isAddedOnMainScreen == true) { + } else if (isAddedOnMainScreen) { store.dispatchDialogShow( WalletDialog.RemoveWalletDialog( currencyTitle = blockchain.name, onOk = { - AnalyticsSender.sendWhenBlockchainAdded(blockchain) - addedBlockchainList = addedBlockchainList?.minus(blockchain) - updateTokensList() + analyticsSender.sendWhenBlockchainAdded(blockchain) + addedBlockchainList.remove(blockchain) + toggledNetwork.changeToggleState() }, ), ) } else { - AnalyticsSender.sendWhenBlockchainRemoved(blockchain) - addedBlockchainList = addedBlockchainList?.minus(blockchain) + analyticsSender.sendWhenBlockchainRemoved(blockchain) + addedBlockchainList.remove(blockchain) + toggledNetwork.changeToggleState() } } else { - AnalyticsSender.sendWhenBlockchainAdded(blockchain) - addedBlockchainList = addedBlockchainList?.plus(blockchain) + analyticsSender.sendWhenBlockchainAdded(blockchain) + addedBlockchainList.add(blockchain) + toggledNetwork.changeToggleState() } } - private fun onTokenToggleClick( - tokenId: String, - networkId: String, - switchedToken: TokenItemState.ManageAccess, - contractAddress: String, + private fun updateTokenItem( + toggledToken: TokenItemState.ManageContent, + toggledNetwork: NetworkItemState.ManageContent, ) { - val currency = store.state.tokensState.currencies.firstOrNull { it.id == tokenId } ?: return - val contract = currency.contracts.firstOrNull { it.networkId == networkId } ?: return val token = TokenWithBlockchain( - token = Token( - id = switchedToken.id, - name = switchedToken.name, - symbol = currency.symbol, - contractAddress = contractAddress, - decimals = requireNotNull(contract.decimalCount), + token = BlockchainToken( + id = toggledToken.id, + name = toggledToken.name, + symbol = toggledToken.symbol, + contractAddress = requireNotNull(toggledNetwork.address), + decimals = requireNotNull(toggledNetwork.decimalCount), ), - blockchain = contract.blockchain, + blockchain = toggledNetwork.blockchain, ) - val isUnsupportedToken = !store.state.tokensState.canHandleToken(token) - val isRemoveAction = addedTokenList?.contains(token) - val isAddedOnMainScreen = originalAddedTokenList?.contains(token) - if (isRemoveAction == true) { - if (isAddedOnMainScreen == true) { + + val isRemoveAction = addedTokenList.contains(token) + + if (isRemoveAction) { + val isAddedOnMainScreen = args.mainScreenTokenList.contains(token) + + if (isAddedOnMainScreen) { store.dispatchDialogShow( WalletDialog.RemoveWalletDialog( currencyTitle = token.token.name, onOk = { - AnalyticsSender.sendWhenTokenRemoved(token.token) - addedTokenList = addedTokenList?.minus(token) - updateTokensList() + analyticsSender.sendWhenTokenRemoved(token.token) + addedTokenList.remove(token) + toggledNetwork.changeToggleState() }, ), ) } else { - AnalyticsSender.sendWhenTokenRemoved(token.token) - addedTokenList = addedTokenList?.minus(token) + analyticsSender.sendWhenTokenRemoved(token.token) + addedTokenList.remove(token) + toggledNetwork.changeToggleState() } } else { + val isUnsupportedToken = + !(reduxStateHolder.scanResponse?.card?.canHandleToken(token.blockchain) ?: false) + if (isUnsupportedToken) { store.dispatchDialogShow( AppDialog.SimpleOkDialogRes( @@ -350,100 +360,16 @@ internal class TokensListViewModel @Inject constructor( ), ) } else { - AnalyticsSender.sendWhenTokenAdded(token.token) - addedTokenList = addedTokenList?.plus(token) + analyticsSender.sendWhenTokenAdded(token.token) + addedTokenList.add(token) + toggledNetwork.changeToggleState() } } } - private fun updateTokensList() { - (uiState as? TokensListStateHolder.ManageAccess)?.let { state -> - val tokens = store.state.tokensState.currencies.mapNotNull { currency -> - state.tokens.firstOrNull { it.id == currency.id }?.copy( - networks = currency.contracts.mapNotNull { contract -> - state.tokens.firstOrNull { it.id == currency.id } - ?.networks?.firstOrNull { it.networkId == contract.networkId } - ?.copy( - isAdded = contract.isAdded(), - iconResId = if (contract.isAdded()) { - getActiveIconRes(contract.blockchain.id) - } else { - contract.blockchain.getGreyedOutIconRes() - }, - ) - }.toImmutableList(), - ) - }.toImmutableList() - - uiState = state.copy(tokens = tokens) - } - } - - private fun toManageTokenItemState(currency: Currency): TokenItemState.ManageAccess { - return TokenItemState.ManageAccess( - name = currency.fullName, - iconUrl = currency.iconUrl, - networks = currency.contracts.map(::toManageNetworkItemState).toImmutableList(), - id = currency.id, - ) - } - - private fun toManageNetworkItemState(contract: Contract): NetworkItemState.ManageAccess { - val isAdded = contract.isAdded() - return NetworkItemState.ManageAccess( - name = contract.blockchain.fullNameWithoutTestnet.uppercase(), - protocolName = if (contract.address == null) { - MAIN_NETWORK_LABEL - } else { - contract.blockchain.getNetworkName().uppercase() - }, - iconResId = if (isAdded) { - getActiveIconRes(contract.blockchain.id) - } else { - contract.blockchain.getGreyedOutIconRes() - }, - isMainNetwork = contract.address == null, - isAdded = isAdded, - networkId = contract.networkId, - contractAddress = contract.address, - onToggleClick = ::onToggleClick, - onNetworkClick = { store.dispatchNotification(R.string.contract_address_copied_message) }, - ) - } - - private fun toReadTokenItemState(currency: Currency): TokenItemState.ReadAccess { - return TokenItemState.ReadAccess( - name = currency.fullName, - iconUrl = currency.iconUrl, - networks = currency.contracts.map(::toReadNetworkItemState).toImmutableList(), - ) - } - - private fun toReadNetworkItemState(contract: Contract): NetworkItemState.ReadAccess { - return NetworkItemState.ReadAccess( - name = contract.blockchain.fullNameWithoutTestnet.uppercase(), - protocolName = if (contract.address == null) { - MAIN_NETWORK_LABEL - } else { - contract.blockchain.getNetworkName().uppercase() - }, - iconResId = if (contract.isAdded()) { - getActiveIconRes(contract.blockchain.id) - } else { - contract.blockchain.getGreyedOutIconRes() - }, - isMainNetwork = contract.address == null, - ) - } - - private fun Contract.isAdded(): Boolean { - return if (address != null) { - addedTokenList?.any { addedToken -> - address == addedToken.token.contractAddress && blockchain == addedToken.blockchain - } - } else { - addedBlockchainList?.contains(blockchain) - } ?: false + private fun onSaveButtonClick() { + analyticsSender.sendWhenSaveButtonClicked() + store.dispatch(TokensAction.SaveChanges(addedTokenList, addedBlockchainList)) } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index 9b3be6dca7..eee906b7d1 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -113,35 +113,30 @@ class TokensMiddleware { val scanResponse = store.state.globalState.scanResponse ?: return@launch val currentTokens = store.state.tokensState.addedWallets.toNonCustomTokensWithBlockchains( - scanResponse.card.derivationStyle, + derivationStyle = scanResponse.card.derivationStyle, ) val currentBlockchains = store.state.tokensState.addedWallets.toNonCustomBlockchains( - scanResponse.card.derivationStyle, + derivationStyle = scanResponse.card.derivationStyle, ) - val blockchainsToAdd = action.addedBlockchains.filter { !currentBlockchains.contains(it) } - val blockchainsToRemove = - currentBlockchains.filter { !action.addedBlockchains.contains(it) } + val blockchainsToAdd = action.addedBlockchains.filterNot(currentBlockchains::contains) + val blockchainsToRemove = currentBlockchains.filterNot(action.addedBlockchains::contains) - val tokensToAdd = action.addedTokens.filter { !currentTokens.contains(it) } - val tokensToRemove = currentTokens.filter { token -> - !action.addedTokens.any { it.token == token.token } - } - val derivationStyle = scanResponse.card.derivationStyle + val tokensToAdd = action.addedTokens.filterNot(currentTokens::contains) + val tokensToRemove = currentTokens.filterNot { token -> action.addedTokens.any { it.token == token.token } } removeCurrenciesIfNeeded( - convertToCurrencies( + currencies = convertToCurrencies( blockchains = blockchainsToRemove, tokens = tokensToRemove, - derivationStyle = derivationStyle, + derivationStyle = scanResponse.card.derivationStyle, ), ) - @Suppress("ComplexCondition") - if (tokensToAdd.isEmpty() && tokensToRemove.isEmpty() && - blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty() - ) { - store.dispatchDebugErrorNotification("Nothing to save") + val isNothingToDoWithTokens = tokensToAdd.isEmpty() && tokensToRemove.isEmpty() + val isNothingToDoWithBlockchain = blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty() + if (isNothingToDoWithTokens && isNothingToDoWithBlockchain) { + store.dispatchDebugErrorNotification(message = "Nothing to save") store.dispatchOnMain(NavigationAction.PopBackTo()) return@launch } @@ -149,8 +144,9 @@ class TokensMiddleware { val currencyList = convertToCurrencies( blockchains = blockchainsToAdd, tokens = tokensToAdd, - derivationStyle = derivationStyle, + derivationStyle = scanResponse.card.derivationStyle, ) + if (scanResponse.supportsHdWallet()) { deriveMissingBlockchains(scanResponse, currencyList) { submitAdd(it, currencyList) From 0580908dd2d4a3bd371b311287eb324303a985d1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Apr 2023 12:40:22 +0300 Subject: [PATCH 16/30] Updated on 2026-08-14 --- app/src/main/AndroidManifest.xml | 1 + .../disclaimer/ui/DisclaimerFragment.kt | 2 ++ .../main/res/layout/fragment_disclaimer.xml | 26 ++++++------------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 93e65b1cc3..7e632399d0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,6 +35,7 @@ android:supportsRtl="true" android:allowBackup="false" android:networkSecurityConfig="@xml/network_security_config" + android:hardwareAccelerated="true" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:allowBackup"> diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt index e19be8e926..62a0161bb8 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.disclaimer.ui import android.os.Bundle import android.view.View +import android.view.View.OVER_SCROLL_NEVER import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding import com.tangem.core.ui.fragments.setStatusBarColor @@ -50,6 +51,7 @@ class DisclaimerFragment : BaseFragment(R.layout.fragment_disclaimer), StoreSubs webView.apply { settings.allowFileAccess = false settings.javaScriptEnabled = false + overScrollMode = OVER_SCROLL_NEVER webViewClient = this@DisclaimerFragment.webViewClient } webView.hide() diff --git a/app/src/main/res/layout/fragment_disclaimer.xml b/app/src/main/res/layout/fragment_disclaimer.xml index e243e2e94a..328a435e5c 100644 --- a/app/src/main/res/layout/fragment_disclaimer.xml +++ b/app/src/main/res/layout/fragment_disclaimer.xml @@ -1,5 +1,5 @@ - - - - - - + app:layout_constraintTop_toTopOf="parent" /> - + From 8751486283053b8d55e2582945aed2401a16cb6e Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Apr 2023 15:10:55 +0300 Subject: [PATCH 17/30] Updated on 2026-08-14 --- .../tap/common/utils/SafeStoreSubscriber.kt | 36 +++++++++++++++++++ .../wallet/ui/WalletDetailsFragment.kt | 6 ++-- .../tap/features/wallet/ui/WalletFragment.kt | 6 ++-- gradle/dependencies.toml | 2 +- 4 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/utils/SafeStoreSubscriber.kt diff --git a/app/src/main/java/com/tangem/tap/common/utils/SafeStoreSubscriber.kt b/app/src/main/java/com/tangem/tap/common/utils/SafeStoreSubscriber.kt new file mode 100644 index 0000000000..ac430a6ea5 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/utils/SafeStoreSubscriber.kt @@ -0,0 +1,36 @@ +package com.tangem.tap.common.utils + +import android.os.Handler +import android.os.Looper +import org.rekotlin.StoreSubscriber + +private val mainLooper by lazy { Looper.getMainLooper() } +private val mainHandler by lazy { Handler(mainLooper) } + +/** + * A subscriber interface for safely subscribing to state changes in a Store. + * + * @param State the type of the state in the Store + */ +interface SafeStoreSubscriber : StoreSubscriber { + + /** + * A function that will be called when the state in the Store changes. + * + * @param state the new state in the Store + */ + override fun newState(state: State) { + if (Thread.currentThread() != mainLooper.thread) { + mainHandler.post { newStateOnMain(state) } + } else { + newStateOnMain(state) + } + } + + /** + * A function that will be called on the main thread when the state in the Store changes. + * + * @param state the new state in the Store + */ + fun newStateOnMain(state: State) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 9952836ff9..7da258be29 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -41,6 +41,7 @@ import com.tangem.tap.common.extensions.show import com.tangem.tap.common.extensions.toQrCode import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.common.utils.SafeStoreSubscriber import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction @@ -72,7 +73,6 @@ import com.tangem.wallet.databinding.FragmentWalletDetailsBinding import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import org.rekotlin.StoreSubscriber import timber.log.Timber import javax.inject.Inject @@ -80,7 +80,7 @@ import javax.inject.Inject @AndroidEntryPoint class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), - StoreSubscriber { + SafeStoreSubscriber { @Inject lateinit var swapInteractor: SwapInteractor @@ -227,7 +227,7 @@ class WalletDetailsFragment : } } - override fun newState(state: WalletState) { + override fun newStateOnMain(state: WalletState) { if (activity == null || view == null) return if (state.selectedWalletData == null) return walletStateWatcher.invoke(state) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index ca1149d987..3bf4cd8b80 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -28,6 +28,7 @@ import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction +import com.tangem.tap.common.utils.SafeStoreSubscriber import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.statePrinter.printScanResponseState import com.tangem.tap.domain.statePrinter.printWalletState @@ -46,11 +47,10 @@ import com.tangem.wallet.BuildConfig import com.tangem.wallet.R import com.tangem.wallet.databinding.FragmentWalletBinding import dagger.hilt.android.AndroidEntryPoint -import org.rekotlin.StoreSubscriber import javax.inject.Inject @AndroidEntryPoint -class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber { +class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber { @Inject lateinit var swapInteractor: SwapInteractor @@ -148,7 +148,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber Date: Thu, 13 Apr 2023 22:52:21 +0900 Subject: [PATCH 18/30] Updated on 2026-08-14 --- .../model/builders/UserWalletBuilder.kt | 46 +-------------- .../userWalletList/GetCardImageUseCase.kt | 59 +++++++++++++++++++ .../userWalletList/UserWalletsListManager.kt | 5 +- .../BiometricUserWalletsListManager.kt | 2 +- .../RuntimeUserWalletsListManager.kt | 2 +- .../tap/features/wallet/redux/WalletAction.kt | 5 ++ .../redux/middlewares/WalletMiddleware.kt | 22 +++++++ .../wallet/redux/reducers/WalletReducer.kt | 5 +- 8 files changed, 99 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/domain/userWalletList/GetCardImageUseCase.kt diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt index b74821a988..3a82b45171 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt @@ -1,22 +1,15 @@ package com.tangem.tap.domain.model.builders -import com.tangem.common.extensions.toHexString -import com.tangem.common.services.Result import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ProductType -import com.tangem.domain.common.SaltPayWorkaround import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TapWorkarounds.isStart2Coin -import com.tangem.domain.common.TwinCardNumber -import com.tangem.domain.common.TwinsHelper -import com.tangem.operations.attestation.OnlineCardVerifier -import com.tangem.operations.attestation.TangemApi import com.tangem.tap.domain.model.UserWallet -import com.tangem.tap.features.wallet.redux.Artwork +import com.tangem.tap.domain.userWalletList.GetCardImageUseCase class UserWalletBuilder( private val scanResponse: ScanResponse, - private val onlineCardVerifier: OnlineCardVerifier = OnlineCardVerifier(), + private val getCardImageUseCase: GetCardImageUseCase = GetCardImageUseCase(), ) { private var backupCardsIds: Set = emptySet() @@ -50,7 +43,7 @@ class UserWalletBuilder( UserWallet( walletId = it, name = userWalletName, - artworkUrl = loadArtworkUrl(card.cardId, card.cardPublicKey), + artworkUrl = getCardImageUseCase.invoke(card.cardId, card.cardPublicKey), cardsInWallet = backupCardsIds.plus(card.cardId), scanResponse = this, isMultiCurrency = cardTypesResolver.isMultiwalletAllowed(), @@ -58,37 +51,4 @@ class UserWalletBuilder( } } } - - private suspend fun loadArtworkUrl(cardId: String, cardPublicKey: ByteArray): String { - return when (val result = onlineCardVerifier.getCardInfo(cardId, cardPublicKey)) { - is Result.Success -> { - val artworkId = result.data.artwork?.id - if (artworkId.isNullOrEmpty()) { - getFallbackArtworkUrl(cardId) - } else { - getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId) - } - } - - is Result.Failure -> getFallbackArtworkUrl(cardId) - } - } - - private fun getFallbackArtworkUrl(cardId: String): String { - return when { - cardId.startsWith(Artwork.SERGIO_CARD_ID) -> Artwork.SERGIO_CARD_URL - cardId.startsWith(Artwork.MARTA_CARD_ID) -> Artwork.MARTA_CARD_URL - SaltPayWorkaround.isSaltPayCardId(cardId) -> Artwork.SALT_PAY_URL - else -> when (TwinsHelper.getTwinCardNumber(cardId)) { - TwinCardNumber.First -> Artwork.TWIN_CARD_1 - TwinCardNumber.Second -> Artwork.TWIN_CARD_2 - else -> Artwork.DEFAULT_IMG_URL - } - } - } - - private fun getUrlForArtwork(cardId: String, cardPublicKeyHex: String, artworkId: String): String { - return TangemApi.Companion.BaseUrl.VERIFY.url + TangemApi.ARTWORK + - "?artworkId=$artworkId&CID=$cardId&publicKey=$cardPublicKeyHex" - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/GetCardImageUseCase.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/GetCardImageUseCase.kt new file mode 100644 index 0000000000..71415134a2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/GetCardImageUseCase.kt @@ -0,0 +1,59 @@ +package com.tangem.tap.domain.userWalletList + +import com.tangem.common.extensions.toHexString +import com.tangem.common.services.Result +import com.tangem.domain.common.SaltPayWorkaround +import com.tangem.domain.common.TwinCardNumber +import com.tangem.domain.common.TwinsHelper +import com.tangem.operations.attestation.OnlineCardVerifier +import com.tangem.operations.attestation.TangemApi +import com.tangem.tap.features.wallet.redux.Artwork + +/** + * Use case for getting card image url + * + * @property verifier REST API + * +[REDACTED_AUTHOR] + */ +class GetCardImageUseCase(private val verifier: OnlineCardVerifier = OnlineCardVerifier()) { + + /** + * Get card image url + * + * @param cardId card id + * @param cardPublicKey card public key + */ + suspend operator fun invoke(cardId: String, cardPublicKey: ByteArray): String { + return when (val result = verifier.getCardInfo(cardId, cardPublicKey)) { + is Result.Success -> { + val artworkId = result.data.artwork?.id + if (artworkId.isNullOrEmpty()) { + getFallbackArtworkUrl(cardId) + } else { + getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId) + } + } + + is Result.Failure -> getFallbackArtworkUrl(cardId) + } + } + + private fun getFallbackArtworkUrl(cardId: String): String { + return when { + cardId.startsWith(Artwork.SERGIO_CARD_ID) -> Artwork.SERGIO_CARD_URL + cardId.startsWith(Artwork.MARTA_CARD_ID) -> Artwork.MARTA_CARD_URL + SaltPayWorkaround.isSaltPayCardId(cardId) -> Artwork.SALT_PAY_URL + else -> when (TwinsHelper.getTwinCardNumber(cardId)) { + TwinCardNumber.First -> Artwork.TWIN_CARD_1 + TwinCardNumber.Second -> Artwork.TWIN_CARD_2 + else -> Artwork.DEFAULT_IMG_URL + } + } + } + + private fun getUrlForArtwork(cardId: String, cardPublicKeyHex: String, artworkId: String): String { + return TangemApi.Companion.BaseUrl.VERIFY.url + TangemApi.ARTWORK + + "?artworkId=$artworkId&CID=$cardId&publicKey=$cardPublicKeyHex" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt index 4286bfd8c0..b1c97b594b 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt @@ -55,7 +55,10 @@ interface UserWalletsListManager { * @return [CompletionResult.Success] with updated [UserWallet] * or [CompletionResult.Failure] with [NoSuchElementException] if [UserWallet] with [userWalletId] not found * */ - suspend fun update(userWalletId: UserWalletId, update: (UserWallet) -> UserWallet): CompletionResult + suspend fun update( + userWalletId: UserWalletId, + update: suspend (UserWallet) -> UserWallet, + ): CompletionResult /** * Delete saved [UserWallet]s with provided [UserWalletId]s diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt index b4bcf48c73..72244a8bf8 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt @@ -120,7 +120,7 @@ internal class BiometricUserWalletsListManager( override suspend fun update( userWalletId: UserWalletId, - update: (UserWallet) -> UserWallet, + update: suspend (UserWallet) -> UserWallet, ): CompletionResult { return get(userWalletId) .map { storedUserWallet -> diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/RuntimeUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/RuntimeUserWalletsListManager.kt index f726dba792..c94958d46f 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/RuntimeUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/RuntimeUserWalletsListManager.kt @@ -58,7 +58,7 @@ internal class RuntimeUserWalletsListManager : UserWalletsListManager { override suspend fun update( userWalletId: UserWalletId, - update: (UserWallet) -> UserWallet, + update: suspend (UserWallet) -> UserWallet, ): CompletionResult = catching { val wallet = state.value.userWallet ?.takeIf { it.walletId == userWalletId } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index c026cc9e0f..e4a508d068 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -4,6 +4,7 @@ import android.content.Context import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.address.AddressType import com.tangem.core.analytics.AnalyticsEvent +import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.domain.TapError @@ -130,4 +131,8 @@ sealed class WalletAction : Action { data class WalletStoresChanged(val walletStores: List) : WalletAction() data class TotalFiatBalanceChanged(val balance: TotalFiatBalance) : WalletAction() + + data class UpdateUserWalletArtwork(val walletId: UserWalletId) : WalletAction() + + data class SetArtworkUrl(val url: String) : WalletAction() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 404aa63a43..7d34cdc332 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -5,6 +5,7 @@ import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.address.AddressType import com.tangem.common.CompletionResult +import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics import com.tangem.datasource.connection.NetworkConnectionManager @@ -25,6 +26,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.TapError import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel +import com.tangem.tap.domain.userWalletList.GetCardImageUseCase import com.tangem.tap.domain.userWalletList.lockIfLockable import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction @@ -133,6 +135,9 @@ class WalletMiddleware { Timber.e("Unable to load/refresh wallets data, no user wallet selected") return } + + store.dispatch(WalletAction.UpdateUserWalletArtwork(selectedWallet.walletId)) + scope.launch { globalState.tapWalletManager.loadData( userWallet = selectedWallet, @@ -205,6 +210,23 @@ class WalletMiddleware { is WalletAction.ChangeSelectedAddress -> { changeSelectedWalletAddress(action.type, walletState) } + is WalletAction.UpdateUserWalletArtwork -> { + scope.launch { + userWalletsListManager + .update( + userWalletId = action.walletId, + update = { userWallet -> + userWallet.copy( + artworkUrl = GetCardImageUseCase().invoke( + cardId = userWallet.cardId, + cardPublicKey = userWallet.scanResponse.card.cardPublicKey, + ), + ) + }, + ) + .doOnSuccess { store.dispatch(WalletAction.SetArtworkUrl(it.artworkUrl)) } + } + } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index b1d7fcfef0..a7ebec614d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -113,8 +113,11 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS ) } is WalletAction.UpdateCanSaveUserWallets -> { + newState = newState.copy(canSaveUserWallets = action.canSaveUserWallets) + } + is WalletAction.SetArtworkUrl -> { newState = newState.copy( - canSaveUserWallets = action.canSaveUserWallets, + cardImage = Artwork(artworkId = action.url, artwork = newState.cardImage?.artwork), ) } else -> Unit From 25d468b7b5e980ee20ea5c1d0ee65b93cec605b2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 14 Apr 2023 11:48:31 +0300 Subject: [PATCH 19/30] Updated on 2026-08-14 --- .../tap/domain/model/TotalFiatBalance.kt | 7 +- .../DefaultTotalFiatBalanceCalculator.kt | 51 ++++---- .../analytics/WalletAnalyticsEventsMapper.kt | 20 +-- .../wallet/ui/view/TotalBalanceCard.kt | 28 +++-- .../redux/WalletSelectorMiddleware.kt | 8 +- .../tap/features/walletSelector/ui/Mapper.kt | 8 +- .../walletSelector/ui/components/MockData.kt | 2 + .../ui/components/WalletItem.kt | 117 +++++++++++++++--- .../walletSelector/ui/model/UserWalletItem.kt | 17 ++- 9 files changed, 179 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt b/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt index 9fa5b24fd8..0180d85435 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt @@ -13,11 +13,12 @@ sealed interface TotalFiatBalance { override val amount: BigDecimal? = null } - data class Error( - override val amount: BigDecimal?, - ) : TotalFiatBalance + object Failed : TotalFiatBalance { + override val amount: BigDecimal? = null + } data class Loaded( override val amount: BigDecimal, + val isWarning: Boolean, ) : TotalFiatBalance } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt index fd5bf29aa9..330561f5af 100644 --- a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt +++ b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt @@ -22,13 +22,15 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { val walletsData = walletStores .asSequence() .flatMap { it.walletsData } - val calculateAmount = { walletsData.calculateTotalFiatAmount() } - when (walletsData.findStatus()) { + when (val status = walletsData.findStatus()) { TotalFiatBalanceStatus.Loading -> TotalFiatBalance.Loading - TotalFiatBalanceStatus.Error -> TotalFiatBalance.Error(calculateAmount()) - TotalFiatBalanceStatus.Loaded -> TotalFiatBalance.Loaded( - amount = calculateAmount() ?: BigDecimal.ZERO, + TotalFiatBalanceStatus.Failed -> TotalFiatBalance.Failed + TotalFiatBalanceStatus.Warning, + TotalFiatBalanceStatus.Loaded, + -> TotalFiatBalance.Loaded( + amount = walletsData.calculateTotalFiatAmount(), + isWarning = status == TotalFiatBalanceStatus.Warning, ) } } @@ -50,29 +52,30 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { is WalletDataModel.SameCurrencyTransactionInProgress, is WalletDataModel.TransactionInProgress, is WalletDataModel.NoAccount, - -> if (walletData.isCustom && walletData.fiatRate == null) { - TotalFiatBalanceStatus.Error + -> if (walletData.isWarningCase()) { + TotalFiatBalanceStatus.Warning } else { TotalFiatBalanceStatus.Loaded } is WalletDataModel.Unreachable, is WalletDataModel.MissedDerivation, - -> TotalFiatBalanceStatus.Error + -> TotalFiatBalanceStatus.Failed is WalletDataModel.Loading -> TotalFiatBalanceStatus.Loading } } } - private fun Sequence.calculateTotalFiatAmount(): BigDecimal? { + private fun Sequence.calculateTotalFiatAmount(): BigDecimal { return this - .filterNot { it.isCustom && it.fiatRate == null } + .filterNot { it.isWarningCase() } .map { walletData -> walletData.fiatRate ?.takeUnless { walletData.status.isErrorStatus } ?.let { walletData.status.amount.toFiatValue(it) } + ?: BigDecimal.ZERO } .reduce { acc, value -> - value?.let { acc?.plus(it) } + acc + value } } @@ -80,20 +83,22 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { prevStatus: TotalFiatBalanceStatus, newStatus: TotalFiatBalanceStatus, ): TotalFiatBalanceStatus { - return when (prevStatus) { - TotalFiatBalanceStatus.Loading -> prevStatus - TotalFiatBalanceStatus.Loaded, - TotalFiatBalanceStatus.Error, - -> when (newStatus) { - TotalFiatBalanceStatus.Loading, - TotalFiatBalanceStatus.Error, - -> newStatus - TotalFiatBalanceStatus.Loaded -> prevStatus - } - } + return TotalFiatBalanceStatus[minOf(prevStatus.ordinal, newStatus.ordinal)] } + private fun WalletDataModel.isWarningCase(): Boolean = isCustom && fiatRate == null + private enum class TotalFiatBalanceStatus { - Loading, Error, Loaded, + Loading, + Failed, + Warning, + Loaded, + ; + + companion object { + private val allValues = values() + + operator fun get(index: Int) = allValues[index] + } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/analytics/WalletAnalyticsEventsMapper.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/analytics/WalletAnalyticsEventsMapper.kt index 277ce8471c..184e85983c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/analytics/WalletAnalyticsEventsMapper.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/analytics/WalletAnalyticsEventsMapper.kt @@ -10,21 +10,11 @@ class WalletAnalyticsEventsMapper : Converter { - if (value.amount == null) { - // if fiatAmount is null while ProgressState.Error it means error occurs when loading blockchain - AnalyticsParam.CardBalanceState.BlockchainError - } else { - // if fiatAmount is not null while ProgressState.Error it means couldn't load custom token amount - AnalyticsParam.CardBalanceState.CustomToken - } - } - is TotalFiatBalance.Loaded -> { - if (value.amount.isGreaterThan(BigDecimal.ZERO)) { - AnalyticsParam.CardBalanceState.Full - } else { - AnalyticsParam.CardBalanceState.Empty - } + is TotalFiatBalance.Failed -> AnalyticsParam.CardBalanceState.BlockchainError + is TotalFiatBalance.Loaded -> when { + value.isWarning -> AnalyticsParam.CardBalanceState.CustomToken + value.amount.isGreaterThan(BigDecimal.ZERO) -> AnalyticsParam.CardBalanceState.Full + else -> AnalyticsParam.CardBalanceState.Empty } is TotalFiatBalance.Loading -> null } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt index 4eab1313a5..605053c7e4 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt @@ -86,8 +86,7 @@ internal class TotalBalanceCard @JvmOverloads constructor( private fun updateState(status: TotalFiatBalance?, fiatCurrency: FiatCurrency, onChangeCurrencyClick: () -> Unit) { state = when (status) { null -> TotalBalanceCardState.Empty - is TotalFiatBalance.Error -> TotalBalanceCardState.Failure( - amount = status.amount, + is TotalFiatBalance.Failed -> TotalBalanceCardState.Failure( fiatCurrency = fiatCurrency, onChangeFiatCurrencyClick = onChangeCurrencyClick, ) @@ -97,8 +96,9 @@ internal class TotalBalanceCard @JvmOverloads constructor( ) is TotalFiatBalance.Loaded -> TotalBalanceCardState.Success( amount = status.amount, - fiatCurrency = fiatCurrency, + showWarning = status.isWarning, onChangeFiatCurrencyClick = onChangeCurrencyClick, + fiatCurrency = fiatCurrency, ) } } @@ -138,8 +138,8 @@ private fun TotalBalanceCardContent(state: TotalBalanceCardState, modifier: Modi ) } }, - failureText = { - AnimatedVisibility(visible = state is TotalBalanceCardState.Failure) { + warningText = { + AnimatedVisibility(visible = state.showWarning) { Text( modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.main_processing_full_amount), @@ -156,7 +156,7 @@ private fun TotalBalanceCardScaffold( title: @Composable () -> Unit, amount: @Composable () -> Unit, currencySelector: @Composable () -> Unit, - failureText: @Composable () -> Unit, + warningText: @Composable () -> Unit, modifier: Modifier = Modifier, amountWeight: Float = 0.8f, ) { @@ -192,7 +192,7 @@ private fun TotalBalanceCardScaffold( horizontal = TangemTheme.dimens.spacing16, ), ) { - failureText() + warningText() } SpacerH12() } @@ -252,11 +252,13 @@ private fun buildAmountString(amount: BigDecimal?, fiatCurrencySymbol: String): private sealed interface TotalBalanceCardState { val amount: BigDecimal? - val onChangeFiatCurrencyClick: () -> Unit + val showWarning: Boolean val fiatCurrency: FiatCurrency + val onChangeFiatCurrencyClick: () -> Unit object Empty : TotalBalanceCardState { override val amount: BigDecimal? = null + override val showWarning: Boolean = false override val fiatCurrency: FiatCurrency = FiatCurrency.Default override val onChangeFiatCurrencyClick: () -> Unit = { /* no-op */ } } @@ -266,16 +268,20 @@ private sealed interface TotalBalanceCardState { override val onChangeFiatCurrencyClick: () -> Unit, ) : TotalBalanceCardState { override val amount: BigDecimal = BigDecimal.ZERO + override val showWarning: Boolean = false } data class Failure( - override val amount: BigDecimal?, override val fiatCurrency: FiatCurrency, override val onChangeFiatCurrencyClick: () -> Unit, - ) : TotalBalanceCardState + ) : TotalBalanceCardState { + override val amount: BigDecimal? = null + override val showWarning: Boolean = true + } data class Success( override val amount: BigDecimal, + override val showWarning: Boolean, override val fiatCurrency: FiatCurrency, override val onChangeFiatCurrencyClick: () -> Unit, ) : TotalBalanceCardState @@ -297,7 +303,6 @@ private fun TotalBalanceCardContentSample(modifier: Modifier = Modifier) { Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) TotalBalanceCardContent( state = TotalBalanceCardState.Failure( - amount = BigDecimal("9917.72"), onChangeFiatCurrencyClick = {}, fiatCurrency = FiatCurrency("USD", "USD", "$"), ), @@ -306,6 +311,7 @@ private fun TotalBalanceCardContentSample(modifier: Modifier = Modifier) { TotalBalanceCardContent( state = TotalBalanceCardState.Success( amount = BigDecimal("9917.72"), + showWarning = false, onChangeFiatCurrencyClick = {}, fiatCurrency = FiatCurrency("USD", "USD", "$"), ), diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index 9191b57a00..aadd56356b 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -108,7 +108,7 @@ internal class WalletSelectorMiddleware { ) { if (updatedWalletStores.isNotEmpty()) { scope.launch(Dispatchers.Default) { - val updatedWallets = state.wallets.updateWalletStoresAndCalculateFiatBalance(updatedWalletStores) + val updatedWallets = state.wallets.calculateBalanceAndUpdateWalletStores(updatedWalletStores) if (updatedWallets != state.wallets) { store.dispatchOnMain(WalletSelectorAction.BalancesLoaded(updatedWallets)) } @@ -362,17 +362,17 @@ internal class WalletSelectorMiddleware { } } - private suspend fun List.updateWalletStoresAndCalculateFiatBalance( + private suspend fun List.calculateBalanceAndUpdateWalletStores( walletStores: Map>, ): List { return this .associateWith { walletStores[it.id] } .map { (wallet, walletStores) -> - wallet.updateWalletStoresAndCalculateFiatBalance(walletStores) + wallet.calculateBalanceAndUpdateWalletStores(walletStores) } } - private suspend fun UserWalletModel.updateWalletStoresAndCalculateFiatBalance( + private suspend fun UserWalletModel.calculateBalanceAndUpdateWalletStores( walletStores: List?, ): UserWalletModel { return this.copy( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt index 400c4e026e..0e4319a4dc 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt @@ -3,7 +3,6 @@ package com.tangem.tap.features.walletSelector.ui import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.toFormattedFiatValue import com.tangem.tap.domain.model.TotalFiatBalance -import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN import com.tangem.tap.features.walletSelector.redux.UserWalletModel import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem @@ -13,13 +12,12 @@ internal fun List.toUiModels(appCurrency: FiatCurrency): Sequen return this.asSequence().map { userWalletModel -> with(userWalletModel) { val balance = when (fiatBalance) { - is TotalFiatBalance.Error -> UserWalletItem.Balance.Error( - amount = fiatBalance.amount?.toFormattedFiatValue(appCurrency.symbol) ?: UNKNOWN_AMOUNT_SIGN, - ) + is TotalFiatBalance.Failed -> UserWalletItem.Balance.Failed + is TotalFiatBalance.Loading -> UserWalletItem.Balance.Loading is TotalFiatBalance.Loaded -> UserWalletItem.Balance.Loaded( amount = fiatBalance.amount.toFormattedFiatValue(appCurrency.symbol), + showWarning = fiatBalance.isWarning, ) - is TotalFiatBalance.Loading -> UserWalletItem.Balance.Loading } when (type) { is UserWalletModel.Type.MultiCurrency -> MultiCurrencyUserWalletItem( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt index db09868d03..c404c8890a 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt @@ -11,6 +11,7 @@ internal object MockData { id = UserWalletId("wallet_1"), balance = UserWalletItem.Balance.Loaded( amount = "6781.05 $", + showWarning = true, ), name = "Wallet", imageUrl = "https://app.tangem.com/cards/card_default.png", @@ -23,6 +24,7 @@ internal object MockData { id = UserWalletId("wallet_4"), balance = UserWalletItem.Balance.Loaded( amount = "6781.05 $", + showWarning = false, ), name = "Wallet", imageUrl = "https://app.tangem.com/cards/card_default.png", diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt index 70c46cb0ce..40f87ab080 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -178,18 +179,13 @@ private fun RowScope.TokensInfo(isLocked: Boolean, balance: UserWalletItem.Balan LockedPlaceholder() } else { when (balance) { - is UserWalletItem.Balance.Error -> { + is UserWalletItem.Balance.Failed, + is UserWalletItem.Balance.Loaded, + -> { LoadedTokensInfo( balanceAmount = balance.amount, tokensCount = tokensCount, - showWarning = true, - ) - } - is UserWalletItem.Balance.Loaded -> { - LoadedTokensInfo( - balanceAmount = balance.amount, - tokensCount = tokensCount, - showWarning = false, + showWarning = balance.showWarning, ) } is UserWalletItem.Balance.Loading -> { @@ -360,16 +356,23 @@ private fun CheckedWalletMark(modifier: Modifier = Modifier) { } } -@Preview(widthDp = 360, heightDp = 72, showBackground = true) +// region Preview @Composable -private fun PreviewWalletItem() { - TangemTheme { +@Suppress("LongMethod") // preview +private fun WalletItemSample(modifier: Modifier = Modifier) { + Column( + modifier = modifier + .background(TangemTheme.colors.background.primary), + ) { WalletItem( wallet = MultiCurrencyUserWalletItem( id = UserWalletId(value = null), name = "Tangem Card", imageUrl = "", - balance = UserWalletItem.Balance.Loaded("141212121888 BTC"), + balance = UserWalletItem.Balance.Loaded( + amount = "1412121218 BTC", + showWarning = false, + ), isLocked = false, tokensCount = 2, cardsInWallet = 1, @@ -379,5 +382,91 @@ private fun PreviewWalletItem() { onWalletClick = {}, onWalletLongClick = {}, ) + Divider(modifier = Modifier.padding(vertical = 4.dp)) + WalletItem( + wallet = MultiCurrencyUserWalletItem( + id = UserWalletId(value = null), + name = "Tangem Card", + imageUrl = "", + balance = UserWalletItem.Balance.Loaded( + amount = "1412121218 BTC", + showWarning = true, + ), + isLocked = false, + tokensCount = 2, + cardsInWallet = 1, + ), + isSelected = false, + isChecked = false, + onWalletClick = {}, + onWalletLongClick = {}, + ) + Divider(modifier = Modifier.padding(vertical = 4.dp)) + WalletItem( + wallet = MultiCurrencyUserWalletItem( + id = UserWalletId(value = null), + name = "Tangem Card", + imageUrl = "", + balance = UserWalletItem.Balance.Loading, + isLocked = true, + tokensCount = 2, + cardsInWallet = 1, + ), + isSelected = false, + isChecked = false, + onWalletClick = {}, + onWalletLongClick = {}, + ) + Divider(modifier = Modifier.padding(vertical = 4.dp)) + WalletItem( + wallet = MultiCurrencyUserWalletItem( + id = UserWalletId(value = null), + name = "Tangem Card", + imageUrl = "", + balance = UserWalletItem.Balance.Failed, + isLocked = false, + tokensCount = 2, + cardsInWallet = 1, + ), + isSelected = true, + isChecked = false, + onWalletClick = {}, + onWalletLongClick = {}, + ) + Divider(modifier = Modifier.padding(vertical = 4.dp)) + WalletItem( + wallet = SingleCurrencyUserWalletItem( + id = UserWalletId(value = null), + name = "Tangem Card", + imageUrl = "", + balance = UserWalletItem.Balance.Loaded( + amount = "141212121888 BTC", + showWarning = false, + ), + isLocked = false, + tokenName = "Bitcoin", + ), + isSelected = false, + isChecked = true, + onWalletClick = {}, + onWalletLongClick = {}, + ) } -} \ No newline at end of file +} + +@Preview(showBackground = true, widthDp = 360) +@Composable +private fun WalletItemPreview_Light() { + TangemTheme { + WalletItemSample() + } +} + +@Preview(showBackground = true, widthDp = 360) +@Composable +private fun WalletItemPreview_Dark() { + TangemTheme(isDark = true) { + WalletItemSample() + } +} +// endregion Preview \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt index eeca9d7611..7013362085 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.walletSelector.ui.model import com.tangem.domain.common.util.UserWalletId +import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN internal sealed interface UserWalletItem { val id: UserWalletId @@ -9,12 +10,20 @@ internal sealed interface UserWalletItem { val balance: Balance val isLocked: Boolean - sealed interface Balance { - object Loading : Balance + sealed class Balance { + open val amount: String = UNKNOWN_AMOUNT_SIGN + open val showWarning: Boolean = false - data class Error(val amount: String) : Balance + object Loading : Balance() - data class Loaded(val amount: String) : Balance + object Failed : Balance() { + override val showWarning: Boolean = true + } + + data class Loaded( + override val amount: String, + override val showWarning: Boolean, + ) : Balance() } } From 3c14484840659ef29cc99786ace971035a448529 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 14 Apr 2023 12:09:22 +0300 Subject: [PATCH 20/30] Updated on 2026-08-14 --- .../com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt | 6 ++++-- app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt | 2 +- .../tangem/tap/domain/extensions/WalletManagerFactory.kt | 2 +- .../java/com/tangem/tap/domain/model/WalletStoreModel.kt | 2 +- .../tangem/tap/domain/model/builders/WalletStoreBuilder.kt | 2 +- .../tap/domain/tasks/product/CreateProductWalletTask.kt | 2 +- .../com/tangem/tap/domain/tasks/product/ScanProductTask.kt | 2 +- .../utils/json/ExtendedPublicKeysMapAdapter.kt | 4 ++-- .../utils/json/WalletDerivedKeysMapAdapter.kt | 4 ++-- .../implementation/DefaultWalletManagersRepository.kt | 2 +- .../details/redux/walletconnect/WalletConnectState.kt | 2 +- .../tangem/tap/features/tokens/redux/TokensMiddleware.kt | 2 +- .../main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt | 2 +- domain/src/main/java/com/tangem/domain/common/CardDTO.kt | 4 ++-- .../src/main/java/com/tangem/domain/common/ScanResponse.kt | 2 +- .../tangem/domain/features/addCustomToken/CustomCurrency.kt | 2 +- .../features/addCustomToken/redux/AddCustomTokenHub.kt | 2 +- .../features/addCustomToken/redux/AddCustomTokenState.kt | 2 +- gradle/dependencies.toml | 4 ++-- 19 files changed, 26 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt b/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt index 0cfa1388be..0a06bf876e 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt @@ -94,8 +94,6 @@ object TangemSdkErrorMapper { is TangemSdkError.BackupFailedEmptyWallets -> TangemSdkError.BackupFailedEmptyWallets() is TangemSdkError.BackupFailedNotEmptyWallets -> TangemSdkError.BackupFailedNotEmptyWallets() is TangemSdkError.NoActiveBackup -> TangemSdkError.NoActiveBackup() - is TangemSdkError.ResetBackupFailedHasBackupedWallets -> - TangemSdkError.ResetBackupFailedHasBackupedWallets() is TangemSdkError.BackupServiceInvalidState -> TangemSdkError.BackupServiceInvalidState() is TangemSdkError.NoBackupCardForIndex -> TangemSdkError.NoBackupCardForIndex() is TangemSdkError.EmptyBackupCards -> TangemSdkError.EmptyBackupCards() @@ -121,6 +119,10 @@ object TangemSdkErrorMapper { is TangemSdkError.InvalidEncryptionKey -> error is TangemSdkError.KeyGenerationException -> error is TangemSdkError.MnemonicException -> error + is TangemSdkError.WalletAlreadyCreated -> error + is TangemSdkError.ResetBackupFailedHasBackedUpWallets -> error + is TangemSdkError.KeysImportDisabled -> error + is TangemSdkError.Underlying -> error } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 36e5dcebdf..11faf6ba4a 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -18,7 +18,7 @@ import com.tangem.common.core.Config import com.tangem.common.core.TangemSdkError import com.tangem.common.core.UserCodeRequestPolicy import com.tangem.common.extensions.ByteArrayKey -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.common.map import com.tangem.common.usersCode.UserCodeRepository import com.tangem.core.analytics.Analytics diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt index 5298777226..b2dbd64995 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt @@ -8,7 +8,7 @@ import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toMapKey -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TapWorkarounds.isTestCard diff --git a/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt b/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt index 01da397e3c..2dad9e1303 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt @@ -2,7 +2,7 @@ package com.tangem.tap.domain.model import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.WalletManager -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.domain.model.WalletStoreModel.WalletRent import com.tangem.tap.domain.tokens.models.BlockchainNetwork diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index 65405fa242..d9805be40f 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -6,7 +6,7 @@ import com.tangem.blockchain.common.DerivationStyle import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.common.WalletManager -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.tap.common.extensions.getBlockchainTxHistory import com.tangem.tap.common.extensions.getTokenTxHistory diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt index eeed6d4ad6..e57a629edc 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt @@ -10,7 +10,7 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.guard import com.tangem.common.extensions.toMapKey -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.common.map import com.tangem.domain.common.CardDTO import com.tangem.domain.common.CardTypesResolver diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 00ca32c553..78866f673b 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -15,7 +15,7 @@ import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toByteArray import com.tangem.common.extensions.toHexString import com.tangem.common.extensions.toMapKey -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.common.tlv.Tlv import com.tangem.common.tlv.TlvDecoder import com.tangem.crypto.CryptoUtils diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/ExtendedPublicKeysMapAdapter.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/ExtendedPublicKeysMapAdapter.kt index 9399f55b79..4fa0999074 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/ExtendedPublicKeysMapAdapter.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/ExtendedPublicKeysMapAdapter.kt @@ -7,8 +7,8 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString -import com.tangem.common.hdWallet.DerivationPath -import com.tangem.common.hdWallet.ExtendedPublicKey +import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey import com.tangem.operations.derivation.ExtendedPublicKeysMap internal class ExtendedPublicKeysMapAdapter { diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/WalletDerivedKeysMapAdapter.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/WalletDerivedKeysMapAdapter.kt index e4ba0dd0db..d374f5013d 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/WalletDerivedKeysMapAdapter.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/json/WalletDerivedKeysMapAdapter.kt @@ -7,8 +7,8 @@ import com.squareup.moshi.JsonWriter import com.squareup.moshi.ToJson import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString -import com.tangem.common.hdWallet.DerivationPath -import com.tangem.common.hdWallet.ExtendedPublicKey +import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey internal class WalletDerivedKeysMapAdapter { @ToJson diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt index a09ea7abd2..6c5eba1809 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt @@ -9,7 +9,7 @@ import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.common.CompletionResult import com.tangem.common.catching import com.tangem.common.doOnSuccess -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.common.mapFailure import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ScanResponse diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt index 5c32fdb2cd..61fa67dd44 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt @@ -5,7 +5,7 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.WalletManager -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.ScanResponse import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index eee906b7d1..7a3c9a9d17 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -8,7 +8,7 @@ import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.guard import com.tangem.common.extensions.toMapKey import com.tangem.common.flatMap -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.common.services.Result import com.tangem.core.analytics.Analytics import com.tangem.domain.DomainWrapped diff --git a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt index 0ef9bf082d..f52ac33f8a 100644 --- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt @@ -8,7 +8,7 @@ import com.tangem.common.core.TangemError import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.toMapKey -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.extensions.fromNetworkId diff --git a/domain/src/main/java/com/tangem/domain/common/CardDTO.kt b/domain/src/main/java/com/tangem/domain/common/CardDTO.kt index 630a017700..fa4cbe9f42 100644 --- a/domain/src/main/java/com/tangem/domain/common/CardDTO.kt +++ b/domain/src/main/java/com/tangem/domain/common/CardDTO.kt @@ -5,8 +5,8 @@ import com.tangem.common.card.Card import com.tangem.common.card.CardWallet import com.tangem.common.card.EllipticCurve import com.tangem.common.card.EncryptionMode -import com.tangem.common.hdWallet.DerivationPath -import com.tangem.common.hdWallet.ExtendedPublicKey +import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey import com.tangem.operations.attestation.Attestation import java.util.* import com.tangem.common.card.FirmwareVersion as SdkFirmwareVersion diff --git a/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt b/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt index 17f4e1c64a..a93b21fba7 100644 --- a/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt +++ b/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt @@ -5,7 +5,7 @@ import com.tangem.common.card.EllipticCurve import com.tangem.common.card.WalletData import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.toMapKey -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.operations.CommandResponse diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/CustomCurrency.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/CustomCurrency.kt index fd1a47b728..6757215dda 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/CustomCurrency.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/CustomCurrency.kt @@ -3,7 +3,7 @@ package com.tangem.domain.features.addCustomToken import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle import com.tangem.blockchain.common.Token -import com.tangem.common.hdWallet.DerivationPath +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.form.BaseFieldDataConverter import com.tangem.domain.common.form.FieldId import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenState diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt index 1a533426fc..08315dc850 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt @@ -420,7 +420,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT private fun getDerivationPathFromSelectedBlockchain( selectedDerivationBlockchain: Blockchain, - ): com.tangem.common.hdWallet.DerivationPath? = AddCustomTokenState.getDerivationPath( + ): com.tangem.crypto.hdWallet.DerivationPath? = AddCustomTokenState.getDerivationPath( mainNetwork = Network.getFieldValue(), derivationNetwork = selectedDerivationBlockchain, derivationStyle = hubState.cardDerivationStyle, diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt index 829077bc70..7076b19233 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt @@ -173,7 +173,7 @@ data class AddCustomTokenState( mainNetwork: Blockchain, derivationNetwork: Blockchain, derivationStyle: DerivationStyle?, - ): com.tangem.common.hdWallet.DerivationPath? { + ): com.tangem.crypto.hdWallet.DerivationPath? { // If we allow user to select derivations, we need to provide different derivations // (Legacy style derivations). // But the mainNetwork derivation depends on whether a user has a card diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 6759d13722..d134968349 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -71,9 +71,9 @@ kotlinSerialization = "1.4.1" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-193" +tangemBlockchainSdk = "develop-197" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-209" +tangemCardSdk = "develop-213" # tangemCardSdk = "0.0.1" # Keep it! - used for local builds # endregion Tangem From 8a1239f014dc46d284ed05296a52ca0c2fd7adf3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 14 Apr 2023 20:47:58 +0900 Subject: [PATCH 21/30] Updated on 2026-08-14 --- .../tokens/di/TokensListInteractorModule.kt | 1 + .../domain/DefaultTokensListInteractor.kt | 232 +++++++++++++++++- .../tokens/domain/TokensListInteractor.kt | 10 + .../router/DefaultTokensListRouter.kt | 31 +++ .../presentation/router/TokensListRouter.kt | 24 +- .../states/TokensListStateHolder.kt | 25 +- .../presentation/ui/TokensListScreen.kt | 12 +- .../viewmodels/TokensListViewModel.kt | 145 +++++------ .../features/tokens/redux/TokensMiddleware.kt | 2 +- gradle/dependencies.toml | 2 +- 10 files changed, 374 insertions(+), 110 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListInteractorModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListInteractorModule.kt index 8d1f10d327..c27bc5f8e0 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListInteractorModule.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListInteractorModule.kt @@ -35,6 +35,7 @@ internal object TokensListInteractorModule { reduxStateHolder = reduxStateHolder, testnetTokensStorage = testnetTokensStorage, ), + reduxStateHolder = reduxStateHolder, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/DefaultTokensListInteractor.kt b/app/src/main/java/com/tangem/tap/features/tokens/domain/DefaultTokensListInteractor.kt index 3391af49a2..5012ccebc5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/domain/DefaultTokensListInteractor.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/domain/DefaultTokensListInteractor.kt @@ -1,17 +1,245 @@ package com.tangem.tap.features.tokens.domain import androidx.paging.PagingData +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.DerivationStyle +import com.tangem.common.CompletionResult +import com.tangem.common.card.EllipticCurve +import com.tangem.common.extensions.guard +import com.tangem.common.extensions.toMapKey +import com.tangem.common.flatMap +import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.domain.common.ScanResponse +import com.tangem.domain.common.TapWorkarounds.derivationStyle +import com.tangem.operations.derivation.ExtendedPublicKeysMap +import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE +import com.tangem.tap.common.extensions.dispatchDebugErrorNotification +import com.tangem.tap.common.extensions.dispatchOnMain +import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.domain.TapError +import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.redux.TokensMiddleware +import com.tangem.tap.features.wallet.models.Currency +import com.tangem.tap.proxy.AppStateHolder +import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager +import com.tangem.tap.userWalletsListManager +import com.tangem.tap.walletCurrenciesManager +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow +import timber.log.Timber /** * Default implementation of tokens list interactor + * FIXME("Necessary to avoid using redux actions") * - * @property repository repository of tokens list feature + * @property repository repository of tokens list feature + * @property reduxStateHolder redux state holder */ -internal class DefaultTokensListInteractor(private val repository: TokensListRepository) : TokensListInteractor { +internal class DefaultTokensListInteractor( + private val repository: TokensListRepository, + private val reduxStateHolder: AppStateHolder, +) : TokensListInteractor { override fun getTokensList(searchText: String): Flow> { return repository.getAvailableTokens(searchText = searchText.ifBlank(defaultValue = { null })) } + + override suspend fun saveChanges(tokens: List, blockchains: List) { + val scanResponse = requireNotNull(reduxStateHolder.scanResponse) + + val currentTokens = store.state.tokensState.addedWallets + .toNonCustomTokensWithBlockchains(style = scanResponse.card.derivationStyle) + + val currentBlockchains = store.state.tokensState.addedWallets + .toNonCustomBlockchains(derivationStyle = scanResponse.card.derivationStyle) + + val blockchainsToAdd = blockchains.filterNot(currentBlockchains::contains) + val blockchainsToRemove = currentBlockchains.filterNot(blockchains::contains) + + val tokensToAdd = tokens.filterNot(currentTokens::contains) + val tokensToRemove = currentTokens.filterNot { token -> tokens.any { it.token == token.token } } + + val isNothingToDoWithTokens = tokensToAdd.isEmpty() && tokensToRemove.isEmpty() + val isNothingToDoWithBlockchain = blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty() + if (isNothingToDoWithTokens && isNothingToDoWithBlockchain) { + store.dispatchDebugErrorNotification(message = "Nothing to save") + return + } + + remove( + tokens = tokensToRemove, + blockchains = blockchainsToRemove, + derivationStyle = scanResponse.card.derivationStyle, + ) + + add(tokens = tokensToAdd, blockchains = blockchainsToAdd, scanResponse = scanResponse) + } + + private fun List.toNonCustomTokensWithBlockchains( + style: DerivationStyle?, + ): List { + return this.map(WalletDataModel::currency) + .mapNotNull { currency -> + if (currency !is Currency.Token || currency.isCustomCurrency(style)) return@mapNotNull null + TokenWithBlockchain(token = currency.token, blockchain = currency.blockchain) + } + .distinct() + } + + private fun List.toNonCustomBlockchains(derivationStyle: DerivationStyle?): List { + return this.map(WalletDataModel::currency) + .mapNotNull { currency -> + if (currency.isCustomCurrency(derivationStyle)) return@mapNotNull null + (currency as? Currency.Blockchain)?.blockchain + } + .distinct() + } + + private suspend fun remove( + tokens: List, + blockchains: List, + derivationStyle: DerivationStyle?, + ) { + val currencies = convertToCurrencies(tokens, blockchains, derivationStyle) + if (currencies.isEmpty()) return + + val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { + Timber.e("Unable to remove currencies, no user wallet selected") + return + } + + walletCurrenciesManager.removeCurrencies(userWallet = selectedUserWallet, currenciesToRemove = currencies) + } + + private suspend fun add( + tokens: List, + blockchains: List, + scanResponse: ScanResponse, + ) { + val currenciesToAdd = convertToCurrencies( + tokens = tokens, + blockchains = blockchains, + derivationStyle = scanResponse.card.derivationStyle, + ) + + // TODO("[REDACTED_TASK_KEY] use DerivationManager") + if (scanResponse.supportsHdWallet()) { + deriveMissingBlockchains(scanResponse, currenciesToAdd) + } else { + submitAdd(scanResponse, currenciesToAdd) + return + } + } + + private suspend fun deriveMissingBlockchains(scanResponse: ScanResponse, currencies: List) { + val derivations = listOfNotNull( + getDerivations(EllipticCurve.Secp256k1, scanResponse, currencies), + getDerivations(EllipticCurve.Ed25519, scanResponse, currencies), + ).associate(transform = TokensMiddleware.DerivationData::derivations) + + if (derivations.isEmpty()) { + submitAdd(scanResponse, currencies) + return + } + + when (val result = tangemSdkManager.derivePublicKeys(cardId = null, derivations = derivations)) { + is CompletionResult.Success -> { + val newDerivedKeys = result.data.entries + val oldDerivedKeys = scanResponse.derivedKeys + + val walletKeys = (newDerivedKeys.keys + oldDerivedKeys.keys).toSet() + + val updatedDerivedKeys = walletKeys.associateWith { walletKey -> + val oldDerivations = ExtendedPublicKeysMap(map = oldDerivedKeys[walletKey] ?: emptyMap()) + val newDerivations = newDerivedKeys[walletKey] ?: ExtendedPublicKeysMap(map = emptyMap()) + ExtendedPublicKeysMap(map = oldDerivations + newDerivations) + } + + val updatedScanResponse = scanResponse.copy(derivedKeys = updatedDerivedKeys) + + store.dispatchOnMain(GlobalAction.SaveScanResponse(updatedScanResponse)) + delay(DELAY_SDK_DIALOG_CLOSE) + + submitAdd(scanResponse, currencies) + return + } + is CompletionResult.Failure -> { + store.dispatchDebugErrorNotification(TapError.CustomError(customMessage = "Error adding tokens")) + } + } + } + + private fun getDerivations( + curve: EllipticCurve, + scanResponse: ScanResponse, + currencyList: List, + ): TokensMiddleware.DerivationData? { + val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null + + val manageTokensCandidates = currencyList + .map(Currency::blockchain) + .distinct() + .filter { it.getSupportedCurves().contains(curve) } + .mapNotNull { it.derivationPath(scanResponse.card.derivationStyle) } + + val customTokensCandidates = currencyList + .filter { it.blockchain.getSupportedCurves().contains(curve) } + .mapNotNull(Currency::derivationPath) + .map(::DerivationPath) + + val bothCandidates = (manageTokensCandidates + customTokensCandidates).distinct() + if (bothCandidates.isEmpty()) return null + + val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey() + val alreadyDerivedKeys = scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap()) + val alreadyDerivedPaths = alreadyDerivedKeys.keys.toList() + + val toDerive = bothCandidates.filterNot(alreadyDerivedPaths::contains) + if (toDerive.isEmpty()) return null + + return TokensMiddleware.DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive) + } + + private suspend fun submitAdd(scanResponse: ScanResponse, currencies: List) { + val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { + Timber.e("Unable to add currencies, no user wallet selected") + return + } + + userWalletsListManager + .update( + userWalletId = selectedUserWallet.walletId, + update = { userWallet -> userWallet.copy(scanResponse = scanResponse) }, + ) + .flatMap { updatedUserWallet -> + walletCurrenciesManager.addCurrencies( + userWallet = updatedUserWallet, + currenciesToAdd = currencies, + ) + } + } + + private fun convertToCurrencies( + tokens: List, + blockchains: List, + derivationStyle: DerivationStyle?, + ): List { + return tokens.map { tokenWithBlockchain -> + Currency.Token( + token = tokenWithBlockchain.token, + blockchain = tokenWithBlockchain.blockchain, + derivationPath = tokenWithBlockchain.blockchain.derivationPath(derivationStyle)?.rawPath, + ) + }.plus( + blockchains.map { blockchain -> + Currency.Blockchain( + blockchain = blockchain, + derivationPath = blockchain.derivationPath(derivationStyle)?.rawPath, + ) + }, + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt b/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt index 1fab924630..6ffe49b885 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt @@ -1,7 +1,9 @@ package com.tangem.tap.features.tokens.domain import androidx.paging.PagingData +import com.tangem.blockchain.common.Blockchain import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.redux.TokenWithBlockchain import kotlinx.coroutines.flow.Flow /** @@ -13,4 +15,12 @@ internal interface TokensListInteractor { /** Get tokens list using filter by text [searchText] */ fun getTokensList(searchText: String): Flow> + + /** + * Save added tokens + * + * @param tokens tokens list that need to save + * @param blockchains blockchains list that need to save + */ + suspend fun saveChanges(tokens: List, blockchains: List) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt index a016e91a00..f266e0805f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt @@ -1,11 +1,17 @@ package com.tangem.tap.features.tokens.presentation.router +import com.tangem.tap.common.extensions.dispatchDialogShow +import com.tangem.tap.common.extensions.dispatchNotification +import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.tokens.redux.TokensAction +import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.store +import com.tangem.wallet.R /** * Default implementation of tokens list router + * FIXME("Necessary to avoid using redux actions") * [REDACTED_AUTHOR] */ @@ -19,4 +25,29 @@ internal class DefaultTokensListRouter : TokensListRouter { override fun openAddCustomTokenScreen() { store.dispatch(TokensAction.PrepareAndNavigateToAddCustomToken) } + + override fun showAddressCopiedNotification() { + store.dispatchNotification(R.string.contract_address_copied_message) + } + + override fun openUnableHideMainTokenAlert(tokenName: String, tokenSymbol: String) { + store.dispatchDialogShow( + dialog = WalletDialog.TokensAreLinkedDialog(currencyTitle = tokenName, currencySymbol = tokenSymbol), + ) + } + + override fun openRemoveWalletAlert(tokenName: String, onOkClick: () -> Unit) { + store.dispatchDialogShow( + dialog = WalletDialog.RemoveWalletDialog(currencyTitle = tokenName, onOk = onOkClick), + ) + } + + override fun openUnsupportedSoltanaNetworkAlert() { + store.dispatchDialogShow( + AppDialog.SimpleOkDialogRes( + headerId = R.string.common_warning, + messageId = R.string.alert_manage_tokens_unsupported_message, + ), + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt index 1ed3a068dc..ccc7ed37cb 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt @@ -6,6 +6,28 @@ internal interface TokensListRouter { /** Return to last screen */ fun popBackStack() - /** Open screen for adding custom token */ + /** Open adding custom token screen */ fun openAddCustomTokenScreen() + + /** Show notification to inform about copied address */ + fun showAddressCopiedNotification() + + /** + * Open alert if unable to hide the main token + * + * @param tokenName token name + * @param tokenSymbol token brief name + */ + fun openUnableHideMainTokenAlert(tokenName: String, tokenSymbol: String) + + /** + * Open alert to remove wallet + * + * @param tokenName token name + * @param onOkClick lambda be invoked if OkButton is been clicked + */ + fun openRemoveWalletAlert(tokenName: String, onOkClick: () -> Unit) + + /** Open alert if solana network is unsupported */ + fun openUnsupportedSoltanaNetworkAlert() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt index c4049ddfcc..a7368f383d 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt @@ -14,6 +14,9 @@ internal sealed interface TokensListStateHolder { /** Toolbar state */ val toolbarState: TokensListToolbarState + /** Loading state */ + val isLoading: Boolean + /** Tokens list */ val tokens: Flow> @@ -24,34 +27,22 @@ internal sealed interface TokensListStateHolder { * Util function that allow to make a copy * * @param toolbarState toolbar state + * @param isLoading loading state * @param tokens tokens list * @param onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed */ fun copySealed( toolbarState: TokensListToolbarState = this.toolbarState, + isLoading: Boolean = this.isLoading, tokens: Flow> = this.tokens, onTokensLoadStateChanged: (LoadState) -> Unit = this.onTokensLoadStateChanged, ): TokensListStateHolder { return when (this) { - is ManageContent -> copy(toolbarState, tokens, onTokensLoadStateChanged) - is Loading -> copy(toolbarState, tokens, onTokensLoadStateChanged) - is ReadContent -> copy(toolbarState, tokens, onTokensLoadStateChanged) + is ManageContent -> copy(toolbarState, isLoading, tokens, onTokensLoadStateChanged) + is ReadContent -> copy(toolbarState, isLoading, tokens, onTokensLoadStateChanged) } } - /** - * Loading state - * - * @property toolbarState toolbar state - * @property tokens tokens list - * @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed - */ - data class Loading( - override val toolbarState: TokensListToolbarState, - override val tokens: Flow>, - override val onTokensLoadStateChanged: (LoadState) -> Unit, - ) : TokensListStateHolder - /** * State screen that is available only for read * @@ -61,6 +52,7 @@ internal sealed interface TokensListStateHolder { */ data class ReadContent( override val toolbarState: TokensListToolbarState, + override val isLoading: Boolean, override val tokens: Flow>, override val onTokensLoadStateChanged: (LoadState) -> Unit, ) : TokensListStateHolder @@ -75,6 +67,7 @@ internal sealed interface TokensListStateHolder { */ data class ManageContent( override val toolbarState: TokensListToolbarState, + override val isLoading: Boolean, override val tokens: Flow>, override val onTokensLoadStateChanged: (LoadState) -> Unit, val onSaveButtonClick: () -> Unit, diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt index 977e5705bf..57f720ee1c 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt @@ -55,15 +55,12 @@ internal fun TokensListScreen(stateHolder: TokensListStateHolder) { ) { scaffoldPadding -> val tokens = stateHolder.tokens.collectAsLazyPagingItems() - TokensListContent( - tokens = tokens, - scaffoldPadding = scaffoldPadding, - ) + TokensListContent(tokens, scaffoldPadding) stateHolder.onTokensLoadStateChanged(tokens.loadState.refresh) AnimatedVisibility( - visible = stateHolder is TokensListStateHolder.Loading, + visible = stateHolder.isLoading, enter = fadeIn(), exit = fadeOut(), ) { @@ -122,13 +119,14 @@ private fun SaveChangesButton(onClick: () -> Unit) { private fun Preview_TokensListScreen_Loading() { TangemTheme { TokensListScreen( - stateHolder = TokensListStateHolder.Loading( + stateHolder = TokensListStateHolder.ReadContent( toolbarState = TokensListToolbarState.Title.Manage( titleResId = R.string.main_manage_tokens, onBackButtonClick = {}, onSearchButtonClick = {}, onAddCustomTokenClick = {}, ), + isLoading = true, tokens = emptyFlow(), onTokensLoadStateChanged = {}, ), @@ -148,6 +146,7 @@ private fun Preview_TokensListScreen_Manage() { onSearchButtonClick = {}, onAddCustomTokenClick = {}, ), + isLoading = false, tokens = flow { emit( PagingData.from( @@ -176,6 +175,7 @@ private fun Preview_TokensListScreen_Read() { onBackButtonClick = {}, onSearchButtonClick = {}, ), + isLoading = false, tokens = flow { emit( PagingData.from( diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt index d09d68b5d5..6917f88b1e 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt @@ -13,12 +13,9 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.extensions.getActiveIconRes import com.tangem.domain.common.extensions.canHandleToken import com.tangem.domain.common.extensions.fromNetworkId -import com.tangem.tap.common.extensions.dispatchDialogShow -import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.extensions.fullNameWithoutTestnet import com.tangem.tap.common.extensions.getGreyedOutIconRes import com.tangem.tap.common.extensions.getNetworkName -import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.features.tokens.domain.TokensListInteractor import com.tangem.tap.features.tokens.domain.models.Token import com.tangem.tap.features.tokens.domain.models.Token.Network @@ -29,10 +26,7 @@ import com.tangem.tap.features.tokens.presentation.states.TokenItemState import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState import com.tangem.tap.features.tokens.redux.TokenWithBlockchain -import com.tangem.tap.features.tokens.redux.TokensAction -import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.proxy.AppStateHolder -import com.tangem.tap.store import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider import com.tangem.utils.coroutines.Debouncer import com.tangem.wallet.R @@ -40,7 +34,9 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch import kotlinx.coroutines.plus +import kotlinx.coroutines.withContext import javax.inject.Inject import com.tangem.blockchain.common.Token as BlockchainToken @@ -72,15 +68,28 @@ internal class TokensListViewModel @Inject constructor( var uiState by mutableStateOf(value = getInitialUiState()) private set - private val addedTokenList: MutableList = args.mainScreenTokenList.toMutableList() - private val addedBlockchainList: MutableList = args.mainScreenBlockchainList.toMutableList() + private val changedTokensList: MutableList = args.mainScreenTokenList.toMutableList() + private val changedBlockchainList: MutableList = args.mainScreenBlockchainList.toMutableList() + + private var saveButtonPressed = false private fun getInitialUiState(): TokensListStateHolder { - return TokensListStateHolder.Loading( - toolbarState = getInitialToolbarState(), - tokens = getInitialTokensList(), - onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged, - ) + return if (args.isManageAccess) { + TokensListStateHolder.ManageContent( + toolbarState = getInitialToolbarState(), + isLoading = true, + tokens = getInitialTokensList(), + onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged, + onSaveButtonClick = actionsHandler::onSaveButtonClick, + ) + } else { + TokensListStateHolder.ReadContent( + toolbarState = getInitialToolbarState(), + isLoading = true, + tokens = getInitialTokensList(), + onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged, + ) + } } private fun getInitialToolbarState(): TokensListToolbarState { @@ -101,6 +110,8 @@ internal class TokensListViewModel @Inject constructor( } private fun getInitialTokensList(searchText: String = ""): Flow> { + if (searchText.isNotEmpty()) analyticsSender.sendWhenTokenSearched() + return interactor.getTokensList(searchText = searchText).map { it.map { token -> if (args.isManageAccess) createManageTokenContent(token) else createReadTokenContent(token) @@ -177,11 +188,11 @@ internal class TokensListViewModel @Inject constructor( private fun isAdded(address: String?, blockchain: Blockchain?): Boolean { return if (address != null) { - addedTokenList.any { addedToken -> + changedTokensList.any { addedToken -> address == addedToken.token.contractAddress && blockchain == addedToken.blockchain } } else { - addedBlockchainList.contains(blockchain) + changedBlockchainList.contains(blockchain) } } @@ -221,38 +232,22 @@ internal class TokensListViewModel @Inject constructor( } } - // FIXME("Necessary to avoid using redux actions") fun onNetworkClick() { - store.dispatchNotification(R.string.contract_address_copied_message) + router.showAddressCopiedNotification() } fun onTokensLoadStateChanged(state: LoadState) { - uiState = when (state) { - is LoadState.NotLoading -> { - analyticsSender.sendWhenTokenSearched() + uiState = uiState.copySealed(isLoading = state is LoadState.Loading || saveButtonPressed) + if (saveButtonPressed) saveButtonPressed = false + } - if (args.isManageAccess) { - TokensListStateHolder.ManageContent( - toolbarState = uiState.toolbarState, - tokens = uiState.tokens, - onTokensLoadStateChanged = uiState.onTokensLoadStateChanged, - onSaveButtonClick = this::onSaveButtonClick, - ) - } else { - TokensListStateHolder.ReadContent( - toolbarState = uiState.toolbarState, - tokens = uiState.tokens, - onTokensLoadStateChanged = uiState.onTokensLoadStateChanged, - ) - } - } - else -> { - TokensListStateHolder.Loading( - toolbarState = uiState.toolbarState, - tokens = uiState.tokens, - onTokensLoadStateChanged = uiState.onTokensLoadStateChanged, - ) - } + fun onSaveButtonClick() { + viewModelScope.launch(dispatchers.main) { + saveButtonPressed = true + analyticsSender.sendWhenSaveButtonClicked() + uiState = uiState.copySealed(isLoading = true) + withContext(dispatchers.io) { interactor.saveChanges(changedTokensList, changedBlockchainList) } + router.popBackStack() } } @@ -276,38 +271,34 @@ internal class TokensListViewModel @Inject constructor( } private fun updateBlockchainItem(toggledNetwork: NetworkItemState.ManageContent, blockchain: Blockchain) { - val isRemoveAction = addedBlockchainList.contains(blockchain) + val isRemoveAction = changedBlockchainList.contains(blockchain) if (isRemoveAction) { - val isTokenWithSameBlockchainFound = addedTokenList.any { it.blockchain == blockchain } + val isTokenWithSameBlockchainFound = changedTokensList.any { it.blockchain == blockchain } val isAddedOnMainScreen = args.mainScreenBlockchainList.contains(blockchain) if (isTokenWithSameBlockchainFound) { - store.dispatchDialogShow( - WalletDialog.TokensAreLinkedDialog( - currencyTitle = blockchain.name, - currencySymbol = blockchain.currency, - ), + router.openUnableHideMainTokenAlert( + tokenName = blockchain.name, + tokenSymbol = blockchain.currency, ) } else if (isAddedOnMainScreen) { - store.dispatchDialogShow( - WalletDialog.RemoveWalletDialog( - currencyTitle = blockchain.name, - onOk = { - analyticsSender.sendWhenBlockchainAdded(blockchain) - addedBlockchainList.remove(blockchain) - toggledNetwork.changeToggleState() - }, - ), + router.openRemoveWalletAlert( + tokenName = blockchain.name, + onOkClick = { + analyticsSender.sendWhenBlockchainAdded(blockchain) + changedBlockchainList.remove(blockchain) + toggledNetwork.changeToggleState() + }, ) } else { analyticsSender.sendWhenBlockchainRemoved(blockchain) - addedBlockchainList.remove(blockchain) + changedBlockchainList.remove(blockchain) toggledNetwork.changeToggleState() } } else { analyticsSender.sendWhenBlockchainAdded(blockchain) - addedBlockchainList.add(blockchain) + changedBlockchainList.add(blockchain) toggledNetwork.changeToggleState() } } @@ -327,25 +318,23 @@ internal class TokensListViewModel @Inject constructor( blockchain = toggledNetwork.blockchain, ) - val isRemoveAction = addedTokenList.contains(token) + val isRemoveAction = changedTokensList.contains(token) if (isRemoveAction) { val isAddedOnMainScreen = args.mainScreenTokenList.contains(token) if (isAddedOnMainScreen) { - store.dispatchDialogShow( - WalletDialog.RemoveWalletDialog( - currencyTitle = token.token.name, - onOk = { - analyticsSender.sendWhenTokenRemoved(token.token) - addedTokenList.remove(token) - toggledNetwork.changeToggleState() - }, - ), + router.openRemoveWalletAlert( + tokenName = token.token.name, + onOkClick = { + analyticsSender.sendWhenTokenRemoved(token.token) + changedTokensList.remove(token) + toggledNetwork.changeToggleState() + }, ) } else { analyticsSender.sendWhenTokenRemoved(token.token) - addedTokenList.remove(token) + changedTokensList.remove(token) toggledNetwork.changeToggleState() } } else { @@ -353,24 +342,14 @@ internal class TokensListViewModel @Inject constructor( !(reduxStateHolder.scanResponse?.card?.canHandleToken(token.blockchain) ?: false) if (isUnsupportedToken) { - store.dispatchDialogShow( - AppDialog.SimpleOkDialogRes( - headerId = R.string.common_warning, - messageId = R.string.alert_manage_tokens_unsupported_message, - ), - ) + router.openUnsupportedSoltanaNetworkAlert() } else { analyticsSender.sendWhenTokenAdded(token.token) - addedTokenList.add(token) + changedTokensList.add(token) toggledNetwork.changeToggleState() } } } - - private fun onSaveButtonClick() { - analyticsSender.sendWhenSaveButtonClicked() - store.dispatch(TokensAction.SaveChanges(addedTokenList, addedBlockchainList)) - } } private companion object { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index 7a3c9a9d17..e275b0c072 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -252,7 +252,7 @@ class TokensMiddleware { return DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive) } - private class DerivationData(val derivations: Pair>) + class DerivationData(val derivations: Pair>) private fun submitAdd(scanResponse: ScanResponse, currencyList: List) { val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index d134968349..33a5dcf0a4 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -71,7 +71,7 @@ kotlinSerialization = "1.4.1" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-197" +tangemBlockchainSdk = "develop-198" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-213" # tangemCardSdk = "0.0.1" # Keep it! - used for local builds From 3a33ef4bac25cbd713b14be9fa576e7ebe8e7d6e Mon Sep 17 00:00:00 2001 From: Tangem Date: Sat, 15 Apr 2023 00:13:58 +0900 Subject: [PATCH 22/30] Updated on 2026-08-14 --- .../common/compose/ComposeDialogManager.kt | 2 +- .../tap/common/extensions/Navigation.kt | 6 ++--- .../com/tangem/tap/common/redux/AppReducer.kt | 2 +- .../com/tangem/tap/common/redux/AppState.kt | 4 ++-- .../addCustomToken/AddCustomTokenFragment.kt | 4 ++-- .../compose/AddCustomTokenScreen.kt | 12 +++------- .../addCustomToken/compose/FormFieldViews.kt | 2 +- .../compose/HangingOverKeyboardView.kt | 2 +- .../compose/SelectTokenNetworkDialog.kt | 2 +- .../compose/test/ContractAddressTests.kt | 2 +- .../compose/test/TestCasesList.kt | 2 +- .../tangem/tap/features/home/HomeFragment.kt | 2 +- .../data/DefaultTokensListRepository.kt | 6 ++--- .../data/TangemApiTokensPagingSource.kt | 6 ++--- .../data/TestnetTokensPagingSource.kt | 6 ++--- .../data/converters/CoinsResponseConverter.kt | 4 ++-- .../TestnetTokensConfigConverter.kt | 4 ++-- .../di/TokensListFeatureTogglesModule.kt | 4 ++-- .../di/TokensListInteractorModule.kt | 8 +++---- .../di/TokensListRepositoryModule.kt | 6 ++--- .../{ => impl}/di/TokensListRouterModule.kt | 6 ++--- .../domain/DefaultTokensListInteractor.kt | 8 +++---- .../{ => impl}/domain/TokensListInteractor.kt | 6 ++--- .../{ => impl}/domain/TokensListRepository.kt | 4 ++-- .../tokens/{ => impl}/domain/models/Token.kt | 2 +- .../DefaultTokensListFeatureToggles.kt | 2 +- .../presentation/TokensListFragment.kt | 6 ++--- .../presentation/models/TokensListArgs.kt | 4 ++-- .../router/DefaultTokensListRouter.kt | 4 ++-- .../presentation/router/TokensListRouter.kt | 2 +- .../presentation/states/NetworkItemState.kt | 4 ++-- .../presentation/states/TokenItemState.kt | 2 +- .../states/TokensListStateHolder.kt | 2 +- .../states/TokensListToolbarState.kt | 2 +- .../presentation/ui/BriefNetworksList.kt | 4 ++-- .../presentation/ui/DetailedNetworksList.kt | 6 ++--- .../presentation/ui/NetworkItemArrow.kt | 2 +- .../{ => impl}/presentation/ui/TokenItem.kt | 4 ++-- .../presentation/ui/TokenListPreviewData.kt | 6 ++--- .../presentation/ui/TokensListScreen.kt | 8 +++---- .../presentation/ui/TokensListToolbar.kt | 8 +++---- .../viewmodels/TokensListAnalyticsSender.kt | 2 +- .../viewmodels/TokensListViewModel.kt | 22 +++++++++---------- .../AddTokensFragment.kt | 12 +++++----- .../tokens/{ => legacy}/redux/TokensAction.kt | 2 +- .../{ => legacy}/redux/TokensMiddleware.kt | 4 ++-- .../{ => legacy}/redux/TokensReducer.kt | 2 +- .../tokens/{ => legacy}/redux/TokensState.kt | 2 +- .../ui/compose/CurrenciesScreen.kt | 10 ++++----- .../ui/compose/CurrenciesWarning.kt | 2 +- .../ui/compose/CurrencyPlaceholderIcon.kt | 2 +- .../ui/compose/ListOfCurrencies.kt | 8 +++---- .../currencyItem/CurrencyExpandedContent.kt | 6 ++--- .../ui/compose/currencyItem/CurrencyItem.kt | 6 ++--- .../currencyItem/CurrencyItemHeader.kt | 8 +++---- .../ui/compose/currencyItem/NetworkItem.kt | 10 ++++----- .../wallet/ui/wallet/MultiWalletView.kt | 2 +- 57 files changed, 136 insertions(+), 142 deletions(-) rename app/src/main/java/com/tangem/tap/features/{tokens => }/addCustomToken/AddCustomTokenFragment.kt (95%) rename app/src/main/java/com/tangem/tap/features/{tokens => }/addCustomToken/compose/AddCustomTokenScreen.kt (96%) rename app/src/main/java/com/tangem/tap/features/{tokens => }/addCustomToken/compose/FormFieldViews.kt (99%) rename app/src/main/java/com/tangem/tap/features/{tokens => }/addCustomToken/compose/HangingOverKeyboardView.kt (93%) rename app/src/main/java/com/tangem/tap/features/{tokens => }/addCustomToken/compose/SelectTokenNetworkDialog.kt (92%) rename app/src/main/java/com/tangem/tap/features/{tokens => }/addCustomToken/compose/test/ContractAddressTests.kt (98%) rename app/src/main/java/com/tangem/tap/features/{tokens => }/addCustomToken/compose/test/TestCasesList.kt (96%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/data/DefaultTokensListRepository.kt (91%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/data/TangemApiTokensPagingSource.kt (92%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/data/TestnetTokensPagingSource.kt (87%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/data/converters/CoinsResponseConverter.kt (91%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/data/converters/TestnetTokensConfigConverter.kt (91%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/di/TokensListFeatureTogglesModule.kt (82%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/di/TokensListInteractorModule.kt (81%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/di/TokensListRepositoryModule.kt (84%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/di/TokensListRouterModule.kt (65%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/domain/DefaultTokensListInteractor.kt (97%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/domain/TokensListInteractor.kt (76%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/domain/TokensListRepository.kt (75%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/domain/models/Token.kt (94%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/featuretoggles/DefaultTokensListFeatureToggles.kt (91%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/TokensListFragment.kt (85%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/models/TokensListArgs.kt (82%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/router/DefaultTokensListRouter.kt (93%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/router/TokensListRouter.kt (93%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/states/NetworkItemState.kt (95%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/states/TokenItemState.kt (95%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/states/TokensListStateHolder.kt (97%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/states/TokensListToolbarState.kt (97%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/ui/BriefNetworksList.kt (94%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/ui/DetailedNetworksList.kt (96%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/ui/NetworkItemArrow.kt (97%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/ui/TokenItem.kt (98%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/ui/TokenListPreviewData.kt (92%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/ui/TokensListScreen.kt (95%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/ui/TokensListToolbar.kt (95%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/viewmodels/TokensListAnalyticsSender.kt (96%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => impl}/presentation/viewmodels/TokensListViewModel.kt (94%) rename app/src/main/java/com/tangem/tap/features/tokens/{presentation => legacy}/AddTokensFragment.kt (94%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/redux/TokensAction.kt (95%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/redux/TokensMiddleware.kt (99%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/redux/TokensReducer.kt (97%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/redux/TokensState.kt (98%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/ui/compose/CurrenciesScreen.kt (96%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/ui/compose/CurrenciesWarning.kt (96%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/ui/compose/CurrencyPlaceholderIcon.kt (95%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/ui/compose/ListOfCurrencies.kt (90%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/ui/compose/currencyItem/CurrencyExpandedContent.kt (91%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/ui/compose/currencyItem/CurrencyItem.kt (84%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/ui/compose/currencyItem/CurrencyItemHeader.kt (96%) rename app/src/main/java/com/tangem/tap/features/tokens/{ => legacy}/ui/compose/currencyItem/NetworkItem.kt (94%) diff --git a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt b/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt index 7afe67bf43..e762a3dabe 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt @@ -36,7 +36,7 @@ import com.tangem.domain.redux.domainStore import com.tangem.domain.redux.global.DomainGlobalAction import com.tangem.domain.redux.global.DomainGlobalState import com.tangem.tap.domain.moduleMessage.ModuleMessageConverter -import com.tangem.tap.features.tokens.addCustomToken.compose.SelectTokenNetworkDialog +import com.tangem.tap.features.addCustomToken.compose.SelectTokenNetworkDialog import com.tangem.wallet.R import org.rekotlin.StoreSubscriber diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index f6e77e9af9..7ad24431c6 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -9,6 +9,7 @@ import com.tangem.feature.referral.ReferralFragment import com.tangem.feature.swap.presentation.SwapFragment import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.FragmentShareTransition +import com.tangem.tap.features.addCustomToken.AddCustomTokenFragment import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment import com.tangem.tap.features.details.ui.cardsettings.CardSettingsFragment import com.tangem.tap.features.details.ui.details.DetailsFragment @@ -25,9 +26,8 @@ import com.tangem.tap.features.onboarding.products.wallet.ui.OnboardingWalletFra import com.tangem.tap.features.saveWallet.ui.SaveWalletBottomSheetFragment import com.tangem.tap.features.send.ui.SendFragment import com.tangem.tap.features.shop.ui.ShopFragment -import com.tangem.tap.features.tokens.addCustomToken.AddCustomTokenFragment -import com.tangem.tap.features.tokens.presentation.AddTokensFragment -import com.tangem.tap.features.tokens.presentation.TokensListFragment +import com.tangem.tap.features.tokens.impl.presentation.TokensListFragment +import com.tangem.tap.features.tokens.legacy.AddTokensFragment import com.tangem.tap.features.wallet.ui.WalletDetailsFragment import com.tangem.tap.features.wallet.ui.WalletFragment import com.tangem.tap.features.walletSelector.ui.WalletSelectorBottomSheetFragment diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index cb18e36047..7210599e41 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -15,7 +15,7 @@ import com.tangem.tap.features.send.redux.reducers.SendScreenReducer import com.tangem.tap.features.shop.redux.ShopReducer import com.tangem.tap.features.signin.redux.SignInReducer import com.tangem.tap.features.sprinklr.redux.SprinklrReducer -import com.tangem.tap.features.tokens.redux.TokensReducer +import com.tangem.tap.features.tokens.legacy.redux.TokensReducer import com.tangem.tap.features.wallet.redux.reducers.WalletReducer import com.tangem.tap.features.walletSelector.redux.WalletSelectorReducer import com.tangem.tap.features.welcome.redux.WelcomeReducer diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index d3000eb374..2efd12e515 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -35,8 +35,8 @@ import com.tangem.tap.features.signin.redux.SignInMiddleware import com.tangem.tap.features.signin.redux.SignInState import com.tangem.tap.features.sprinklr.redux.SprinklrMiddleware import com.tangem.tap.features.sprinklr.redux.SprinklrState -import com.tangem.tap.features.tokens.redux.TokensMiddleware -import com.tangem.tap.features.tokens.redux.TokensState +import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware +import com.tangem.tap.features.tokens.legacy.redux.TokensState import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.middlewares.WalletMiddleware import com.tangem.tap.features.walletSelector.redux.WalletSelectorMiddleware diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/AddCustomTokenFragment.kt b/app/src/main/java/com/tangem/tap/features/addCustomToken/AddCustomTokenFragment.kt similarity index 95% rename from app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/AddCustomTokenFragment.kt rename to app/src/main/java/com/tangem/tap/features/addCustomToken/AddCustomTokenFragment.kt index 2a41a990b6..39689b35e5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/AddCustomTokenFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/addCustomToken/AddCustomTokenFragment.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.addCustomToken +package com.tangem.tap.features.addCustomToken import android.os.Bundle import android.view.View @@ -19,7 +19,7 @@ import com.tangem.tap.common.compose.ClosePopupTrigger import com.tangem.tap.features.BaseStoreFragment import com.tangem.tap.features.FragmentOnBackPressedHandler import com.tangem.tap.features.addBackPressHandler -import com.tangem.tap.features.tokens.addCustomToken.compose.AddCustomTokenScreen +import com.tangem.tap.features.addCustomToken.compose.AddCustomTokenScreen import com.tangem.wallet.R import org.rekotlin.StoreSubscriber diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/AddCustomTokenScreen.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt rename to app/src/main/java/com/tangem/tap/features/addCustomToken/compose/AddCustomTokenScreen.kt index d5c9bfe9c0..9342b868d1 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/AddCustomTokenScreen.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.addCustomToken.compose +package com.tangem.tap.features.addCustomToken.compose import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -52,17 +52,11 @@ import com.tangem.tap.common.compose.AddCustomTokenWarning import com.tangem.tap.common.compose.ClosePopupTrigger import com.tangem.tap.common.compose.ComposeDialogManager import com.tangem.tap.domain.moduleMessage.ModuleMessageConverter -import com.tangem.tap.features.tokens.addCustomToken.compose.test.TestCase -import com.tangem.tap.features.tokens.addCustomToken.compose.test.TestCasesList +import com.tangem.tap.features.addCustomToken.compose.test.TestCase +import com.tangem.tap.features.addCustomToken.compose.test.TestCasesList import com.tangem.wallet.R import kotlinx.coroutines.launch -/** -[REDACTED_AUTHOR] - */ -@Suppress("UnusedPrivateClass") -private class AddCustomTokenScreen // for simple search - @OptIn(ExperimentalMaterialApi::class) @Composable fun AddCustomTokenScreen(state: MutableState, closePopupTrigger: ClosePopupTrigger) { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/FormFieldViews.kt b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/FormFieldViews.kt similarity index 99% rename from app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/FormFieldViews.kt rename to app/src/main/java/com/tangem/tap/features/addCustomToken/compose/FormFieldViews.kt index 7a14ca2d85..069d9f6823 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/FormFieldViews.kt +++ b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/FormFieldViews.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.addCustomToken.compose +package com.tangem.tap.features.addCustomToken.compose import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.runtime.Composable diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/HangingOverKeyboardView.kt b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/HangingOverKeyboardView.kt similarity index 93% rename from app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/HangingOverKeyboardView.kt rename to app/src/main/java/com/tangem/tap/features/addCustomToken/compose/HangingOverKeyboardView.kt index a330583a8b..54f0d74243 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/HangingOverKeyboardView.kt +++ b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/HangingOverKeyboardView.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.addCustomToken.compose +package com.tangem.tap.features.addCustomToken.compose import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/SelectTokenNetworkDialog.kt b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/SelectTokenNetworkDialog.kt similarity index 92% rename from app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/SelectTokenNetworkDialog.kt rename to app/src/main/java/com/tangem/tap/features/addCustomToken/compose/SelectTokenNetworkDialog.kt index 5dc938ed1c..b30ab3c9e9 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/SelectTokenNetworkDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/SelectTokenNetworkDialog.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.addCustomToken.compose +package com.tangem.tap.features.addCustomToken.compose import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/ContractAddressTests.kt b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/test/ContractAddressTests.kt similarity index 98% rename from app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/ContractAddressTests.kt rename to app/src/main/java/com/tangem/tap/features/addCustomToken/compose/test/ContractAddressTests.kt index 581af5a8df..6ba18d8a22 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/ContractAddressTests.kt +++ b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/test/ContractAddressTests.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.addCustomToken.compose.test +package com.tangem.tap.features.addCustomToken.compose.test import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/TestCasesList.kt b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/test/TestCasesList.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/TestCasesList.kt rename to app/src/main/java/com/tangem/tap/features/addCustomToken/compose/test/TestCasesList.kt index ef6a3bc4cd..7f92a0a666 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/TestCasesList.kt +++ b/app/src/main/java/com/tangem/tap/features/addCustomToken/compose/test/TestCasesList.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.addCustomToken.compose.test +package com.tangem.tap.features.addCustomToken.compose.test import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt index 372866fafc..64ea0798e0 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -20,7 +20,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.home.compose.StoriesScreen import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.home.redux.HomeState -import com.tangem.tap.features.tokens.redux.TokensAction +import com.tangem.tap.features.tokens.legacy.redux.TokensAction import com.tangem.tap.store import org.rekotlin.StoreSubscriber diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/DefaultTokensListRepository.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/DefaultTokensListRepository.kt similarity index 91% rename from app/src/main/java/com/tangem/tap/features/tokens/data/DefaultTokensListRepository.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/data/DefaultTokensListRepository.kt index ba522709c6..7ff7b78228 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/data/DefaultTokensListRepository.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/DefaultTokensListRepository.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.data +package com.tangem.tap.features.tokens.impl.data import androidx.paging.Pager import androidx.paging.PagingConfig @@ -6,8 +6,8 @@ import androidx.paging.PagingData import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.local.testnet.TestnetTokensStorage import com.tangem.domain.common.TapWorkarounds.isTestCard -import com.tangem.tap.features.tokens.domain.TokensListRepository -import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.impl.domain.TokensListRepository +import com.tangem.tap.features.tokens.impl.domain.models.Token import com.tangem.tap.proxy.AppStateHolder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/TangemApiTokensPagingSource.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/TangemApiTokensPagingSource.kt similarity index 92% rename from app/src/main/java/com/tangem/tap/features/tokens/data/TangemApiTokensPagingSource.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/data/TangemApiTokensPagingSource.kt index d9d63213bd..2cae031963 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/data/TangemApiTokensPagingSource.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/TangemApiTokensPagingSource.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.data +package com.tangem.tap.features.tokens.impl.data import androidx.paging.PagingSource import androidx.paging.PagingState @@ -6,8 +6,8 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.domain.common.extensions.supportedBlockchains import com.tangem.domain.common.extensions.toNetworkId -import com.tangem.tap.features.tokens.data.converters.CoinsResponseConverter -import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.impl.data.converters.CoinsResponseConverter +import com.tangem.tap.features.tokens.impl.domain.models.Token import com.tangem.tap.proxy.AppStateHolder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.runCatching diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/TestnetTokensPagingSource.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/TestnetTokensPagingSource.kt similarity index 87% rename from app/src/main/java/com/tangem/tap/features/tokens/data/TestnetTokensPagingSource.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/data/TestnetTokensPagingSource.kt index 87943ee140..9525c329ba 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/data/TestnetTokensPagingSource.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/TestnetTokensPagingSource.kt @@ -1,11 +1,11 @@ -package com.tangem.tap.features.tokens.data +package com.tangem.tap.features.tokens.impl.data import androidx.paging.PagingSource import androidx.paging.PagingState import com.tangem.datasource.local.testnet.TestnetTokensStorage import com.tangem.datasource.local.testnet.models.TestnetTokensConfig -import com.tangem.tap.features.tokens.data.converters.TestnetTokensConfigConverter -import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.impl.data.converters.TestnetTokensConfigConverter +import com.tangem.tap.features.tokens.impl.domain.models.Token /** * Paging source that get tokens by testnet tokens config diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt similarity index 91% rename from app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt index d8b9477c16..64739f61a7 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/CoinsResponseConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt @@ -1,10 +1,10 @@ -package com.tangem.tap.features.tokens.data.converters +package com.tangem.tap.features.tokens.impl.data.converters import com.tangem.blockchain.common.Blockchain import com.tangem.datasource.api.tangemTech.models.CoinsResponse import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.tap.domain.tokens.getIconUrl -import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.impl.domain.models.Token import com.tangem.utils.converter.Converter /** diff --git a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/TestnetTokensConfigConverter.kt similarity index 91% rename from app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/TestnetTokensConfigConverter.kt index b010b81704..269690c18b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/data/converters/TestnetTokensConfigConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/TestnetTokensConfigConverter.kt @@ -1,10 +1,10 @@ -package com.tangem.tap.features.tokens.data.converters +package com.tangem.tap.features.tokens.impl.data.converters import com.tangem.blockchain.common.Blockchain import com.tangem.datasource.local.testnet.models.TestnetTokensConfig import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.tap.domain.tokens.getIconUrl -import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.impl.domain.models.Token import com.tangem.utils.converter.Converter /** diff --git a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListFeatureTogglesModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListFeatureTogglesModule.kt similarity index 82% rename from app/src/main/java/com/tangem/tap/features/tokens/di/TokensListFeatureTogglesModule.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListFeatureTogglesModule.kt index be1a69cc5b..d2b8ae0470 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListFeatureTogglesModule.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListFeatureTogglesModule.kt @@ -1,8 +1,8 @@ -package com.tangem.tap.features.tokens.di +package com.tangem.tap.features.tokens.impl.di import com.tangem.core.featuretoggle.manager.FeatureTogglesManager import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles -import com.tangem.tap.features.tokens.featuretoggles.DefaultTokensListFeatureToggles +import com.tangem.tap.features.tokens.impl.featuretoggles.DefaultTokensListFeatureToggles import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListInteractorModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListInteractorModule.kt similarity index 81% rename from app/src/main/java/com/tangem/tap/features/tokens/di/TokensListInteractorModule.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListInteractorModule.kt index c27bc5f8e0..ddc7a2a15b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListInteractorModule.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListInteractorModule.kt @@ -1,10 +1,10 @@ -package com.tangem.tap.features.tokens.di +package com.tangem.tap.features.tokens.impl.di import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.local.testnet.TestnetTokensStorage -import com.tangem.tap.features.tokens.data.DefaultTokensListRepository -import com.tangem.tap.features.tokens.domain.DefaultTokensListInteractor -import com.tangem.tap.features.tokens.domain.TokensListInteractor +import com.tangem.tap.features.tokens.impl.data.DefaultTokensListRepository +import com.tangem.tap.features.tokens.impl.domain.DefaultTokensListInteractor +import com.tangem.tap.features.tokens.impl.domain.TokensListInteractor import com.tangem.tap.proxy.AppStateHolder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module diff --git a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRepositoryModule.kt similarity index 84% rename from app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRepositoryModule.kt index e71a3a6531..dbba8fe0dd 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRepositoryModule.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRepositoryModule.kt @@ -1,9 +1,9 @@ -package com.tangem.tap.features.tokens.di +package com.tangem.tap.features.tokens.impl.di import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.local.testnet.TestnetTokensStorage -import com.tangem.tap.features.tokens.data.DefaultTokensListRepository -import com.tangem.tap.features.tokens.domain.TokensListRepository +import com.tangem.tap.features.tokens.impl.data.DefaultTokensListRepository +import com.tangem.tap.features.tokens.impl.domain.TokensListRepository import com.tangem.tap.proxy.AppStateHolder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module diff --git a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRouterModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRouterModule.kt similarity index 65% rename from app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRouterModule.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRouterModule.kt index 9716a3e027..2a7da5cca4 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/di/TokensListRouterModule.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRouterModule.kt @@ -1,7 +1,7 @@ -package com.tangem.tap.features.tokens.di +package com.tangem.tap.features.tokens.impl.di -import com.tangem.tap.features.tokens.presentation.router.DefaultTokensListRouter -import com.tangem.tap.features.tokens.presentation.router.TokensListRouter +import com.tangem.tap.features.tokens.impl.presentation.router.DefaultTokensListRouter +import com.tangem.tap.features.tokens.impl.presentation.router.TokensListRouter import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/DefaultTokensListInteractor.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/DefaultTokensListInteractor.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/tokens/domain/DefaultTokensListInteractor.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/domain/DefaultTokensListInteractor.kt index 5012ccebc5..290dfa225f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/domain/DefaultTokensListInteractor.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/DefaultTokensListInteractor.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.domain +package com.tangem.tap.features.tokens.impl.domain import androidx.paging.PagingData import com.tangem.blockchain.common.Blockchain @@ -18,9 +18,9 @@ import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TapError import com.tangem.tap.domain.model.WalletDataModel -import com.tangem.tap.features.tokens.domain.models.Token -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain -import com.tangem.tap.features.tokens.redux.TokensMiddleware +import com.tangem.tap.features.tokens.impl.domain.models.Token +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.proxy.AppStateHolder import com.tangem.tap.store diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListInteractor.kt similarity index 76% rename from app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListInteractor.kt index 6ffe49b885..fee08220bf 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListInteractor.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListInteractor.kt @@ -1,9 +1,9 @@ -package com.tangem.tap.features.tokens.domain +package com.tangem.tap.features.tokens.impl.domain import androidx.paging.PagingData import com.tangem.blockchain.common.Blockchain -import com.tangem.tap.features.tokens.domain.models.Token -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.impl.domain.models.Token +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain import kotlinx.coroutines.flow.Flow /** diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListRepository.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListRepository.kt similarity index 75% rename from app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListRepository.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListRepository.kt index 95fdde59ff..11fea0d2fc 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/domain/TokensListRepository.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListRepository.kt @@ -1,7 +1,7 @@ -package com.tangem.tap.features.tokens.domain +package com.tangem.tap.features.tokens.impl.domain import androidx.paging.PagingData -import com.tangem.tap.features.tokens.domain.models.Token +import com.tangem.tap.features.tokens.impl.domain.models.Token import kotlinx.coroutines.flow.Flow /** diff --git a/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/models/Token.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/domain/models/Token.kt index 750dfc94f5..72c6ecfdae 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/domain/models/Token.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/models/Token.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.domain.models +package com.tangem.tap.features.tokens.impl.domain.models import com.tangem.blockchain.common.Blockchain diff --git a/app/src/main/java/com/tangem/tap/features/tokens/featuretoggles/DefaultTokensListFeatureToggles.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/featuretoggles/DefaultTokensListFeatureToggles.kt similarity index 91% rename from app/src/main/java/com/tangem/tap/features/tokens/featuretoggles/DefaultTokensListFeatureToggles.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/featuretoggles/DefaultTokensListFeatureToggles.kt index eedb10b4a9..b9aa44c70f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/featuretoggles/DefaultTokensListFeatureToggles.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/featuretoggles/DefaultTokensListFeatureToggles.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.featuretoggles +package com.tangem.tap.features.tokens.impl.featuretoggles import com.tangem.core.featuretoggle.manager.FeatureTogglesManager import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt similarity index 85% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt index 55615e908b..0a455118c1 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/TokensListFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation +package com.tangem.tap.features.tokens.impl.presentation import android.os.Bundle import android.view.LayoutInflater @@ -10,8 +10,8 @@ import androidx.fragment.app.Fragment import androidx.hilt.navigation.compose.hiltViewModel import androidx.transition.TransitionInflater import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.ui.TokensListScreen -import com.tangem.tap.features.tokens.presentation.viewmodels.TokensListViewModel +import com.tangem.tap.features.tokens.impl.presentation.ui.TokensListScreen +import com.tangem.tap.features.tokens.impl.presentation.viewmodels.TokensListViewModel import com.tangem.wallet.R import dagger.hilt.android.AndroidEntryPoint diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/models/TokensListArgs.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/models/TokensListArgs.kt similarity index 82% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/models/TokensListArgs.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/models/TokensListArgs.kt index de2b9a97bf..88fdf58dd7 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/models/TokensListArgs.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/models/TokensListArgs.kt @@ -1,7 +1,7 @@ -package com.tangem.tap.features.tokens.presentation.models +package com.tangem.tap.features.tokens.impl.presentation.models import com.tangem.blockchain.common.Blockchain -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain import com.tangem.tap.store /** diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt similarity index 93% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt index f266e0805f..73e09a433e 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/DefaultTokensListRouter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt @@ -1,10 +1,10 @@ -package com.tangem.tap.features.tokens.presentation.router +package com.tangem.tap.features.tokens.impl.presentation.router import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.features.tokens.redux.TokensAction +import com.tangem.tap.features.tokens.legacy.redux.TokensAction import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.store import com.tangem.wallet.R diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/TokensListRouter.kt similarity index 93% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/TokensListRouter.kt index ccc7ed37cb..cc4f49409c 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/router/TokensListRouter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/TokensListRouter.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.router +package com.tangem.tap.features.tokens.impl.presentation.router /** Tokens list feature router */ internal interface TokensListRouter { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/NetworkItemState.kt similarity index 95% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/NetworkItemState.kt index c6967c78e4..081a399e06 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/NetworkItemState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/NetworkItemState.kt @@ -1,10 +1,10 @@ -package com.tangem.tap.features.tokens.presentation.states +package com.tangem.tap.features.tokens.impl.presentation.states import androidx.compose.runtime.MutableState import com.tangem.blockchain.common.Blockchain import com.tangem.core.ui.extensions.getActiveIconRes import com.tangem.tap.common.extensions.getGreyedOutIconRes -import com.tangem.tap.features.tokens.redux.ContractAddress +import com.tangem.tap.features.tokens.legacy.redux.ContractAddress /** * Network item state diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokenItemState.kt similarity index 95% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokenItemState.kt index e3ab7e2553..603989d157 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokenItemState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokenItemState.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.states +package com.tangem.tap.features.tokens.impl.presentation.states import kotlinx.collections.immutable.ImmutableList diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt index a7368f383d..669242641f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.states +package com.tangem.tap.features.tokens.impl.presentation.states import androidx.paging.LoadState import androidx.paging.PagingData diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListToolbarState.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListToolbarState.kt index 0fff69aabd..b4104f692b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/states/TokensListToolbarState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListToolbarState.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.states +package com.tangem.tap.features.tokens.impl.presentation.states /** Toolbar state */ sealed interface TokensListToolbarState { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt index bd3605c70e..9ef5db3888 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/BriefNetworksList.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.ui +package com.tangem.tap.features.tokens.impl.presentation.ui import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn @@ -18,7 +18,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.states.NetworkItemState +import com.tangem.tap.features.tokens.impl.presentation.states.NetworkItemState import kotlinx.collections.immutable.ImmutableCollection /** diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/DetailedNetworksList.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/DetailedNetworksList.kt index bdf39d31e9..28efb5d313 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/DetailedNetworksList.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/DetailedNetworksList.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.ui +package com.tangem.tap.features.tokens.impl.presentation.ui import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically @@ -34,8 +34,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.states.NetworkItemState -import com.tangem.tap.features.tokens.presentation.states.TokenItemState +import com.tangem.tap.features.tokens.impl.presentation.states.NetworkItemState +import com.tangem.tap.features.tokens.impl.presentation.states.TokenItemState import kotlinx.collections.immutable.ImmutableCollection /** diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/NetworkItemArrow.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/NetworkItemArrow.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/NetworkItemArrow.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/NetworkItemArrow.kt index 5aadb66fa1..6e9be1c229 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/NetworkItemArrow.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/NetworkItemArrow.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.ui +package com.tangem.tap.features.tokens.impl.presentation.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt similarity index 98% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt index bd6b760fd5..3545c6a2a5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.ui +package com.tangem.tap.features.tokens.impl.presentation.ui import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility @@ -38,7 +38,7 @@ import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.common.compose.extensions.toPx -import com.tangem.tap.features.tokens.presentation.states.TokenItemState +import com.tangem.tap.features.tokens.impl.presentation.states.TokenItemState import com.tangem.wallet.R /** diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenListPreviewData.kt similarity index 92% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenListPreviewData.kt index efed29fd37..3fb8f93097 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokenListPreviewData.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenListPreviewData.kt @@ -1,9 +1,9 @@ -package com.tangem.tap.features.tokens.presentation.ui +package com.tangem.tap.features.tokens.impl.presentation.ui import androidx.compose.runtime.mutableStateOf import com.tangem.blockchain.common.Blockchain -import com.tangem.tap.features.tokens.presentation.states.NetworkItemState -import com.tangem.tap.features.tokens.presentation.states.TokenItemState +import com.tangem.tap.features.tokens.impl.presentation.states.NetworkItemState +import com.tangem.tap.features.tokens.impl.presentation.states.TokenItemState import com.tangem.wallet.R import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt similarity index 95% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt index 57f720ee1c..6d4494dcf5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.ui +package com.tangem.tap.features.tokens.impl.presentation.ui import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility @@ -30,9 +30,9 @@ import androidx.paging.compose.items import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.states.TokenItemState -import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder -import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState +import com.tangem.tap.features.tokens.impl.presentation.states.TokenItemState +import com.tangem.tap.features.tokens.impl.presentation.states.TokensListStateHolder +import com.tangem.tap.features.tokens.impl.presentation.states.TokensListToolbarState import com.tangem.wallet.R import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flow diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListToolbar.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListToolbar.kt similarity index 95% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListToolbar.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListToolbar.kt index f3bb8bbafd..03ae578e8a 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/ui/TokensListToolbar.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListToolbar.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.ui +package com.tangem.tap.features.tokens.impl.presentation.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -33,9 +33,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState -import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState.InputField -import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState.Title +import com.tangem.tap.features.tokens.impl.presentation.states.TokensListToolbarState +import com.tangem.tap.features.tokens.impl.presentation.states.TokensListToolbarState.InputField +import com.tangem.tap.features.tokens.impl.presentation.states.TokensListToolbarState.Title import com.tangem.wallet.R import kotlinx.coroutines.delay diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListAnalyticsSender.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListAnalyticsSender.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListAnalyticsSender.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListAnalyticsSender.kt index 615f039a8f..8e839d1ddd 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListAnalyticsSender.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListAnalyticsSender.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.viewmodels +package com.tangem.tap.features.tokens.impl.presentation.viewmodels import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Token diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt rename to app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt index 6917f88b1e..d709e49df6 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/viewmodels/TokensListViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation.viewmodels +package com.tangem.tap.features.tokens.impl.presentation.viewmodels import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -16,16 +16,16 @@ import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.tap.common.extensions.fullNameWithoutTestnet import com.tangem.tap.common.extensions.getGreyedOutIconRes import com.tangem.tap.common.extensions.getNetworkName -import com.tangem.tap.features.tokens.domain.TokensListInteractor -import com.tangem.tap.features.tokens.domain.models.Token -import com.tangem.tap.features.tokens.domain.models.Token.Network -import com.tangem.tap.features.tokens.presentation.models.TokensListArgs -import com.tangem.tap.features.tokens.presentation.router.TokensListRouter -import com.tangem.tap.features.tokens.presentation.states.NetworkItemState -import com.tangem.tap.features.tokens.presentation.states.TokenItemState -import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder -import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.impl.domain.TokensListInteractor +import com.tangem.tap.features.tokens.impl.domain.models.Token +import com.tangem.tap.features.tokens.impl.domain.models.Token.Network +import com.tangem.tap.features.tokens.impl.presentation.models.TokensListArgs +import com.tangem.tap.features.tokens.impl.presentation.router.TokensListRouter +import com.tangem.tap.features.tokens.impl.presentation.states.NetworkItemState +import com.tangem.tap.features.tokens.impl.presentation.states.TokenItemState +import com.tangem.tap.features.tokens.impl.presentation.states.TokensListStateHolder +import com.tangem.tap.features.tokens.impl.presentation.states.TokensListToolbarState +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain import com.tangem.tap.proxy.AppStateHolder import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider import com.tangem.utils.coroutines.Debouncer diff --git a/app/src/main/java/com/tangem/tap/features/tokens/presentation/AddTokensFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/AddTokensFragment.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/tokens/presentation/AddTokensFragment.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/AddTokensFragment.kt index c2e0aa1302..3d6216bf22 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/presentation/AddTokensFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/AddTokensFragment.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.presentation +package com.tangem.tap.features.tokens.legacy import android.os.Bundle import android.view.Menu @@ -22,11 +22,11 @@ import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.BaseFragment import com.tangem.tap.features.addBackPressHandler -import com.tangem.tap.features.tokens.redux.ContractAddress -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain -import com.tangem.tap.features.tokens.redux.TokensAction -import com.tangem.tap.features.tokens.redux.TokensState -import com.tangem.tap.features.tokens.ui.compose.CurrenciesScreen +import com.tangem.tap.features.tokens.legacy.redux.ContractAddress +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.redux.TokensAction +import com.tangem.tap.features.tokens.legacy.redux.TokensState +import com.tangem.tap.features.tokens.legacy.ui.compose.CurrenciesScreen import com.tangem.tap.mainScope import com.tangem.tap.store import com.tangem.wallet.R diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensAction.kt similarity index 95% rename from app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensAction.kt index 0c87bc313a..2831a00547 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensAction.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.redux +package com.tangem.tap.features.tokens.legacy.redux import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensMiddleware.kt similarity index 99% rename from app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensMiddleware.kt index e275b0c072..dfb76ced9e 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensMiddleware.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.redux +package com.tangem.tap.features.tokens.legacy.redux import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle @@ -8,9 +8,9 @@ import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.guard import com.tangem.common.extensions.toMapKey import com.tangem.common.flatMap -import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.common.services.Result import com.tangem.core.analytics.Analytics +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.DomainWrapped import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TapWorkarounds.derivationStyle diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensReducer.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensReducer.kt index c792805d9b..7b5d5eaef5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensReducer.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.redux +package com.tangem.tap.features.tokens.legacy.redux import com.tangem.tap.common.redux.AppState import org.rekotlin.Action diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensState.kt similarity index 98% rename from app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensState.kt index 8015b9d1d5..432b422128 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensState.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.redux +package com.tangem.tap.features.tokens.legacy.redux import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesScreen.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesScreen.kt index f236111d4a..6088fde47a 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesScreen.kt @@ -1,6 +1,6 @@ @file:Suppress("MagicNumber") -package com.tangem.tap.features.tokens.ui.compose +package com.tangem.tap.features.tokens.legacy.ui.compose import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween @@ -40,10 +40,10 @@ import com.tangem.tap.common.compose.extensions.removeAndNotify import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.tokens.redux.ContractAddress -import com.tangem.tap.features.tokens.redux.LoadCoinsState -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain -import com.tangem.tap.features.tokens.redux.TokensState +import com.tangem.tap.features.tokens.legacy.redux.ContractAddress +import com.tangem.tap.features.tokens.legacy.redux.LoadCoinsState +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.redux.TokensState import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.store import com.tangem.wallet.R diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesWarning.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesWarning.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesWarning.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesWarning.kt index bfd230a1c7..b4b94b8edb 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesWarning.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesWarning.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.ui.compose +package com.tangem.tap.features.tokens.legacy.ui.compose import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyPlaceholderIcon.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrencyPlaceholderIcon.kt similarity index 95% rename from app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyPlaceholderIcon.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrencyPlaceholderIcon.kt index 188c75e57b..43a2885497 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrencyPlaceholderIcon.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrencyPlaceholderIcon.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.ui.compose +package com.tangem.tap.features.tokens.legacy.ui.compose import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ListOfCurrencies.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/ListOfCurrencies.kt similarity index 90% rename from app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ListOfCurrencies.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/ListOfCurrencies.kt index 1c5ba31d04..4f067daa9d 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/ListOfCurrencies.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/ListOfCurrencies.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.ui.compose +package com.tangem.tap.features.tokens.legacy.ui.compose import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues @@ -15,9 +15,9 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.tap.common.compose.extensions.HideKeyboardOnScroll import com.tangem.tap.common.compose.extensions.OnBottomReached import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.tokens.redux.ContractAddress -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain -import com.tangem.tap.features.tokens.ui.compose.currencyItem.CurrencyItem +import com.tangem.tap.features.tokens.legacy.redux.ContractAddress +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem.CurrencyItem @Suppress("LongParameterList") @Composable diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyExpandedContent.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyExpandedContent.kt similarity index 91% rename from app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyExpandedContent.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyExpandedContent.kt index 4783c5ac67..9ea93f61d6 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyExpandedContent.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyExpandedContent.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.ui.compose.currencyItem +package com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically @@ -12,8 +12,8 @@ import androidx.compose.ui.Modifier import com.tangem.blockchain.common.Blockchain import com.tangem.tap.domain.tokens.Contract import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.tokens.redux.ContractAddress -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.redux.ContractAddress +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain @Suppress("LongParameterList") @Composable diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItem.kt similarity index 84% rename from app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItem.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItem.kt index c2aa9f238f..a15c17000f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItem.kt @@ -1,11 +1,11 @@ -package com.tangem.tap.features.tokens.ui.compose.currencyItem +package com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import com.tangem.blockchain.common.Blockchain import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.tokens.redux.ContractAddress -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.redux.ContractAddress +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain @Suppress("LongParameterList") @Composable diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemHeader.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItemHeader.kt similarity index 96% rename from app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemHeader.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItemHeader.kt index bcc681addb..bf5fc63457 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemHeader.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItemHeader.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.ui.compose.currencyItem +package com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -36,9 +36,9 @@ import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.tap.common.extensions.getGreyedOutIconRes import com.tangem.tap.domain.tokens.Contract import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain -import com.tangem.tap.features.tokens.ui.compose.CurrencyPlaceholderIcon -import com.tangem.tap.features.tokens.ui.compose.fullName +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.ui.compose.CurrencyPlaceholderIcon +import com.tangem.tap.features.tokens.legacy.ui.compose.fullName import com.tangem.wallet.R @Suppress("LongMethod", "MagicNumber") diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/NetworkItem.kt similarity index 94% rename from app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt rename to app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/NetworkItem.kt index ceb4e333c7..4d7eab3fb6 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/NetworkItem.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.tokens.ui.compose.currencyItem +package com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -37,10 +37,10 @@ import com.tangem.tap.common.extensions.getGreyedOutIconRes import com.tangem.tap.common.extensions.getNetworkName import com.tangem.tap.domain.tokens.Contract import com.tangem.tap.domain.tokens.Currency -import com.tangem.tap.features.tokens.presentation.ui.NetworkItemArrow -import com.tangem.tap.features.tokens.redux.ContractAddress -import com.tangem.tap.features.tokens.redux.TokenWithBlockchain -import com.tangem.tap.features.tokens.ui.compose.CurrencyPlaceholderIcon +import com.tangem.tap.features.tokens.impl.presentation.ui.NetworkItemArrow +import com.tangem.tap.features.tokens.legacy.redux.ContractAddress +import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.ui.compose.CurrencyPlaceholderIcon @Suppress("LongParameterList", "LongMethod", "MagicNumber") @OptIn(ExperimentalFoundationApi::class) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index f981a8beca..dfe3f32704 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -14,7 +14,7 @@ import com.tangem.tap.common.extensions.show import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.model.TotalFiatBalance -import com.tangem.tap.features.tokens.redux.TokensAction +import com.tangem.tap.features.tokens.legacy.redux.TokensAction import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState From 0299f1b6a7974f32574911578d66b5e903cf9b38 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 14 Apr 2023 20:24:38 +0300 Subject: [PATCH 23/30] Updated on 2026-08-14 --- core/res/src/main/res/values-zh-rTW/strings-blockchain.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/res/src/main/res/values-zh-rTW/strings-blockchain.xml b/core/res/src/main/res/values-zh-rTW/strings-blockchain.xml index d593a969ce..56e05a6b07 100644 --- a/core/res/src/main/res/values-zh-rTW/strings-blockchain.xml +++ b/core/res/src/main/res/values-zh-rTW/strings-blockchain.xml @@ -4,7 +4,7 @@ 遺留資產 獲取費用失敗 沒有足夠的資金進行交易。請先入金 - Due to Kaspa limitations only %1$d UTXOs can fit in a single transaction. This means you can only send %2$s or less. You need to reduce the amount. + 由於 Kaspa 的限制,只有%1$d UTXO 可以放入單次交易中。這意味著您只能發送%2$s或更少數量。您需要減少數量。 加載 %1$s+ %2$s 以創建帳戶 目標帳戶未激活。發送 %s 或更多以激活帳戶 區塊鏈內部錯誤 From 8522a53690c543e1764d72525871fb6b814fda5f Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Apr 2023 14:25:48 +0400 Subject: [PATCH 24/30] Updated on 2026-08-14 --- .../com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt | 1 + app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt | 3 ++- domain/src/main/java/com/tangem/domain/common/CardDTO.kt | 2 +- gradle/dependencies.toml | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt b/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt index 0a06bf876e..a2eecd43e4 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt @@ -123,6 +123,7 @@ object TangemSdkErrorMapper { is TangemSdkError.ResetBackupFailedHasBackedUpWallets -> error is TangemSdkError.KeysImportDisabled -> error is TangemSdkError.Underlying -> error + is TangemSdkError.UserCodeRecoveryDisabled -> error } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 11faf6ba4a..c9d4a5e39c 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -18,10 +18,10 @@ import com.tangem.common.core.Config import com.tangem.common.core.TangemSdkError import com.tangem.common.core.UserCodeRequestPolicy import com.tangem.common.extensions.ByteArrayKey -import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.common.map import com.tangem.common.usersCode.UserCodeRepository import com.tangem.core.analytics.Analytics +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ScanResponse import com.tangem.operations.CommandResponse @@ -240,6 +240,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co allowUntrustedCards = true, filter = CardFilter( allowedCardTypes = FirmwareVersion.FirmwareType.values().toList(), + maxFirmwareVersion = FirmwareVersion(major = 4, minor = 52), ), ) } diff --git a/domain/src/main/java/com/tangem/domain/common/CardDTO.kt b/domain/src/main/java/com/tangem/domain/common/CardDTO.kt index fa4cbe9f42..ffe33e01e2 100644 --- a/domain/src/main/java/com/tangem/domain/common/CardDTO.kt +++ b/domain/src/main/java/com/tangem/domain/common/CardDTO.kt @@ -105,7 +105,7 @@ data class CardDTO( maxWalletsCount = settings.maxWalletsCount, isSettingAccessCodeAllowed = settings.isSettingAccessCodeAllowed, isSettingPasscodeAllowed = settings.isSettingPasscodeAllowed, - isResettingUserCodesAllowed = settings.isResettingUserCodesAllowed, + isResettingUserCodesAllowed = settings.isRemovingUserCodesAllowed, isLinkedTerminalEnabled = settings.isLinkedTerminalEnabled, isBackupAllowed = settings.isBackupAllowed, supportedEncryptionModes = settings.supportedEncryptionModes, diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 33a5dcf0a4..ce5ce3a82d 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -73,7 +73,7 @@ kotlinSerialization = "1.4.1" # region Tangem tangemBlockchainSdk = "develop-198" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-213" +tangemCardSdk = "develop-218" # tangemCardSdk = "0.0.1" # Keep it! - used for local builds # endregion Tangem From 673774bf7cc07a0d0b2af795e5a27a416cb82908 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Apr 2023 16:44:49 +0300 Subject: [PATCH 25/30] Updated on 2026-08-14 --- core/res/src/main/res/values-ru/strings.xml | 2 +- core/res/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 105e37499d..f11b1ab441 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -393,7 +393,7 @@ Мои кошельки Разблокировать все с %s Создать PayString - Проверить адрес + История транзакций Сеть недоступна Блокчейн недоступен. Попробуй позже. Баланс загружается… diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 307ced0569..e0e0ef5d5b 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -393,7 +393,7 @@ My Wallets Unlock all with %s Create PayString - Explore address + Transaction history Network is unreachable Blockchain is unreachable. Try later Balance is loading… From 73a48924a0beab02cf0062060a7df6ecbfc7c14f Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Apr 2023 23:00:54 +0900 Subject: [PATCH 26/30] Updated on 2026-08-14 --- .../states/TokensListStateHolder.kt | 47 ++++++++++---- .../impl/presentation/ui/TokensListScreen.kt | 63 ++++++++++++++++++- .../viewmodels/TokensListViewModel.kt | 25 ++++---- .../com/tangem/core/ui/res/TangemDimens.kt | 1 + 4 files changed, 109 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt index 669242641f..e083f7991b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt @@ -17,6 +17,9 @@ internal sealed interface TokensListStateHolder { /** Loading state */ val isLoading: Boolean + /** Flag that determines if warning block is visible */ + val isDifferentAddressesBlockVisible: Boolean + /** Tokens list */ val tokens: Flow> @@ -26,33 +29,50 @@ internal sealed interface TokensListStateHolder { /** * Util function that allow to make a copy * - * @param toolbarState toolbar state - * @param isLoading loading state - * @param tokens tokens list - * @param onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed + * @param toolbarState toolbar state + * @param isLoading loading state + * @param isDifferentAddressesBlockVisible flag that determines if warning block is visible + * @param tokens tokens list + * @param onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed */ fun copySealed( toolbarState: TokensListToolbarState = this.toolbarState, isLoading: Boolean = this.isLoading, + isDifferentAddressesBlockVisible: Boolean = this.isDifferentAddressesBlockVisible, tokens: Flow> = this.tokens, onTokensLoadStateChanged: (LoadState) -> Unit = this.onTokensLoadStateChanged, ): TokensListStateHolder { return when (this) { - is ManageContent -> copy(toolbarState, isLoading, tokens, onTokensLoadStateChanged) - is ReadContent -> copy(toolbarState, isLoading, tokens, onTokensLoadStateChanged) + is ManageContent -> copy( + toolbarState, + isLoading, + isDifferentAddressesBlockVisible, + tokens, + onTokensLoadStateChanged, + ) + is ReadContent -> copy( + toolbarState, + isLoading, + isDifferentAddressesBlockVisible, + tokens, + onTokensLoadStateChanged, + ) } } /** * State screen that is available only for read * - * @property toolbarState toolbar state - * @property tokens tokens list - * @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed + * @property toolbarState toolbar state + * @property isLoading loading state + * @property isDifferentAddressesBlockVisible flag that determines if warning block is visible + * @property tokens tokens list + * @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed */ data class ReadContent( override val toolbarState: TokensListToolbarState, override val isLoading: Boolean, + override val isDifferentAddressesBlockVisible: Boolean, override val tokens: Flow>, override val onTokensLoadStateChanged: (LoadState) -> Unit, ) : TokensListStateHolder @@ -60,14 +80,17 @@ internal sealed interface TokensListStateHolder { /** * State screen that is available for read and manage * - * @property toolbarState toolbar state - * @property tokens tokens list - * @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed + * @property toolbarState toolbar state + * @property isLoading loading state + * @property isDifferentAddressesBlockVisible flag that determines if warning block is visible + * @property tokens tokens list + * @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed * @property onSaveButtonClick callback to be invoked when SaveButton is being clicked */ data class ManageContent( override val toolbarState: TokensListToolbarState, override val isLoading: Boolean, + override val isDifferentAddressesBlockVisible: Boolean, override val tokens: Flow>, override val onTokensLoadStateChanged: (LoadState) -> Unit, val onSaveButtonClick: () -> Unit, diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt index 6d4494dcf5..08d9d6978c 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt @@ -13,16 +13,25 @@ import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.FabPosition import androidx.compose.material.Scaffold +import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.ExperimentalUnitApi +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.TextUnitType import androidx.paging.PagingData import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems @@ -55,7 +64,7 @@ internal fun TokensListScreen(stateHolder: TokensListStateHolder) { ) { scaffoldPadding -> val tokens = stateHolder.tokens.collectAsLazyPagingItems() - TokensListContent(tokens, scaffoldPadding) + TokensListContent(stateHolder.isDifferentAddressesBlockVisible, tokens, scaffoldPadding) stateHolder.onTokensLoadStateChanged(tokens.loadState.refresh) @@ -83,7 +92,11 @@ private fun LoadingContent() { @OptIn(ExperimentalComposeUiApi::class) @Composable -private fun TokensListContent(tokens: LazyPagingItems, scaffoldPadding: PaddingValues) { +private fun TokensListContent( + isDifferentAddressesBlockVisible: Boolean, + tokens: LazyPagingItems, + scaffoldPadding: PaddingValues, +) { val state = rememberLazyListState() if (state.isScrollInProgress) { @@ -96,12 +109,55 @@ private fun TokensListContent(tokens: LazyPagingItems, scaffoldP .padding(scaffoldPadding), state = state, ) { + if (isDifferentAddressesBlockVisible) { + item { DifferentAddressesWarning() } + } + items(items = tokens, key = TokenItemState::name) { it?.let { TokenItem(model = it) } } } } +@OptIn(ExperimentalUnitApi::class) +@Composable +private fun DifferentAddressesWarning() { + Box( + modifier = Modifier + .padding(TangemTheme.dimens.spacing16) + .background( + color = TangemColorPalette.Light1, + shape = RoundedCornerShape(TangemTheme.dimens.radius10), + ), + contentAlignment = Alignment.Center, + ) { + val text = stringResource(id = R.string.alert_manage_tokens_addresses_message) + val firstSpaceIndex = text.indexOf(" ") + Text( + text = AnnotatedString( + text = text, + spanStyles = listOf( + AnnotatedString.Range( + SpanStyle(fontWeight = FontWeight.Bold), + start = 0, + end = firstSpaceIndex, + ), + ), + ), + modifier = Modifier.padding( + horizontal = TangemTheme.dimens.spacing16, + vertical = TangemTheme.dimens.spacing8, + ), + color = TangemColorPalette.Dark1, + textAlign = TextAlign.Start, + style = TangemTheme.typography.body2.copy( + letterSpacing = TextUnit(value = 0.5f, type = TextUnitType.Sp), + lineHeight = TextUnit(value = 25f, type = TextUnitType.Sp), + ), + ) + } +} + @Composable private fun SaveChangesButton(onClick: () -> Unit) { PrimaryButton( @@ -127,6 +183,7 @@ private fun Preview_TokensListScreen_Loading() { onAddCustomTokenClick = {}, ), isLoading = true, + isDifferentAddressesBlockVisible = false, tokens = emptyFlow(), onTokensLoadStateChanged = {}, ), @@ -147,6 +204,7 @@ private fun Preview_TokensListScreen_Manage() { onAddCustomTokenClick = {}, ), isLoading = false, + isDifferentAddressesBlockVisible = true, tokens = flow { emit( PagingData.from( @@ -176,6 +234,7 @@ private fun Preview_TokensListScreen_Read() { onSearchButtonClick = {}, ), isLoading = false, + isDifferentAddressesBlockVisible = false, tokens = flow { emit( PagingData.from( diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt index d709e49df6..543e23d996 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt @@ -11,6 +11,7 @@ import androidx.paging.map import com.tangem.blockchain.common.Blockchain import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.extensions.getActiveIconRes +import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation import com.tangem.domain.common.extensions.canHandleToken import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.tap.common.extensions.fullNameWithoutTestnet @@ -26,7 +27,9 @@ import com.tangem.tap.features.tokens.impl.presentation.states.TokenItemState import com.tangem.tap.features.tokens.impl.presentation.states.TokensListStateHolder import com.tangem.tap.features.tokens.impl.presentation.states.TokensListToolbarState import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain +import com.tangem.tap.features.tokens.legacy.redux.TokensAction import com.tangem.tap.proxy.AppStateHolder +import com.tangem.tap.store import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider import com.tangem.utils.coroutines.Debouncer import com.tangem.wallet.R @@ -34,9 +37,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import kotlinx.coroutines.launch import kotlinx.coroutines.plus -import kotlinx.coroutines.withContext import javax.inject.Inject import com.tangem.blockchain.common.Token as BlockchainToken @@ -71,13 +72,12 @@ internal class TokensListViewModel @Inject constructor( private val changedTokensList: MutableList = args.mainScreenTokenList.toMutableList() private val changedBlockchainList: MutableList = args.mainScreenBlockchainList.toMutableList() - private var saveButtonPressed = false - private fun getInitialUiState(): TokensListStateHolder { return if (args.isManageAccess) { TokensListStateHolder.ManageContent( toolbarState = getInitialToolbarState(), isLoading = true, + isDifferentAddressesBlockVisible = isDifferentAddressesBlockVisible(), tokens = getInitialTokensList(), onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged, onSaveButtonClick = actionsHandler::onSaveButtonClick, @@ -86,6 +86,7 @@ internal class TokensListViewModel @Inject constructor( TokensListStateHolder.ReadContent( toolbarState = getInitialToolbarState(), isLoading = true, + isDifferentAddressesBlockVisible = isDifferentAddressesBlockVisible(), tokens = getInitialTokensList(), onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged, ) @@ -109,6 +110,10 @@ internal class TokensListViewModel @Inject constructor( } } + private fun isDifferentAddressesBlockVisible(): Boolean { + return reduxStateHolder.scanResponse?.card?.useOldStyleDerivation == true + } + private fun getInitialTokensList(searchText: String = ""): Flow> { if (searchText.isNotEmpty()) analyticsSender.sendWhenTokenSearched() @@ -237,18 +242,12 @@ internal class TokensListViewModel @Inject constructor( } fun onTokensLoadStateChanged(state: LoadState) { - uiState = uiState.copySealed(isLoading = state is LoadState.Loading || saveButtonPressed) - if (saveButtonPressed) saveButtonPressed = false + uiState = uiState.copySealed(isLoading = state is LoadState.Loading) } fun onSaveButtonClick() { - viewModelScope.launch(dispatchers.main) { - saveButtonPressed = true - analyticsSender.sendWhenSaveButtonClicked() - uiState = uiState.copySealed(isLoading = true) - withContext(dispatchers.io) { interactor.saveChanges(changedTokensList, changedBlockchainList) } - router.popBackStack() - } + analyticsSender.sendWhenSaveButtonClicked() + store.dispatch(TokensAction.SaveChanges(changedTokensList, changedBlockchainList)) } private fun onSearchValueChange(newValue: String) { diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt index 7a5dcfec58..256d81f8e8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt @@ -25,6 +25,7 @@ data class TangemDimens internal constructor( val radius4: Dp = 4.dp, val radius6: Dp = 6.dp, val radius8: Dp = 8.dp, + val radius10: Dp = 10.dp, val radius12: Dp = 12.dp, val radius16: Dp = 16.dp, val radius28: Dp = 28.dp, From 6760d7c16e330ee9aed88dcacc62e10ae2a6e90e Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Apr 2023 17:48:59 +0300 Subject: [PATCH 27/30] Updated on 2026-08-14 --- .../tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index dfe3f32704..fbe46121d7 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -8,6 +8,7 @@ import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.analytics.events.Portfolio +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.getQuantityString import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show @@ -59,6 +60,7 @@ class MultiWalletView : WalletView() { binding = it, totalBalance = walletState.totalBalance, walletsCount = walletState.walletsDataFromStores.size, + appFiatCurrency = store.state.globalState.appCurrency, ) } } @@ -153,6 +155,7 @@ class MultiWalletView : WalletView() { binding: FragmentWalletBinding, totalBalance: TotalFiatBalance?, walletsCount: Int, + appFiatCurrency: FiatCurrency, ) = with(binding.lCardTotalBalance) { isVisible = walletsCount > 0 @@ -160,6 +163,7 @@ class MultiWalletView : WalletView() { store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) } status = totalBalance + fiatCurrency = appFiatCurrency } private fun handleErrorStates(state: WalletState, binding: FragmentWalletBinding, fragment: WalletFragment) { From 4f927cad748bcfc257e6d697714150563c6e4824 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Apr 2023 18:46:36 +0300 Subject: [PATCH 28/30] Updated on 2026-08-14 --- .../tangem/tap/common/extensions/Specific.kt | 39 +++++++++++++++++-- .../wallet/ui/utils/WalletDataOperations.kt | 4 +- .../tap/features/walletSelector/ui/Mapper.kt | 2 +- .../layout/item_currency_wallet_content.xml | 6 ++- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index 632a28fe81..c5a6d6cd4f 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -5,10 +5,12 @@ import android.text.SpannedString import android.text.style.RelativeSizeSpan import androidx.core.text.buildSpannedString import com.tangem.common.extensions.isZero +import timber.log.Timber import java.math.BigDecimal import java.math.RoundingMode import java.text.DecimalFormat import java.text.DecimalFormatSymbols +import java.text.NumberFormat import java.util.* // TODO: move extensions to utils @@ -46,7 +48,18 @@ fun BigDecimal.toFormattedCurrencyString( return "$formattedAmount $currency" } -fun BigDecimal.toFiatRateString(fiatCurrencyName: String): String { +fun BigDecimal.toFiatRateString(fiatCurrencyName: String, fiatCode: String): String { + try { + val formatter = NumberFormat.getCurrencyInstance() + Currency.getInstance(fiatCode)?.let { currency -> + formatter.currency = currency + formatter.maximumFractionDigits = 2 + formatter.roundingMode = RoundingMode.HALF_UP + return formatter.format(this) + } + } catch (e: IllegalArgumentException) { + Timber.e(e, "can't parse currency") + } val value = this .setScale(2, RoundingMode.HALF_UP) .formatWithSpaces() @@ -56,10 +69,15 @@ fun BigDecimal.toFiatRateString(fiatCurrencyName: String): String { fun BigDecimal.toFiatString( rateValue: BigDecimal, fiatCurrencyName: String, + fiatCode: String, formatWithSpaces: Boolean = false, ): String { val fiatValue = rateValue.multiply(this) - return fiatValue.toFormattedFiatValue(fiatCurrencyName, formatWithSpaces) + return fiatValue.toFormattedFiatValue( + fiatCurrencyName = fiatCurrencyName, + fiatCode = fiatCode, + formatWithSpaces = formatWithSpaces, + ) } fun BigDecimal.toFiatValue(rateValue: BigDecimal): BigDecimal { @@ -67,7 +85,22 @@ fun BigDecimal.toFiatValue(rateValue: BigDecimal): BigDecimal { return fiatValue.setScale(2, RoundingMode.HALF_UP) } -fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: String, formatWithSpaces: Boolean = false): String { +fun BigDecimal.toFormattedFiatValue( + fiatCurrencyName: String, + fiatCode: String, + formatWithSpaces: Boolean = false, +): String { + try { + val formatter = NumberFormat.getCurrencyInstance() + Currency.getInstance(fiatCode)?.let { currency -> + formatter.currency = currency + formatter.maximumFractionDigits = 2 + formatter.roundingMode = RoundingMode.HALF_UP + return formatter.format(this) + } + } catch (e: IllegalArgumentException) { + Timber.e(e, "can't parse currency") + } val fiatValue = this.setScale(2, RoundingMode.HALF_UP) .let { if (formatWithSpaces) it.formatWithSpaces() else it } return " $fiatValue $fiatCurrencyName" diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt index 6b08921a5d..42be04542e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt @@ -36,12 +36,12 @@ internal fun WalletDataModel.getFormattedFiatAmount( ): String { return this.fiatRate?.let { status.amount.toFiatValue(it) } ?.takeIf { !status.isErrorStatus } - ?.toFormattedFiatValue(fiatCurrency.symbol) + ?.toFormattedFiatValue(fiatCurrencyName = fiatCurrency.symbol, fiatCode = fiatCurrency.code) ?: unknownAmountSign } internal fun WalletDataModel.getFormattedFiatRate(fiatCurrency: FiatCurrency, noRateValue: String): String { - return fiatRate?.toFiatRateString(fiatCurrency.symbol) + return fiatRate?.toFiatRateString(fiatCurrency.symbol, fiatCurrency.code) ?: noRateValue } diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt index 0e4319a4dc..d01e48d352 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt @@ -15,7 +15,7 @@ internal fun List.toUiModels(appCurrency: FiatCurrency): Sequen is TotalFiatBalance.Failed -> UserWalletItem.Balance.Failed is TotalFiatBalance.Loading -> UserWalletItem.Balance.Loading is TotalFiatBalance.Loaded -> UserWalletItem.Balance.Loaded( - amount = fiatBalance.amount.toFormattedFiatValue(appCurrency.symbol), + amount = fiatBalance.amount.toFormattedFiatValue(appCurrency.symbol, appCurrency.code), showWarning = fiatBalance.isWarning, ) } diff --git a/app/src/main/res/layout/item_currency_wallet_content.xml b/app/src/main/res/layout/item_currency_wallet_content.xml index b27a1d1edb..5eb26a5bbb 100644 --- a/app/src/main/res/layout/item_currency_wallet_content.xml +++ b/app/src/main/res/layout/item_currency_wallet_content.xml @@ -19,6 +19,7 @@ android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:ellipsize="end" + android:gravity="start" android:maxLines="1" android:textColor="@color/text_primary_1" android:textSize="16sp" @@ -35,8 +36,8 @@ android:id="@+id/tv_amount_fiat" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:gravity="end" android:maxLines="1" - android:textAlignment="viewEnd" android:textColor="@color/text_primary_1" android:textSize="16sp" android:textStyle="bold" @@ -50,8 +51,8 @@ android:id="@+id/tv_amount" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:gravity="end" android:maxLines="1" - android:textAlignment="viewEnd" android:textColor="@color/text_tertiary" android:textSize="12sp" app:layout_constraintBottom_toBottomOf="parent" @@ -66,6 +67,7 @@ android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:ellipsize="end" + android:gravity="start" android:maxLines="1" android:textColor="@color/text_tertiary" android:textSize="12sp" From 318492886628555f43997c25d56e859755571636 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Apr 2023 18:50:30 +0300 Subject: [PATCH 29/30] Updated on 2026-08-14 --- .../java/com/tangem/tap/features/wallet/redux/WalletState.kt | 2 -- .../tap/features/wallet/redux/middlewares/WalletMiddleware.kt | 4 ++-- .../tap/features/wallet/redux/reducers/WalletReducer.kt | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index a1b4340f07..dafb4c0324 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -8,7 +8,6 @@ import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.common.toggleWidget.WidgetState import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.model.TotalFiatBalance -import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.tokens.models.BlockchainNetwork @@ -19,7 +18,6 @@ import org.rekotlin.StateType import kotlin.properties.ReadOnlyProperty data class WalletState( - val userWallet: UserWallet? = null, val state: ProgressState = ProgressState.Done, val error: ErrorType? = null, val cardImage: Artwork? = null, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 7d34cdc332..c12bebc8c7 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -105,7 +105,7 @@ class WalletMiddleware { scope.launch { when (val result = tangemSdkManager.createWallet(globalState.scanResponse?.card?.cardId)) { is CompletionResult.Success -> { - val selectedUserWallet = walletState.userWallet.guard { + val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { Timber.e("Unable to create wallet, no user wallet selected") return@launch } @@ -131,7 +131,7 @@ class WalletMiddleware { is WalletAction.LoadData, is WalletAction.LoadData.Refresh, -> { - val selectedWallet = walletState.userWallet.guard { + val selectedWallet = userWalletsListManager.selectedUserWalletSync.guard { Timber.e("Unable to load/refresh wallets data, no user wallet selected") return } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index a7ebec614d..632ac3e7df 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -73,7 +73,6 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS is WalletAction.UserWalletChanged -> with(action.userWallet) { val card = scanResponse.card newState = WalletState( - userWallet = this, isMultiwalletAllowed = isMultiCurrency, cardImage = Artwork( artworkId = artworkUrl, From 3dacadd4757f64d9f2deb5dc06b8276c6f68b63d Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 17 Apr 2023 19:52:28 +0300 Subject: [PATCH 30/30] Updated on 2026-08-14 --- .../src/main/assets/configs/feature_toggles_config.json | 2 +- gradle/dependencies.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json index b7661838a4..26ee85d521 100644 --- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json @@ -5,6 +5,6 @@ }, { "name": "REDESIGNED_TOKEN_LIST_SCREEN_ENABLED", - "version": "4.5.0" + "version": "4.4.0" } ] \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index ce5ce3a82d..9e76b50534 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -71,7 +71,7 @@ kotlinSerialization = "1.4.1" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-198" +tangemBlockchainSdk = "develop-203" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-218" # tangemCardSdk = "0.0.1" # Keep it! - used for local builds