Updated on 2026-08-14

This commit is contained in:
Tangem 2023-06-01 20:10:08 +08:00
parent 2782d8a846
commit 8262c72f40
15 changed files with 230 additions and 18 deletions

View file

@ -0,0 +1,18 @@
package com.tangem.feature.wallet.di
import com.tangem.feature.wallet.presentation.router.DefaultWalletRouter
import com.tangem.features.wallet.navigation.WalletRouter
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.scopes.ActivityScoped
@Module
@InstallIn(ActivityComponent::class)
internal object WalletRouterModule {
@Provides
@ActivityScoped
fun provideWalletRouter(): WalletRouter = DefaultWalletRouter()
}

View file

@ -8,9 +8,11 @@ import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.WindowCompat
import androidx.fragment.app.Fragment
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
import com.tangem.features.wallet.navigation.WalletRouter
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
/**
* Wallet fragment
@ -18,7 +20,16 @@ import dagger.hilt.android.AndroidEntryPoint
[REDACTED_AUTHOR]
*/
@AndroidEntryPoint
class WalletFragment : Fragment() {
internal class WalletFragment : Fragment() {
/** Feature router */
@Inject
internal lateinit var walletRouter: WalletRouter
private val _walletRouter: InnerWalletRouter
get() = requireNotNull(walletRouter as? InnerWalletRouter) {
"_walletRouter should be instance of InnerWalletRouter"
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) }
@ -31,11 +42,14 @@ class WalletFragment : Fragment() {
return ComposeView(inflater.context).apply {
setContent {
isTransitionGroup = true
TangemTheme {
// TODO: [REDACTED_TASK_KEY] Call WalletScreen
}
_walletRouter.Initialize()
}
}
}
companion object {
/** Create wallet fragment instance */
fun create(): WalletFragment = WalletFragment()
}
}

View file

@ -0,0 +1,51 @@
package com.tangem.feature.wallet.presentation.router
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.fragment.app.Fragment
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.presentation.WalletFragment
import com.tangem.feature.wallet.presentation.ui.WalletScreen
import com.tangem.feature.wallet.presentation.viewmodels.WalletViewModel
import kotlin.properties.Delegates
/** Default implementation of wallet feature router */
internal class DefaultWalletRouter : InnerWalletRouter {
private var navController: NavHostController by Delegates.notNull()
override fun getEntryFragment(): Fragment = WalletFragment.create()
@Composable
override fun Initialize() {
TangemTheme {
NavHost(
navController = rememberNavController().apply { navController = this },
startDestination = WalletScreens.WALLET.name,
) {
composable(WalletScreens.WALLET.name) {
val viewModel = hiltViewModel<WalletViewModel>().apply { router = this@DefaultWalletRouter }
WalletScreen(state = viewModel.uiState)
}
composable(WalletScreens.ORGANIZE_TOKENS.name) {
BackHandler(onBack = ::popBackStack)
// TODO: Add OrganizeTokensScreen
}
}
}
}
override fun popBackStack() {
navController.popBackStack()
}
override fun openOrganizeTokensScreen() {
navController.navigate(WalletScreens.ORGANIZE_TOKENS.name)
}
}

View file

@ -0,0 +1,23 @@
package com.tangem.feature.wallet.presentation.router
import androidx.compose.runtime.Composable
import com.tangem.features.wallet.navigation.WalletRouter
/**
* Interface of inner wallet feature router
*
[REDACTED_AUTHOR]
*/
internal interface InnerWalletRouter : WalletRouter {
/** Initialize router */
@Suppress("TopLevelComposableFunctions")
@Composable
fun Initialize()
/** Pop back stack */
fun popBackStack()
/** Open organize tokens screen */
fun openOrganizeTokensScreen()
}

View file

@ -0,0 +1,10 @@
package com.tangem.feature.wallet.presentation.router
/**
* Wallet feature screens
*
[REDACTED_AUTHOR]
*/
enum class WalletScreens {
WALLET, ORGANIZE_TOKENS
}

View file

@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.ui
import com.tangem.core.ui.R
import com.tangem.feature.wallet.presentation.state.WalletCardState
import com.tangem.feature.wallet.presentation.state.WalletStateHolder
import java.util.UUID
internal object WalletPreviewData {
@ -38,4 +39,13 @@ internal object WalletPreviewData {
imageResId = R.drawable.ill_businessman_3d,
onClick = {},
)
val walletScreenState = WalletStateHolder(
onBackClick = {},
headerConfig = WalletStateHolder.HeaderConfig(
wallets = listOf(walletCardContent, walletCardLoading, walletCardHiddenContent, walletCardError),
onScanCardClick = {},
onMoreClick = {},
),
)
}

View file

@ -1,11 +1,17 @@
package com.tangem.feature.wallet.presentation.ui.components
import androidx.compose.animation.core.*
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.LocalOverscrollConfiguration
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
@ -26,6 +32,7 @@ import com.tangem.feature.wallet.presentation.ui.WalletPreviewData
*
[REDACTED_AUTHOR]
*/
@OptIn(ExperimentalFoundationApi::class)
@Composable
internal fun WalletHeader(config: WalletStateHolder.HeaderConfig) {
Column(
@ -34,15 +41,23 @@ internal fun WalletHeader(config: WalletStateHolder.HeaderConfig) {
.padding(bottom = TangemTheme.dimens.spacing14),
) {
TopBar(onScanCardClick = config.onScanCardClick, onMoreClick = config.onMoreClick)
LazyRow(
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16),
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
items(items = config.wallets, key = WalletCardState::id) { state ->
WalletCard(
state = state,
modifier = Modifier.width(LocalConfiguration.current.screenWidthDp.dp - TangemTheme.dimens.size32),
)
CompositionLocalProvider(LocalOverscrollConfiguration provides null) {
val lazyListState = rememberLazyListState()
LazyRow(
state = lazyListState,
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16),
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
flingBehavior = rememberSnapFlingBehavior(lazyListState = lazyListState),
) {
items(items = config.wallets, key = WalletCardState::id) { state ->
WalletCard(
state = state,
modifier = Modifier.width(
LocalConfiguration.current.screenWidthDp.dp - TangemTheme.dimens.size32,
),
)
}
}
}
}

View file

@ -0,0 +1,36 @@
package com.tangem.feature.wallet.presentation.viewmodels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
import com.tangem.feature.wallet.presentation.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.ui.WalletPreviewData
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlin.properties.Delegates
/**
* Wallet screen view model
*
[REDACTED_AUTHOR]
*/
@HiltViewModel
internal class WalletViewModel @Inject constructor() : ViewModel() {
/** Feature router */
var router: InnerWalletRouter by Delegates.notNull()
/** Screen state */
var uiState by mutableStateOf(getInitialState())
private set
// TODO: [REDACTED_TASK_KEY] Use production data instead of WalletPreviewData
private fun getInitialState(): WalletStateHolder = WalletPreviewData.walletScreenState.copy(
onBackClick = { router.popBackStack() },
headerConfig = WalletPreviewData.walletScreenState.headerConfig.copy(
onScanCardClick = { router.openOrganizeTokensScreen() },
),
)
}