Skip to content

Commit 95419f3

Browse files
committed
feat: add early token selection to give flow
Signed-off-by: Brandon McAnsh <[email protected]>
1 parent 96b9c72 commit 95419f3

File tree

38 files changed

+604
-196
lines changed

38 files changed

+604
-196
lines changed

apps/flipcash/app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ dependencies {
154154
implementation(project(":apps:flipcash:shared:permissions"))
155155
implementation(project(":apps:flipcash:shared:phone"))
156156
implementation(project(":apps:flipcash:shared:shareable"))
157+
implementation(project(":apps:flipcash:shared:tokens"))
157158
implementation(project(":apps:flipcash:shared:transfers"))
158159
implementation(project(":apps:flipcash:shared:web"))
159160
implementation(project(":apps:flipcash:shared:workers"))
@@ -175,6 +176,7 @@ dependencies {
175176
implementation(project(":apps:flipcash:features:payments"))
176177
implementation(project(":apps:flipcash:features:onramp"))
177178
implementation(project(":apps:flipcash:features:contact-verification"))
179+
implementation(project(":apps:flipcash:features:tokens"))
178180

179181
implementation(project(":libs:crypto:solana"))
180182
implementation(project(":libs:datetime"))

apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import com.flipcash.app.balance.PreloadBalance
1111
import com.flipcash.app.cash.CashScreen
1212
import com.flipcash.app.contact.verification.VerificationFlowScreen
1313
import com.flipcash.app.core.AppRoute
14-
import com.flipcash.app.currency.CurrencySelectionScreen
14+
import com.flipcash.app.currency.RegionSelectionScreen
1515
import com.flipcash.app.deposit.DepositScreen
1616
import com.flipcash.app.lab.LabsScreen
1717
import com.flipcash.app.lab.PreloadLabs
@@ -34,6 +34,7 @@ import com.flipcash.app.pools.create.PoolQuestionScreen
3434
import com.flipcash.app.purchase.PurchaseAccountScreen
3535
import com.flipcash.app.scanner.ScannerScreen
3636
import com.flipcash.app.shareapp.ShareAppScreen
37+
import com.flipcash.app.tokens.SelectTokenScreen
3738
import com.flipcash.app.transfers.TransferInformationalScreen
3839
import com.flipcash.app.withdrawal.WithdrawalConfirmationScreen
3940
import com.flipcash.app.withdrawal.WithdrawalDestinationScreen
@@ -72,8 +73,12 @@ internal fun AppScreenContent(content: @Composable () -> Unit) {
7273
ScannerScreen(it.deeplink)
7374
}
7475

75-
register<AppRoute.Sheets.Give> {
76-
CashScreen()
76+
register<AppRoute.Main.Give> {
77+
CashScreen(it.tokenAddress)
78+
}
79+
80+
register<AppRoute.Sheets.TokenSelection> {
81+
SelectTokenScreen()
7782
}
7883

7984
register<AppRoute.Sheets.Wallet> {
@@ -104,8 +109,8 @@ internal fun AppScreenContent(content: @Composable () -> Unit) {
104109
)
105110
}
106111

107-
register<AppRoute.Main.CurrencySelection> {
108-
CurrencySelectionScreen(it.kind)
112+
register<AppRoute.Main.RegionSelection> {
113+
RegionSelectionScreen(it.kind)
109114
}
110115

111116
register<AppRoute.Sheets.ShareApp> {

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/AppRoute.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ package com.flipcash.app.core
22

33
import android.os.Parcelable
44
import cafe.adriel.voyager.core.registry.ScreenProvider
5-
import com.flipcash.app.core.money.CurrencySelectionKind
5+
import com.flipcash.app.core.money.RegionSelectionKind
66
import com.flipcash.app.core.navigation.DeeplinkType
77
import com.flipcash.app.core.transfers.TransferDirection
88
import com.getcode.ed25519.Ed25519
99
import com.getcode.opencode.model.core.ID
1010
import com.getcode.opencode.model.financial.Fiat
11+
import com.getcode.solana.keys.PublicKey
1112
import com.getcode.ui.core.RestrictionType
1213
import kotlinx.parcelize.Parcelize
1314

@@ -34,7 +35,10 @@ sealed interface AppRoute : ScreenProvider, Parcelable {
3435
data class Scanner(val deeplink: DeeplinkType? = null) : Main
3536

3637
// TODO: is there a better place for this to live?
37-
data class CurrencySelection(val kind: CurrencySelectionKind) : Main
38+
data class RegionSelection(val kind: RegionSelectionKind) : Main
39+
40+
41+
data class Give(val tokenAddress: PublicKey?) : Main
3842
}
3943

4044
@Parcelize
@@ -49,7 +53,7 @@ sealed interface AppRoute : ScreenProvider, Parcelable {
4953

5054
@Parcelize
5155
sealed interface Sheets: AppRoute {
52-
data object Give : Sheets
56+
data object TokenSelection: Sheets
5357
data object Wallet : Sheets
5458
data object Menu : Sheets
5559
data object Lab: Sheets

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/money/CurrencySelectionKind.kt renamed to apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/money/RegionSelectionKind.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.flipcash.app.core.money
22

3-
enum class CurrencySelectionKind {
3+
enum class RegionSelectionKind {
44
Entry,
55
Balance;
66
}

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onramp/deeplinks/WalletDeeplinkConnectionResult.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import android.os.Parcelable
44
import com.flipcash.app.core.AppRoute
55
import com.getcode.ed25519.Ed25519
66
import com.getcode.opencode.model.core.ID
7+
import com.getcode.opencode.model.financial.Token
78
import com.getcode.opencode.utils.base64
89
import com.getcode.solana.keys.PublicKey
10+
import com.getcode.solana.keys.base58
911
import com.getcode.utils.base58
1012
import com.getcode.utils.decodeBase58
1113
import com.getcode.utils.decodeBase64
@@ -34,7 +36,7 @@ sealed class OnRampDeeplinkOrigin: Parcelable {
3436
data object Menu : OnRampDeeplinkOrigin()
3537

3638
@Parcelize
37-
data object Give: OnRampDeeplinkOrigin()
39+
data class Give(val tokenAddress: PublicKey?) : OnRampDeeplinkOrigin()
3840

3941
@Parcelize
4042
data object Wallet: OnRampDeeplinkOrigin()
@@ -50,7 +52,7 @@ sealed class OnRampDeeplinkOrigin: Parcelable {
5052
is PoolWithId -> "pool-id_${id.base58}"
5153
is PoolWithRendezvous -> "pool-seed_${keyPair.seed.base64}"
5254
Menu -> "menu"
53-
Give -> "give"
55+
is Give -> "give-${tokenAddress?.base58()}"
5456
Wallet -> "wallet"
5557
}.lowercase()
5658
}
@@ -59,7 +61,7 @@ sealed class OnRampDeeplinkOrigin: Parcelable {
5961
fun fromRoute(route: AppRoute?): OnRampDeeplinkOrigin? {
6062
return when (route) {
6163
is AppRoute.Sheets.Menu -> Menu
62-
is AppRoute.Sheets.Give -> Give
64+
is AppRoute.Main.Give -> Give(route.tokenAddress)
6365
is AppRoute.Pool.Details -> {
6466
route.rendezvous?.let { keyPair -> PoolWithRendezvous(keyPair) }
6567
route.poolId?.let { id -> PoolWithId(id) }
@@ -73,7 +75,12 @@ sealed class OnRampDeeplinkOrigin: Parcelable {
7375
fun fromString(value: String?): OnRampDeeplinkOrigin? {
7476
return when {
7577
value == "menu" -> Menu
76-
value == "give" -> Give
78+
value?.startsWith("give-") == true -> {
79+
val tokenAddress = value.removePrefix("give-")
80+
Give(tokenAddress = runCatching {
81+
PublicKey.fromBase58(tokenAddress)
82+
}.getOrNull())
83+
}
7784
value == "wallet" -> Wallet
7885
value?.startsWith("pool-") == true -> {
7986
val idStringWithPrefix = value.removePrefix("pool-")

apps/flipcash/core/src/main/res/values/strings.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,4 +403,10 @@
403403

404404
<string name="subtitle_addUsdcToWallet">Add Solana USDC to your Flipcash wallet</string>
405405

406+
<string name="title_selectCurrency">Select Currency</string>
407+
<string name="title_selectRegion">Select Region</string>
408+
<string name="title_recentRegions">Recent Regions</string>
409+
<string name="title_otherRegions">Other Regions</string>
410+
<string name="subtitle_searchRegions">Search regions</string>
411+
<string name="title_enterAmount">Enter Amount</string>
406412
</resources>

apps/flipcash/features/balance/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ dependencies {
5656
implementation(project(":apps:flipcash:shared:activityfeed"))
5757
implementation(project(":apps:flipcash:shared:onramp:common"))
5858
implementation(project(":apps:flipcash:shared:featureflags"))
59+
implementation(project(":apps:flipcash:shared:tokens"))
5960
implementation(project(":libs:datetime"))
6061
implementation(project(":libs:logging"))
6162
implementation(project(":libs:messaging"))

apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/BalanceScreen.kt

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@ import androidx.compose.runtime.LaunchedEffect
88
import androidx.compose.ui.Alignment
99
import androidx.compose.ui.Modifier
1010
import androidx.compose.ui.res.stringResource
11-
import androidx.lifecycle.Lifecycle
1211
import cafe.adriel.voyager.core.registry.ScreenRegistry
1312
import cafe.adriel.voyager.core.screen.ScreenKey
1413
import cafe.adriel.voyager.core.screen.uniqueScreenKey
14+
import cafe.adriel.voyager.hilt.getViewModel
1515
import com.flipcash.app.balance.internal.BalanceScreen
1616
import com.flipcash.app.balance.internal.BalanceViewModel
1717
import com.flipcash.app.core.AppRoute
18-
import com.flipcash.app.core.money.CurrencySelectionKind
19-
import com.flipcash.app.core.transfers.TransferDirection
18+
import com.flipcash.app.core.money.RegionSelectionKind
19+
import com.flipcash.app.tokens.SelectTokenViewModel
20+
import com.flipcash.app.tokens.TokenPurpose
2021
import com.flipcash.core.R
2122
import com.getcode.navigation.core.LocalCodeNavigator
2223
import com.getcode.navigation.extensions.getActivityScopedViewModel
2324
import com.getcode.navigation.modal.ModalScreen
2425
import com.getcode.navigation.screens.NamedScreen
2526
import com.getcode.ui.components.AppBarDefaults
2627
import com.getcode.ui.components.AppBarWithTitle
27-
import com.getcode.ui.utils.RepeatOnLifecycle
2828
import kotlinx.coroutines.flow.filterIsInstance
2929
import kotlinx.coroutines.flow.launchIn
3030
import kotlinx.coroutines.flow.map
@@ -59,16 +59,25 @@ class BalanceScreen: ModalScreen, NamedScreen, Parcelable {
5959
)
6060

6161
val viewModel = getActivityScopedViewModel<BalanceViewModel>()
62-
BalanceScreen(viewModel)
62+
val tokenViewModel = getViewModel<SelectTokenViewModel>()
63+
BalanceScreen(viewModel, tokenViewModel)
64+
65+
LaunchedEffect(tokenViewModel) {
66+
tokenViewModel.dispatchEvent(
67+
SelectTokenViewModel.Event.OnPurposeChanged(
68+
TokenPurpose.Balance
69+
)
70+
)
71+
}
6372

6473
LaunchedEffect(viewModel) {
6574
viewModel.eventFlow
6675
.filterIsInstance<BalanceViewModel.Event.OpenCurrencySelection>()
6776
.onEach {
6877
navigator.push(
6978
ScreenRegistry.get(
70-
AppRoute.Main.CurrencySelection(
71-
CurrencySelectionKind.Balance
79+
AppRoute.Main.RegionSelection(
80+
RegionSelectionKind.Balance
7281
)
7382
)
7483
)

apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/BalanceScreenContent.kt

Lines changed: 21 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,55 @@ import androidx.compose.foundation.background
44
import androidx.compose.foundation.layout.Arrangement
55
import androidx.compose.foundation.layout.Box
66
import androidx.compose.foundation.layout.Column
7-
import androidx.compose.foundation.layout.PaddingValues
8-
import androidx.compose.foundation.layout.Spacer
9-
import androidx.compose.foundation.layout.WindowInsets
10-
import androidx.compose.foundation.layout.asPaddingValues
117
import androidx.compose.foundation.layout.fillMaxWidth
12-
import androidx.compose.foundation.layout.navigationBars
138
import androidx.compose.foundation.layout.padding
14-
import androidx.compose.foundation.layout.windowInsetsPadding
15-
import androidx.compose.foundation.lazy.LazyColumn
16-
import androidx.compose.foundation.lazy.items
17-
import androidx.compose.foundation.lazy.itemsIndexed
18-
import androidx.compose.foundation.lazy.rememberLazyListState
19-
import androidx.compose.material.Divider
209
import androidx.compose.material.Text
2110
import androidx.compose.runtime.Composable
2211
import androidx.compose.runtime.CompositionLocalProvider
2312
import androidx.compose.runtime.collectAsState
2413
import androidx.compose.runtime.getValue
14+
import androidx.compose.runtime.remember
2515
import androidx.compose.ui.Alignment
2616
import androidx.compose.ui.Modifier
2717
import androidx.compose.ui.platform.LocalContext
2818
import androidx.compose.ui.res.stringResource
2919
import androidx.compose.ui.text.style.TextAlign
3020
import androidx.compose.ui.tooling.preview.Preview
3121
import com.flipcash.app.balance.internal.components.BalanceHeader
32-
import com.flipcash.app.core.ui.TokenBalanceRow
3322
import com.flipcash.app.onramp.AddCashRow
3423
import com.flipcash.app.theme.FlipcashDesignSystem
24+
import com.flipcash.app.tokens.SelectTokenViewModel
25+
import com.flipcash.app.tokens.TokenList
26+
import com.flipcash.app.tokens.TokenPurpose
3527
import com.flipcash.features.balance.R
3628
import com.getcode.opencode.compose.ExchangeStub
3729
import com.getcode.opencode.compose.LocalExchange
3830
import com.getcode.opencode.model.financial.CurrencyCode
3931
import com.getcode.opencode.model.financial.Rate
40-
import com.getcode.solana.keys.base58
4132
import com.getcode.theme.CodeTheme
42-
import com.getcode.ui.core.verticalScrollStateGradient
4333

4434
@Composable
45-
internal fun BalanceScreen(viewModel: BalanceViewModel) {
46-
val state by viewModel.stateFlow.collectAsState()
47-
35+
internal fun BalanceScreen(
36+
viewModel: BalanceViewModel,
37+
tokenViewModel: SelectTokenViewModel,
38+
) {
39+
val tokenState by tokenViewModel.stateFlow.collectAsState()
4840
BalanceScreenContent(
49-
state = state,
41+
tokenState = tokenState,
5042
dispatchEvent = viewModel::dispatchEvent
5143
)
5244
}
5345

5446
@Composable
5547
private fun BalanceScreenContent(
56-
state: BalanceViewModel.State,
48+
tokenState: SelectTokenViewModel.State,
5749
dispatchEvent: (BalanceViewModel.Event) -> Unit
5850
) {
5951
Column {
6052
BalanceHeader(
6153
modifier = Modifier
6254
.fillMaxWidth(),
63-
balance = state.totalBalance
55+
balance = tokenState.totalBalance
6456
) {
6557
dispatchEvent(BalanceViewModel.Event.OpenCurrencySelection)
6658
}
@@ -76,35 +68,11 @@ private fun BalanceScreenContent(
7668
onWithdraw = { dispatchEvent(BalanceViewModel.Event.OnWithdrawClicked) },
7769
)
7870

71+
val tokens = remember(tokenState.tokens) { tokenState.tokens }
72+
7973
TokenList(
8074
modifier = Modifier.weight(1f),
81-
state = state,
82-
dispatchEvent = dispatchEvent
83-
)
84-
}
85-
}
86-
87-
@Composable
88-
private fun TokenList(
89-
modifier: Modifier = Modifier,
90-
state: BalanceViewModel.State,
91-
dispatchEvent: (BalanceViewModel.Event) -> Unit
92-
) {
93-
val listState = rememberLazyListState()
94-
LazyColumn(
95-
modifier = modifier
96-
.verticalScrollStateGradient(
97-
scrollState = listState,
98-
color = CodeTheme.colors.background,
99-
showAtEnd = true
100-
),
101-
contentPadding = PaddingValues(
102-
bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
103-
),
104-
state = listState
105-
) {
106-
if (state.balances != null && state.balances.isEmpty()) {
107-
item {
75+
emptyState = {
10876
Box(
10977
modifier = Modifier
11078
.fillParentMaxSize()
@@ -126,20 +94,9 @@ private fun TokenList(
12694
)
12795
}
12896
}
129-
}
130-
} else {
131-
itemsIndexed(
132-
state.balances.orEmpty(),
133-
key = { index, item -> item.token.address.base58() }) { index, item ->
134-
TokenBalanceRow(
135-
modifier = Modifier.fillParentMaxWidth()
136-
.padding(horizontal = CodeTheme.dimens.inset),
137-
tokenWithBalance = item
138-
) { }
139-
140-
Divider(color = CodeTheme.colors.dividerVariant)
141-
}
142-
}
97+
},
98+
tokens = tokens,
99+
)
143100
}
144101
}
145102

@@ -161,8 +118,9 @@ private fun Preview_BalanceScreen_Empty() {
161118
) {
162119
Box(modifier = Modifier.background(CodeTheme.colors.background)) {
163120
BalanceScreenContent(
164-
state = BalanceViewModel.State(
165-
balances = emptyList()
121+
tokenState = SelectTokenViewModel.State(
122+
purpose = TokenPurpose.Balance,
123+
tokens = emptyList()
166124
),
167125
dispatchEvent = {}
168126
)

0 commit comments

Comments
 (0)