From 1061426e87ec96b9bda4514c51f820e12f960e85 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 5 Sep 2023 12:08:56 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../features/details/redux/DetailsReducer.kt | 9 +- .../features/details/redux/DetailsState.kt | 2 +- .../ui/appsettings/AppSettingsItemsFactory.kt | 11 +++ .../ui/appsettings/AppSettingsScreen.kt | 6 ++ .../ui/appsettings/AppSettingsScreenState.kt | 8 ++ .../ui/appsettings/AppSettingsViewModel.kt | 10 +++ .../ui/appsettings/components/ButtonItem.kt | 80 ++++++++++++++++++ .../details/ui/details/DetailsScreen.kt | 82 +++++++++++-------- .../details/ui/details/DetailsScreenState.kt | 10 +-- .../details/ui/details/DetailsViewModel.kt | 5 -- 10 files changed, 176 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/ButtonItem.kt 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 71e4d6b2dd..77c3972fac 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 @@ -39,8 +39,11 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { is DetailsAction.AppSettings -> { handlePrivacyAction(action, detailsState) } - is DetailsAction.ChangeAppCurrency -> - detailsState.copy(appCurrency = action.fiatCurrency) + is DetailsAction.ChangeAppCurrency -> detailsState.copy( + appSettingsState = detailsState.appSettingsState.copy( + selectedFiatCurrency = action.fiatCurrency, + ), + ) is DetailsAction.AccessCodeRecovery -> handleAccessCodeRecoveryAction(action, detailsState) else -> detailsState } @@ -50,11 +53,11 @@ private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsSta return DetailsState( scanResponse = action.scanResponse, createBackupAllowed = action.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup, - appCurrency = store.state.globalState.appCurrency, appSettingsState = AppSettingsState( isBiometricsAvailable = tangemSdkManager.canUseBiometry, saveWallets = preferencesStorage.shouldSaveUserWallets, saveAccessCodes = preferencesStorage.shouldSaveAccessCodes, + selectedFiatCurrency = store.state.globalState.appCurrency, ), ) } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index 6ad80685b2..3dcf9ddd33 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -12,7 +12,6 @@ data class DetailsState( val cardSettingsState: CardSettingsState? = null, val privacyPolicyUrl: String? = null, val createBackupAllowed: Boolean = false, - val appCurrency: FiatCurrency = FiatCurrency.Default, val appSettingsState: AppSettingsState = AppSettingsState(), ) : StateType @@ -55,6 +54,7 @@ data class AppSettingsState( val isBiometricsAvailable: Boolean = false, val needEnrollBiometrics: Boolean = false, val isInProgress: Boolean = false, + val selectedFiatCurrency: FiatCurrency = FiatCurrency.Default, ) enum class SecurityOption { LongTap, PassCode, AccessCode } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsItemsFactory.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsItemsFactory.kt index 464411faa7..a6a23da4b5 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsItemsFactory.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsItemsFactory.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.details.ui.appsettings import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState.Item import com.tangem.wallet.R @@ -45,4 +46,14 @@ internal class AppSettingsItemsFactory { onCheckedChange = onCheckedChange, ) } + + fun createSelectAppCurrencyButton(currentAppCurrencyName: String, onClick: () -> Unit): Item.Button { + return Item.Button( + id = "select_app_currency_button", + title = resourceReference(R.string.details_row_title_currency), + description = stringReference(currentAppCurrencyName), + isEnabled = true, + onClick = onClick, + ) + } } \ No newline at end of file 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 05405f7d3d..aff04f20a9 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 @@ -12,6 +12,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState.Item +import com.tangem.tap.features.details.ui.appsettings.components.ButtonItem import com.tangem.tap.features.details.ui.appsettings.components.CardItem import com.tangem.tap.features.details.ui.appsettings.components.SettingsAlertDialog import com.tangem.tap.features.details.ui.appsettings.components.SwitchItem @@ -51,6 +52,10 @@ private fun AppSettings(state: AppSettingsScreenState.Content) { modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), item = item, ) + is Item.Button -> ButtonItem( + modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8), + item = item, + ) is Item.Switch -> SwitchItem( modifier = Modifier.padding( vertical = TangemTheme.dimens.spacing16, @@ -90,6 +95,7 @@ private class AppSettingsScreenStateProvider : CollectionPreviewParameterProvide val dialogsFactory = AppSettingsAlertsFactory() val items = persistentListOf( itemsFactory.createEnrollBiometricsCard {}, + itemsFactory.createSelectAppCurrencyButton(currentAppCurrencyName = "US Dollar") {}, itemsFactory.createSaveWalletsSwitch(isChecked = true, isEnabled = true, { _ -> }), itemsFactory.createSaveAccessCodeSwitch(isChecked = false, isEnabled = true) { _ -> }, ) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsScreenState.kt index bee5e3241b..4802004976 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsScreenState.kt @@ -36,6 +36,14 @@ internal sealed class AppSettingsScreenState { val isChecked: Boolean, val onCheckedChange: (Boolean) -> Unit, ) : Item() + + data class Button( + override val id: String, + val title: TextReference, + val description: TextReference, + val isEnabled: Boolean, + val onClick: () -> Unit, + ) : Item() } data class Alert( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt index 98b3cead3b..5aedd6f7b7 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/AppSettingsViewModel.kt @@ -9,6 +9,7 @@ import com.tangem.tap.features.details.redux.AppSetting import com.tangem.tap.features.details.redux.AppSettingsState import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsState +import com.tangem.tap.features.wallet.redux.WalletAction import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import org.rekotlin.Store @@ -42,6 +43,11 @@ internal class AppSettingsViewModel(private val store: Store) { itemsFactory.createEnrollBiometricsCard(onClick = ::enrollBiometrics).let(::add) } + itemsFactory.createSelectAppCurrencyButton( + currentAppCurrencyName = state.selectedFiatCurrency.name, + onClick = ::showAppCurrencySelector, + ).let(::add) + if (state.isBiometricsAvailable) { val canUseBiometrics = !state.needEnrollBiometrics && !state.isInProgress @@ -66,6 +72,10 @@ internal class AppSettingsViewModel(private val store: Store) { store.dispatchOnMain(DetailsAction.AppSettings.EnrollBiometrics) } + private fun showAppCurrencySelector() { + store.dispatchOnMain(WalletAction.AppCurrencyAction.ChooseAppCurrency) + } + private fun onSaveWalletsToggled(isChecked: Boolean) { if (isChecked) { onSettingsToggled(AppSetting.SaveWallets, enable = true) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/ButtonItem.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/ButtonItem.kt new file mode 100644 index 0000000000..4010f633ed --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/components/ButtonItem.kt @@ -0,0 +1,80 @@ +package com.tangem.tap.features.details.ui.appsettings.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.tap.features.details.ui.appsettings.AppSettingsItemsFactory +import com.tangem.tap.features.details.ui.appsettings.AppSettingsScreenState.Item + +@OptIn(ExperimentalMaterialApi::class) +@Composable +internal fun ButtonItem(item: Item.Button, modifier: Modifier = Modifier) { + Surface( + modifier = modifier.fillMaxWidth(), + color = TangemTheme.colors.background.secondary, + onClick = item.onClick, + ) { + Column( + modifier = Modifier.padding( + horizontal = TangemTheme.dimens.spacing20, + vertical = TangemTheme.dimens.spacing8, + ), + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4), + horizontalAlignment = Alignment.Start, + ) { + Text( + modifier = Modifier.fillMaxWidth(), + text = item.title.resolveReference(), + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + ) + Text( + modifier = Modifier.fillMaxWidth(), + text = item.description.resolveReference(), + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.secondary, + ) + } + } +} + +// region Preview +@Preview(showBackground = true, widthDp = 360) +@Composable +private fun ButtonItemPreview_Light(@PreviewParameter(ButtonItemProvider::class) item: Item.Button) { + TangemTheme { + ButtonItem(item = item) + } +} + +@Preview(showBackground = true, widthDp = 360) +@Composable +private fun ButtonItemPreview_Dark(@PreviewParameter(ButtonItemProvider::class) item: Item.Button) { + TangemTheme(isDark = true) { + ButtonItem(item = item) + } +} + +private class ButtonItemProvider : CollectionPreviewParameterProvider( + collection = buildList { + val itemsFactory = AppSettingsItemsFactory() + + itemsFactory.createSelectAppCurrencyButton( + currentAppCurrencyName = "US Dollar", + onClick = { /* no-op */ }, + ).let(::add) + }, +) +// endregion Preview \ No newline at end of file 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 b853168363..2326b3db65 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 @@ -20,6 +20,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.SpacerH +import com.tangem.core.ui.components.SpacerHMax import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.features.details.ui.common.ScreenTitle @@ -44,39 +46,53 @@ private fun Content(state: DetailsScreenState, modifier: Modifier = Modifier) { .fillMaxSize() .verticalScroll(rememberScrollState()), ) { - ScreenTitle(titleRes = R.string.details_title, Modifier.padding(bottom = 52.dp)) - state.elements.map { element -> - if (element == SettingsElement.WalletConnect) { - WalletConnectDetailsItem(onItemsClick = state.onItemsClick) - } else { - DetailsItem( - item = element, - appCurrency = state.appCurrency, - onItemsClick = { state.onItemsClick(element) }, - ) - } - } - Spacer(modifier = Modifier.weight(1f)) - TangemSocialAccounts(state.tangemLinks, state.onSocialNetworkClick) - Spacer(modifier = Modifier.size(12.dp)) - Text( - text = "${stringResource(id = state.appNameRes)} ${state.tangemVersion}", - style = TangemTheme.typography.caption, - color = TangemTheme.colors.text.tertiary, - modifier = Modifier.padding(start = 16.dp, end = 16.dp, bottom = 40.dp), + ScreenTitle(titleRes = R.string.details_title) + SpacerH(height = TangemTheme.dimens.spacing36) + SettingsItems( + items = state.elements, + onItemsClick = state.onItemsClick, ) + SpacerHMax() + TangemSocialAccounts( + links = state.tangemLinks, + onSocialNetworkClick = state.onSocialNetworkClick, + ) + SpacerH(height = TangemTheme.dimens.spacing16) + TangemAppVersion( + appNameRes = state.appNameRes, + version = state.tangemVersion, + ) + SpacerH(height = TangemTheme.dimens.spacing24) } ShowSnackbarIfNeeded(state.showErrorSnackbar.value) } } @Composable -private fun WalletConnectDetailsItem(onItemsClick: (SettingsElement) -> Unit) { +private fun SettingsItems(items: List, onItemsClick: (SettingsElement) -> Unit) { + items.forEach { item -> + val onItemClick = remember(item) { + { onItemsClick(item) } + } + + if (item == SettingsElement.WalletConnect) { + WalletConnectDetailsItem(onItemClick) + } else { + DetailsItem( + item = item, + onItemClick = onItemClick, + ) + } + } +} + +@Composable +private fun WalletConnectDetailsItem(onItemClick: () -> Unit) { Row( modifier = Modifier .defaultMinSize(minHeight = 84.dp) .fillMaxWidth() - .clickable { onItemsClick(SettingsElement.WalletConnect) }, + .clickable(onClick = onItemClick), horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, ) { @@ -108,12 +124,12 @@ private fun WalletConnectDetailsItem(onItemsClick: (SettingsElement) -> Unit) { } @Composable -private fun DetailsItem(item: SettingsElement, appCurrency: String, onItemsClick: () -> Unit) { +private fun DetailsItem(item: SettingsElement, onItemClick: () -> Unit) { Row( modifier = Modifier .height(56.dp) .fillMaxWidth() - .clickable(onClick = onItemsClick), + .clickable(onClick = onItemClick), horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, ) { @@ -130,13 +146,6 @@ private fun DetailsItem(item: SettingsElement, appCurrency: String, onItemsClick style = TangemTheme.typography.subtitle1, color = TangemTheme.colors.text.primary1, ) - if (item == SettingsElement.AppCurrency) { - Text( - text = appCurrency, - style = TangemTheme.typography.body2, - color = TangemTheme.colors.text.secondary, - ) - } } } } @@ -190,6 +199,16 @@ private fun BoxScope.ShowSnackbarIfNeeded(snackbarErrorState: EventError) { } } +@Composable +private fun TangemAppVersion(appNameRes: Int, version: String, modifier: Modifier = Modifier) { + Text( + modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing16), + text = "${stringResource(id = appNameRes)} $version", + style = TangemTheme.typography.caption, + color = TangemTheme.colors.text.tertiary, + ) +} + // region Preview @Composable private fun DetailsScreenContentSample() { @@ -198,7 +217,6 @@ private fun DetailsScreenContentSample() { elements = SettingsElement.values().toList(), tangemLinks = TangemSocialAccounts.accountsEn, tangemVersion = "Tangem 2.14.12 (343)", - appCurrency = "Dollar", onItemsClick = {}, onSocialNetworkClick = {}, ), 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 a5e030a647..f6ea3f1f19 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 @@ -10,7 +10,6 @@ internal data class DetailsScreenState( val elements: List, val tangemLinks: List, val tangemVersion: String, - val appCurrency: String, val onItemsClick: (SettingsElement) -> Unit, val onSocialNetworkClick: (SocialNetworkLink) -> Unit, val showErrorSnackbar: MutableState = mutableStateOf(EventError.Empty), @@ -24,14 +23,13 @@ internal enum class SettingsElement( val titleRes: Int, ) { WalletConnect(R.drawable.ic_walletconnect, R.string.wallet_connect_title), - Chat(R.drawable.ic_chat, R.string.details_chat), - SendFeedback(R.drawable.ic_comment, R.string.details_row_title_send_feedback), + LinkMoreCards(R.drawable.ic_more_cards, R.string.details_row_title_create_backup), ReferralProgram(R.drawable.ic_add_friends, R.string.details_referral_title), CardSettings(R.drawable.ic_card_settings, R.string.card_settings_title), - AppCurrency(R.drawable.ic_currency, R.string.details_row_title_currency), AppSettings(R.drawable.ic_settings, R.string.app_settings_title), - 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 + Chat(R.drawable.ic_chat, R.string.details_chat), + SendFeedback(R.drawable.ic_comment, R.string.details_row_title_send_feedback), + 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), } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index c3491e7c73..7877dff881 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -42,7 +42,6 @@ internal class DetailsViewModel(private val store: Store) { elements = createSettingsItems(state), tangemLinks = getSocialLinks(), tangemVersion = getTangemAppVersion(), - appCurrency = state.appCurrency.name, onItemsClick = { handleClickingSettingsItem(it) }, onSocialNetworkClick = { handleSocialNetworkClick(it) }, ) @@ -60,7 +59,6 @@ internal class DetailsViewModel(private val store: Store) { SettingsElement.LinkMoreCards -> if (state.createBackupAllowed) it else null SettingsElement.PrivacyPolicy -> if (state.privacyPolicyUrl != null) it else null SettingsElement.AppSettings -> if (state.appSettingsState.isBiometricsAvailable) it else null - SettingsElement.AppCurrency -> if (cardTypesResolver.isMultiwalletAllowed()) null else it SettingsElement.ReferralProgram -> if (cardTypesResolver.isTangemWallet()) it else null SettingsElement.TesterMenu -> if (BuildConfig.TESTER_MENU_ENABLED) it else null else -> it @@ -91,9 +89,6 @@ internal class DetailsViewModel(private val store: Store) { Analytics.send(Settings.ButtonCardSettings()) store.dispatch(NavigationAction.NavigateTo(AppScreen.CardSettings)) } - SettingsElement.AppCurrency -> { - store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) - } SettingsElement.AppSettings -> { Analytics.send(Settings.ButtonAppSettings()) store.dispatch(NavigationAction.NavigateTo(AppScreen.AppSettings))