Updated on 2026-08-14

This commit is contained in:
Tangem 2022-08-03 16:26:40 +04:00
parent 252bd57891
commit ced437b892
16 changed files with 95 additions and 165 deletions

View file

@ -5,7 +5,6 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.domain.common.isTangemTwins
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.AnalyticsParam
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.AppState
@ -38,7 +37,7 @@ class DetailsMiddleware {
is DetailsAction.AppSettings -> managePrivacyMiddleware.handle(action)
is DetailsAction.ShowDisclaimer -> {
val uri = store.state.detailsState.cardTermsOfUseUrl
if (uri !=null) {
if (uri != null) {
store.dispatch(NavigationAction.OpenDocument(uri))
} else {
store.dispatch(DisclaimerAction.ShowAcceptedDisclaimer)
@ -108,9 +107,9 @@ class DetailsMiddleware {
currenciesRepository.removeCurrencies(card.cardId)
val returnScreen =
if (card.cardId == store.state.globalState.scanResponse?.card?.cardId) {
null
} else {
AppScreen.Home
} else {
null
}
store.dispatch(NavigationAction.PopBackTo(returnScreen))
}

View file

@ -66,7 +66,7 @@ private fun hanldePrepareCardSettingsScreen(
cardInfo = card.toCardInfo(),
manageSecurityState = prepareSecurityOptions(card),
card = card,
resetCardAllowed = isResetToFactoryAllowedByCard(card)
resetCardAllowed = isResetToFactoryAllowedByCard(card),
)
return state.copy(cardSettingsState = cardSettingsState)
}
@ -101,7 +101,7 @@ private fun prepareSecurityOptions(card: Card): ManageSecurityState {
private fun isResetToFactoryAllowedByCard(card: Card): Boolean {
val notAllowedByAnyWallet = card.wallets.any { it.settings.isPermanent }
val notAllowedByCard = notAllowedByAnyWallet ||
val notAllowedByCard = notAllowedByAnyWallet ||
(card.isWalletDataSupported && (!card.isTangemNote() && !card.settings.isBackupAllowed))
return !notAllowedByCard
}

View file

@ -46,7 +46,7 @@ data class CardSettingsState(
val card: Card,
val manageSecurityState: ManageSecurityState?,
val resetCardAllowed: Boolean,
val resetConfirmed: Boolean = false
val resetConfirmed: Boolean = false,
)
data class ManageSecurityState(

View file

@ -31,7 +31,6 @@ fun CardSettingsScreen(
onBackPressed: () -> Unit,
modifier: Modifier = Modifier,
) {
SettingsScreensScaffold(
content =
if (state.cardDetails == null) {
@ -49,7 +48,6 @@ fun CardSettingsReadCard(
onScanCardClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize(),
@ -105,8 +103,7 @@ fun CardSettingsReadCard(
title = stringResource(id = R.string.scan_card_settings_button),
onClick = onScanCardClick,
modifier = modifier,
)
)
}
}
}
@ -116,12 +113,10 @@ fun CardSettings(
state: CardSettingsScreenState,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxWidth()
.fillMaxWidth(),
) {
state.cardDetails?.map {
val paddingBottom = when (it) {
is CardInfo.CardId, is CardInfo.Issuer -> 12.dp
@ -141,15 +136,14 @@ fun CardSettings(
Column(
modifier = modifier
.fillMaxWidth()
.clickable(
enabled = it.clickable,
onClick = { state.onElementClick(it) },
)
.padding(start = 20.dp, end = 20.dp, bottom = paddingBottom, top = paddingTop),
) {
val titleColor = if (it.clickable) R.color.text_primary_1 else R.color.text_tertiary
val subtitleColor = if (it.clickable) R.color.text_secondary else R.color.text_tertiary
val titleColor = if (it.clickable) R.color.text_primary_1 else R.color.text_tertiary
val subtitleColor = if (it.clickable) R.color.text_secondary else R.color.text_tertiary
Text(
text = stringResource(id = it.titleRes),
color = colorResource(id = titleColor),

View file

@ -5,11 +5,11 @@ import com.tangem.wallet.R
data class CardSettingsScreenState(
val cardDetails: List<CardInfo>? = null,
val onScanCardClick: () -> Unit,
val onElementClick: (CardInfo) -> Unit
val onElementClick: (CardInfo) -> Unit,
)
sealed class CardInfo(
val titleRes: Int, val subtitle: String, val clickable: Boolean = false
val titleRes: Int, val subtitle: String, val clickable: Boolean = false,
) {
class CardId(subtitle: String) : CardInfo(R.string.details_row_title_cid, subtitle)

View file

@ -18,7 +18,8 @@ class CardSettingsViewModel(private val store: Store<AppState>) {
return if (state?.manageSecurityState == null) {
CardSettingsScreenState(
null, onElementClick = {},
cardDetails = null,
onElementClick = {},
onScanCardClick = {
store.dispatch(DetailsAction.ScanCard)
},
@ -69,7 +70,7 @@ class CardSettingsViewModel(private val store: Store<AppState>) {
}
CardSettingsScreenState(
cardDetails,
cardDetails = cardDetails,
onScanCardClick = { },
onElementClick = {
handleClickingItem(it)

View file

@ -81,6 +81,7 @@ fun EmptyTopBarWithNavigation(
},
backgroundColor = colorResource(id = R.color.background_primary),
elevation = 0.dp,
modifier = modifier,
)
}

View file

@ -23,7 +23,6 @@ class DetailsFragment : Fragment(), StoreSubscriber<DetailsState> {
private var detailsScreenState: MutableState<DetailsScreenState> =
mutableStateOf(detailsViewModel.updateState(store.state.detailsState))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -36,7 +35,7 @@ class DetailsFragment : Fragment(), StoreSubscriber<DetailsState> {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
): View {
return ComposeView(requireContext()).apply {
setContent {
isTransitionGroup = true
@ -64,73 +63,8 @@ class DetailsFragment : Fragment(), StoreSubscriber<DetailsState> {
store.unsubscribe(this)
}
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// super.onViewCreated(view, savedInstanceState)
//
// binding.toolbar.setNavigationOnClickListener {
// store.dispatch(NavigationAction.PopBackTo())
// }
// }
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
detailsScreenState.value = detailsViewModel.updateState(state)
}
// private fun setState(state: DetailsState) = with(binding) {
//
// if (state.cardInfo != null) {
// val cardId = if (state.isTangemTwins) {
// state.scanResponse?.card?.getTwinCardIdForUser()
// } else {
// state.cardInfo.cardId
// }
// tvCardId.text = cardId
// tvIssuer.text = state.cardInfo.issuer
// tvSignedHashes.text = getString(
// R.string.details_row_subtitle_signed_hashes_format,
// state.cardInfo.signedHashes.toString()
// )
// }
//
// tvSignedHashes.show(!state.isTangemTwins)
// tvSignedHashesTitle.show(!state.isTangemTwins)
//
// tvDisclaimer.setOnClickListener { store.dispatch(DetailsAction.ShowDisclaimer) }
//
//
// if (state.isTangemTwins) {
// tvResetToFactory.show()
// tvResetToFactory.text = getText(R.string.details_row_title_twins_recreate)
// tvResetToFactory.setOnClickListener {
// store.dispatch(DetailsAction.ReCreateTwinsWallet(state.twinCardsState.cardNumber!!))
// }
// } else {
// tvResetToFactory.show()
// tvResetToFactory.text = getText(R.string.details_row_title_reset_factory_settings)
// tvResetToFactory.setOnClickListener {
// store.dispatch(DetailsAction.ResetToFactory.Check)
// store.dispatch(DetailsAction.ResetToFactory.Proceed)
// }
// }
//
//
// tvAppCurrency.show(state.scanResponse?.card?.isMultiwalletAllowed != true)
// tvAppCurrencyTitle.show(state.scanResponse?.card?.isMultiwalletAllowed != true)
// tvAppCurrency.text = state.appCurrency.code
//
// tvAppCurrency.setOnClickListener {
// store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
// }
//
// tvSecurityAndPrivacy.setOnClickListener {
// store.dispatch(DetailsAction.ManageSecurity.CheckCurrentSecurityOption(state.scanResponse!!.card))
// tvSecurityAndPrivacy.setOnClickListener {
// store.dispatch(NavigationAction.NavigateTo(AppScreen.SecurityAndPrivacy))
// }
//
// }
//
// }
}

View file

@ -9,6 +9,8 @@ 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.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@ -53,12 +55,12 @@ fun Content(
state.elements.map {
if (it == SettingsElement.WalletConnect) {
WalletConnectDetailsItem(
onItemsClick = state.onItemsClick, modifier = modifier
onItemsClick = state.onItemsClick, modifier = modifier,
)
} else {
DetailsItem(
item = it, onItemsClick = state.onItemsClick,
modifier = modifier
modifier = modifier,
)
}
}
@ -82,6 +84,7 @@ fun WalletConnectDetailsItem(
Row(
modifier = modifier
.height(84.dp)
.fillMaxWidth()
.clickable { onItemsClick(SettingsElement.WalletConnect) },
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
@ -150,22 +153,19 @@ fun TangemSocialAccounts(
onSocialNetworkClick: (String) -> Unit,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier.padding(start = 8.dp, end = 8.dp)
LazyRow(
modifier = modifier.padding(start = 8.dp, end = 8.dp),
) {
links.map {
items(links) {
Icon(
painter = painterResource(id = it.iconRes),
contentDescription = "",
modifier = modifier
.padding(8.dp)
.clickable { onSocialNetworkClick(it.url) }
,
.clickable { onSocialNetworkClick(it.url) },
tint = colorResource(id = R.color.icon_informative),
)
}
}
}
@ -174,11 +174,11 @@ fun TangemSocialAccounts(
fun Preview() {
DetailsScreen(
state = DetailsScreenState(
SettingsElement.values().toList(),
TangemSocialAccounts.accountsEn,
"Tangem 2.14.12 (343)",
{}, {}
),
{},
elements = SettingsElement.values().toList(),
tangemLinks = TangemSocialAccounts.accountsEn,
tangemVersion = "Tangem 2.14.12 (343)",
onItemsClick = {}, onSocialNetworkClick = {},
),
onBackPressed = {},
)
}

View file

@ -12,7 +12,6 @@ data class DetailsScreenState(
val appNameRes: Int = R.string.app_name
}
enum class SettingsElement(
val iconRes: Int,
val titleRes: Int,

View file

@ -21,7 +21,7 @@ class ResetCardFragment : Fragment(), StoreSubscriber<DetailsState> {
private val viewModel = ResetCardViewModel(store)
private var screenState: MutableState<ResetCardScreenState> =
mutableStateOf(viewModel.updateState(store.state.detailsState.cardSettingsState, context))
mutableStateOf(viewModel.updateState(store.state.detailsState.cardSettingsState))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -35,7 +35,7 @@ class ResetCardFragment : Fragment(), StoreSubscriber<DetailsState> {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
): View {
return ComposeView(requireContext()).apply {
setContent {
isTransitionGroup = true
@ -65,6 +65,6 @@ class ResetCardFragment : Fragment(), StoreSubscriber<DetailsState> {
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
screenState.value = viewModel.updateState(state.cardSettingsState, context)
screenState.value = viewModel.updateState(state.cardSettingsState)
}
}

View file

@ -46,7 +46,6 @@ fun ResetCardView(
state: ResetCardScreenState,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize(),
@ -111,7 +110,7 @@ fun ResetCardView(
DetailsMainButton(
title = stringResource(id = R.string.reset_factory_button),
onClick = state.onResetButtonClick,
enabled = state.resetButtonEnabled
enabled = state.resetButtonEnabled,
)
}

View file

@ -1,6 +1,5 @@
package com.tangem.tap.features.details.ui.resetcard
import android.content.Context
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.details.redux.CardSettingsState
import com.tangem.tap.features.details.redux.DetailsAction
@ -8,11 +7,11 @@ import org.rekotlin.Store
class ResetCardViewModel(private val store: Store<AppState>) {
fun updateState(state: CardSettingsState?, context: Context?): ResetCardScreenState {
fun updateState(state: CardSettingsState?): ResetCardScreenState {
return ResetCardScreenState(
accepted = state?.resetConfirmed ?: false,
onAcceptWarningToggleClick = { store.dispatch(DetailsAction.ResetToFactory.Confirm(it)) },
onResetButtonClick = { store.dispatch(DetailsAction.ResetToFactory.Proceed) }
onResetButtonClick = { store.dispatch(DetailsAction.ResetToFactory.Proceed) },
)
}
}

View file

@ -35,7 +35,7 @@ class SecurityModeFragment : Fragment(), StoreSubscriber<DetailsState> {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
): View {
return ComposeView(requireContext()).apply {
setContent {
isTransitionGroup = true

View file

@ -29,11 +29,10 @@ fun SecurityModeScreen(
onBackPressed: () -> Unit,
modifier: Modifier = Modifier,
) {
SettingsScreensScaffold(
content = { SecurityModeOptions(state = state, modifier = modifier) },
titleRes = R.string.card_settings_security_mode,
onBackClick = onBackPressed
onBackClick = onBackPressed,
)
}
@ -49,53 +48,11 @@ fun SecurityModeOptions(
.padding(bottom = 28.dp),
verticalArrangement = Arrangement.SpaceBetween,
) {
Column(modifier = modifier.fillMaxWidth()) {
state.availableOptions.map {
val selected = it == state.selectedSecurityMode
val title = it.toTitleRes()
val subtitle = when (it) {
SecurityOption.LongTap -> R.string.details_manage_security_long_tap_description
SecurityOption.PassCode -> R.string.details_manage_security_passcode_description
SecurityOption.AccessCode -> R.string.details_manage_security_access_code_description
}
Row(
modifier = modifier
.fillMaxWidth()
.selectable(
selected = selected, onClick = { state.onNewModeSelected(it) },
)
.padding(start = 20.dp, end = 20.dp, bottom = 32.dp),
) {
RadioButton(
selected = selected, onClick = null,
modifier = modifier.padding(end = 20.dp),
)
Column {
Text(
text = stringResource(id = title),
style = TangemTypography.subtitle1,
color = colorResource(id = R.color.text_primary_1),
)
Spacer(modifier = modifier.size(4.dp))
Text(
text = stringResource(id = subtitle),
style = TangemTypography.body2,
color = colorResource(id = R.color.text_secondary),
)
}
}
}
state.availableOptions.map {
SecurityOption(option = it, state = state, modifier = modifier)
}
Spacer(modifier = Modifier.weight(1f))
DetailsMainButton(
title = stringResource(id = R.string.common_save_changes),
@ -107,6 +64,51 @@ fun SecurityModeOptions(
}
}
@Composable
fun SecurityOption(
option: SecurityOption, state: SecurityModeScreenState,
modifier: Modifier,
) {
val selected = option == state.selectedSecurityMode
val title = option.toTitleRes()
val subtitle = when (option) {
SecurityOption.LongTap -> R.string.details_manage_security_long_tap_description
SecurityOption.PassCode -> R.string.details_manage_security_passcode_description
SecurityOption.AccessCode -> R.string.details_manage_security_access_code_description
}
Row(
modifier = modifier
.fillMaxWidth()
.selectable(
selected = selected, onClick = { state.onNewModeSelected(option) },
)
.padding(start = 20.dp, end = 20.dp, bottom = 32.dp),
) {
RadioButton(
selected = selected, onClick = null,
modifier = modifier.padding(end = 20.dp),
)
Column {
Text(
text = stringResource(id = title),
style = TangemTypography.subtitle1,
color = colorResource(id = R.color.text_primary_1),
)
Spacer(modifier = modifier.size(4.dp))
Text(
text = stringResource(id = subtitle),
style = TangemTypography.body2,
color = colorResource(id = R.color.text_secondary),
)
}
}
}
@Preview
@Composable
fun SecurityModeScreenPreview() {
@ -118,6 +120,6 @@ fun SecurityModeScreenPreview() {
onNewModeSelected = {},
onSaveChangesClicked = {},
),
{}
onBackPressed = {},
)
}

View file

@ -9,13 +9,15 @@ import org.rekotlin.Store
class SecurityModeViewModel(val store: Store<AppState>) {
fun updateState(state: ManageSecurityState?): SecurityModeScreenState {
if (state == null) return SecurityModeScreenState(
emptyList(), SecurityOption.LongTap, false, {},
{},
availableOptions = emptyList(),
selectedSecurityMode = SecurityOption.LongTap,
isSaveChangesEnabled = false,
onNewModeSelected = {},
onSaveChangesClicked = {},
)
return SecurityModeScreenState(
state.allowedOptions.toList(),
availableOptions = state.allowedOptions.toList(),
selectedSecurityMode = state.selectedOption,
isSaveChangesEnabled = state.selectedOption != state.currentOption,
onNewModeSelected = { store.dispatch(DetailsAction.ManageSecurity.SelectOption(it)) },