Updated on 2026-08-14

This commit is contained in:
Tangem 2023-03-21 14:51:37 +03:00
parent f34c9f8213
commit b6ea8b264b
7 changed files with 505 additions and 441 deletions

View file

@ -4,8 +4,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
@ -21,9 +19,6 @@ class DetailsFragment : Fragment(), StoreSubscriber<DetailsState> {
private val detailsViewModel = DetailsViewModel(store)
private var detailsScreenState: MutableState<DetailsScreenState> =
mutableStateOf(detailsViewModel.updateState(store.state.detailsState))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Analytics.send(Settings.ScreenOpened())
@ -42,7 +37,7 @@ class DetailsFragment : Fragment(), StoreSubscriber<DetailsState> {
isTransitionGroup = true
TangemTheme {
DetailsScreen(
state = detailsScreenState.value,
state = detailsViewModel.detailsScreenState.value,
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
)
}
@ -66,6 +61,6 @@ class DetailsFragment : Fragment(), StoreSubscriber<DetailsState> {
override fun newState(state: DetailsState) {
if (activity == null || view == null) return
detailsScreenState.value = detailsViewModel.updateState(state)
detailsViewModel.detailsScreenState.value = detailsViewModel.updateState(state)
}
}

View file

@ -2,6 +2,8 @@ package com.tangem.tap.features.details.ui.details
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -16,8 +18,13 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Icon
import androidx.compose.material.SnackbarHost
import androidx.compose.material.SnackbarHostState
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
@ -27,10 +34,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SystemBarsEffect
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.common.compose.TangemTypography
import com.tangem.tap.features.details.ui.common.ScreenTitle
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
import com.tangem.wallet.R
import kotlinx.coroutines.launch
@Composable
fun DetailsScreen(state: DetailsScreenState, onBackClick: () -> Unit) {
@ -46,32 +55,35 @@ fun DetailsScreen(state: DetailsScreenState, onBackClick: () -> Unit) {
@Composable
fun Content(state: DetailsScreenState) {
Column(
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) },
)
Box {
Column(
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 = TangemTypography.caption,
color = colorResource(id = R.color.text_tertiary),
modifier = Modifier.padding(start = 16.dp, end = 16.dp, bottom = 40.dp),
)
}
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 = TangemTypography.caption,
color = colorResource(id = R.color.text_tertiary),
modifier = Modifier.padding(start = 16.dp, end = 16.dp, bottom = 40.dp),
)
ShowSnackbarIfNeeded(state.showErrorSnackbar.value)
}
}
@ -165,6 +177,36 @@ fun TangemSocialAccounts(
}
}
@Composable
fun BoxScope.ShowSnackbarIfNeeded(snackbarErrorState: EventError) {
val snackbarHostState = remember { SnackbarHostState() }
val coroutineScope = rememberCoroutineScope()
SnackbarHost(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(vertical = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
hostState = snackbarHostState,
)
val errorTitle = when (snackbarErrorState) {
is EventError.DemoReferralNotAvailable -> stringResource(id = R.string.alert_demo_feature_disabled)
EventError.Empty -> ""
}
if (snackbarErrorState != EventError.Empty) {
SideEffect {
coroutineScope.launch {
snackbarHostState.showSnackbar(errorTitle)
}
when (snackbarErrorState) {
is EventError.DemoReferralNotAvailable -> snackbarErrorState.onErrorShow.invoke()
else -> {
/*no-op*/
}
}
}
}
}
@Composable
@Preview
private fun Preview() {

View file

@ -1,6 +1,8 @@
package com.tangem.tap.features.details.ui.details
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import com.tangem.wallet.R
@Immutable
@ -11,6 +13,7 @@ data class DetailsScreenState(
val appCurrency: String,
val onItemsClick: (SettingsElement) -> Unit,
val onSocialNetworkClick: (SocialNetworkLink) -> Unit,
val showErrorSnackbar: MutableState<EventError> = mutableStateOf(EventError.Empty),
) {
val appNameRes: Int = R.string.tangem_app_name
}
@ -39,6 +42,11 @@ data class SocialNetworkLink(
val url: String,
)
sealed class EventError {
object Empty : EventError()
data class DemoReferralNotAvailable(val onErrorShow: () -> Unit) : EventError()
}
sealed class SocialNetwork(val id: String, val iconRes: Int) {
object Telegram : SocialNetwork("Telegram", R.drawable.ic_telegram)
object Twitter : SocialNetwork("Twitter", R.drawable.ic_twitter)

View file

@ -1,5 +1,7 @@
package com.tangem.tap.features.details.ui.details
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.tap.common.feedback.FeedbackEmail
@ -8,6 +10,7 @@ import com.tangem.tap.common.redux.AppState
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.features.demo.DemoHelper
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.home.LocaleRegionProvider
@ -18,6 +21,9 @@ import org.rekotlin.Store
class DetailsViewModel(private val store: Store<AppState>) {
var detailsScreenState: MutableState<DetailsScreenState> = mutableStateOf(updateState(store.state.detailsState))
private set
@Suppress("ComplexMethod")
fun updateState(state: DetailsState): DetailsScreenState {
val cardTypesResolver = state.scanResponse?.cardTypesResolver
@ -95,7 +101,15 @@ class DetailsViewModel(private val store: Store<AppState>) {
// TODO: To be available later
}
SettingsElement.ReferralProgram -> {
store.dispatch(NavigationAction.NavigateTo(AppScreen.ReferralProgram))
if (store.state.detailsState.scanResponse?.let { DemoHelper.isDemoCard(it) } == true) {
detailsScreenState.value.showErrorSnackbar.value = EventError.DemoReferralNotAvailable(
onErrorShow = {
detailsScreenState.value.showErrorSnackbar.value = EventError.Empty
},
)
} else {
store.dispatch(NavigationAction.NavigateTo(AppScreen.ReferralProgram))
}
}
SettingsElement.TesterMenu -> {
store.state.daggerGraphState.testerRouter?.startTesterScreen()