Skip to content

Commit fd5d0fe

Browse files
authored
feat: updated deposit and withdrawal flows with currency selection and USDC info screens (#751)
* feat: updated deposit and withdrawal flows with currency selection and USDC info screens Signed-off-by: Brandon McAnsh <git@bmcreations.dev> * feat: refactor TokenBalanceStyle into sealed interface with per-style textStyle and selection Signed-off-by: Brandon McAnsh <git@bmcreations.dev> --------- Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 58852dd commit fd5d0fe

29 files changed

Lines changed: 462 additions & 189 deletions

File tree

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

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -167,23 +167,15 @@ sealed interface AppRoute : NavKey, Parcelable {
167167
@Parcelize
168168
sealed interface Transfers : AppRoute {
169169
@Serializable
170-
data class Deposit(val mint: Mint): Transfers, FlowRouteWithResult<DepositResult> {
170+
data class Deposit(val showOtherOptions: Boolean = true): Transfers, FlowRouteWithResult<DepositResult> {
171171
override val initialStack: List<NavKey>
172-
get() = if (mint == Mint.usdf) {
173-
listOf(DepositStep.UsdcInformational)
174-
} else {
175-
listOf(DepositStep.Destination(mint))
176-
}
172+
get() = listOf(DepositStep.UsdcInformational(showOtherOptions))
177173
}
178174

179175
@Serializable
180-
data class Withdrawal(val mint: Mint) : Transfers, FlowRouteWithResult<WithdrawalResult> {
176+
data class Withdrawal(val showOtherOptions: Boolean = true) : Transfers, FlowRouteWithResult<WithdrawalResult> {
181177
override val initialStack: List<NavKey>
182-
get() = if (mint == Mint.usdf) {
183-
listOf(WithdrawalStep.UsdcInformational)
184-
} else {
185-
listOf(WithdrawalStep.Amount(mint))
186-
}
178+
get() = listOf(WithdrawalStep.UsdcInformational(showOtherOptions))
187179
}
188180
}
189181

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/deposit/DepositStep.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ import kotlinx.serialization.Serializable
1313
@Serializable
1414
sealed interface DepositStep : FlowStep, Parcelable {
1515
@Parcelize
16-
object UsdcInformational : DepositStep
16+
data class UsdcInformational(val showOtherOptions: Boolean) : DepositStep
1717

1818

19+
@Parcelize
20+
@Serializable
21+
data object SelectToken: DepositStep
1922
@Parcelize
2023
@Serializable
2124
data class Destination(val mint: Mint) : DepositStep

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/SwapResult.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ sealed interface SwapResult : Parcelable {
1313
@Parcelize
1414
@Serializable
1515
data object Canceled : SwapResult
16+
17+
@Parcelize
18+
@Serializable
19+
data object OpenDeposit : SwapResult
1620
}

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/ui/TokenBalanceRow.kt

Lines changed: 111 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.flipcash.app.core.ui
22

33
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.border
45
import androidx.compose.foundation.clickable
56
import androidx.compose.foundation.layout.Arrangement
67
import androidx.compose.foundation.layout.PaddingValues
@@ -11,7 +12,8 @@ import androidx.compose.foundation.layout.size
1112
import androidx.compose.foundation.layout.width
1213
import androidx.compose.foundation.layout.wrapContentWidth
1314
import androidx.compose.foundation.shape.CircleShape
14-
import androidx.compose.material.Text
15+
import androidx.compose.material3.Icon
16+
import androidx.compose.material3.Text
1517
import androidx.compose.runtime.Composable
1618
import androidx.compose.ui.Alignment
1719
import androidx.compose.ui.Modifier
@@ -20,30 +22,56 @@ import androidx.compose.ui.graphics.painter.Painter
2022
import androidx.compose.ui.res.painterResource
2123
import androidx.compose.ui.text.TextStyle
2224
import androidx.compose.ui.unit.Dp
25+
import androidx.compose.ui.unit.dp
2326
import com.flipcash.core.R
2427
import com.getcode.opencode.compose.LocalExchange
2528
import com.getcode.opencode.model.financial.Fiat
2629
import com.getcode.opencode.model.financial.Token
2730
import com.getcode.opencode.model.financial.TokenWithBalance
2831
import com.getcode.opencode.model.financial.TokenWithLocalizedBalance
2932
import com.getcode.theme.CodeTheme
33+
import com.getcode.theme.White20
34+
import com.getcode.theme.extraSmall
3035
import com.getcode.ui.components.text.AnimatedNumberText
3136
import com.getcode.ui.core.addIf
3237

33-
data class TokenBalanceRowSizing(
38+
sealed interface TokenBalanceStyle {
39+
val textStyle: TextStyle
40+
41+
data class Large(override val textStyle: TextStyle = TextStyle.Default) : TokenBalanceStyle
42+
data class Pill(override val textStyle: TextStyle = TextStyle.Default) : TokenBalanceStyle
43+
}
44+
45+
enum class TokenSelectionStyle {
46+
None,
47+
Chevron,
48+
Checkbox,
49+
;
50+
}
51+
52+
data class TokenBalanceRowStyling(
3453
val nameTextStyle: TextStyle,
35-
val balanceTextStyle: TextStyle,
54+
val balanceDisplayStyle: TokenBalanceStyle,
3655
val iconSize: Dp,
3756
val flagSize: Dp,
57+
val selectionStyle: TokenSelectionStyle,
3858
)
3959

4060
@Composable
41-
fun rememberTokenBalanceRowSizing(
61+
fun rememberTokenBalanceRowStyling(
4262
nameTextStyle: TextStyle = CodeTheme.typography.screenTitle,
43-
balanceTextStyle: TextStyle = CodeTheme.typography.screenTitle,
63+
balanceDisplayStyle: TokenBalanceStyle = TokenBalanceStyle.Large(),
4464
iconSize: Dp = CodeTheme.dimens.staticGrid.x6,
4565
flagSize: Dp = CodeTheme.dimens.staticGrid.x3,
46-
): TokenBalanceRowSizing = TokenBalanceRowSizing(nameTextStyle, balanceTextStyle, iconSize, flagSize)
66+
selectionStyle: TokenSelectionStyle = TokenSelectionStyle.None,
67+
): TokenBalanceRowStyling =
68+
TokenBalanceRowStyling(
69+
nameTextStyle = nameTextStyle,
70+
balanceDisplayStyle = balanceDisplayStyle,
71+
iconSize = iconSize,
72+
flagSize = flagSize,
73+
selectionStyle = selectionStyle
74+
)
4775

4876
@Composable
4977
fun TokenBalanceRow(
@@ -56,7 +84,7 @@ fun TokenBalanceRow(
5684
iconOverride: @Composable ((Any?) -> Any?) = { it },
5785
formattedBalance: (Fiat) -> String = { it.formatted() },
5886
horizontalArrangement: Arrangement.Horizontal = Arrangement.SpaceBetween,
59-
sizing: TokenBalanceRowSizing = rememberTokenBalanceRowSizing(),
87+
styling: TokenBalanceRowStyling = rememberTokenBalanceRowStyling(),
6088
contentPadding: PaddingValues = PaddingValues(vertical = CodeTheme.dimens.inset),
6189
onClick: (() -> Unit)? = null,
6290
) {
@@ -72,7 +100,7 @@ fun TokenBalanceRow(
72100
showName = showName,
73101
showFlag = showFlag,
74102
showLogo = showLogo,
75-
sizing = sizing,
103+
styling = styling,
76104
horizontalArrangement = horizontalArrangement,
77105
contentPadding = contentPadding,
78106
onClick = onClick
@@ -90,7 +118,7 @@ fun TokenBalanceRow(
90118
iconOverride: @Composable ((Any?) -> Any?) = { it },
91119
formattedBalance: (Fiat) -> String = { it.formatted() },
92120
horizontalArrangement: Arrangement.Horizontal = Arrangement.SpaceBetween,
93-
sizing: TokenBalanceRowSizing = rememberTokenBalanceRowSizing(),
121+
styling: TokenBalanceRowStyling = rememberTokenBalanceRowStyling(),
94122
contentPadding: PaddingValues = PaddingValues(vertical = CodeTheme.dimens.inset),
95123
onClick: (() -> Unit)? = null,
96124
) {
@@ -104,7 +132,7 @@ fun TokenBalanceRow(
104132
showFlag = showFlag,
105133
isSelected = isSelected,
106134
modifier = modifier,
107-
sizing = sizing,
135+
styling = styling,
108136
iconOverride = iconOverride,
109137
formattedBalance = formattedBalance,
110138
horizontalArrangement = horizontalArrangement,
@@ -127,7 +155,7 @@ fun TokenBalanceRow(
127155
iconOverride: @Composable ((Any?) -> Any?) = { it },
128156
formattedBalance: (Fiat) -> String = { it.formatted() },
129157
horizontalArrangement: Arrangement.Horizontal = Arrangement.SpaceBetween,
130-
sizing: TokenBalanceRowSizing = rememberTokenBalanceRowSizing(),
158+
styling: TokenBalanceRowStyling = rememberTokenBalanceRowStyling(),
131159
contentPadding: PaddingValues = PaddingValues(vertical = CodeTheme.dimens.inset),
132160
onClick: (() -> Unit)? = null,
133161
) {
@@ -150,8 +178,8 @@ fun TokenBalanceRow(
150178
token = token,
151179
iconOverride = iconOverride,
152180
displayName = { displayName },
153-
imageSize = sizing.iconSize,
154-
textStyle = sizing.nameTextStyle,
181+
imageSize = styling.iconSize,
182+
textStyle = styling.nameTextStyle,
155183
textColor = CodeTheme.colors.textMain,
156184
spacing = CodeTheme.dimens.grid.x2,
157185
)
@@ -162,19 +190,20 @@ fun TokenBalanceRow(
162190
is Painter -> Image(
163191
painter = image,
164192
contentDescription = null,
165-
modifier = Modifier.size(sizing.iconSize),
193+
modifier = Modifier.size(styling.iconSize),
166194
)
195+
167196
else -> TokenIcon(
168197
image = image,
169-
modifier = Modifier.size(sizing.iconSize)
198+
modifier = Modifier.size(styling.iconSize)
170199
)
171200
}
172201
}
173202

174203
showName -> {
175204
Text(
176205
text = displayName,
177-
style = sizing.nameTextStyle,
206+
style = styling.nameTextStyle,
178207
color = CodeTheme.colors.textMain,
179208
)
180209
}
@@ -190,33 +219,79 @@ fun TokenBalanceRow(
190219
flag?.let {
191220
Image(
192221
modifier = Modifier
193-
.height(sizing.flagSize)
194-
.width(sizing.flagSize)
222+
.height(styling.flagSize)
223+
.width(styling.flagSize)
195224
.clip(CircleShape),
196225
painter = painterResource(it),
197226
contentDescription = ""
198227
)
199228
}
200229
}
201230

202-
AnimatedNumberText(
203-
value = formattedBalance(balance),
204-
style = sizing.balanceTextStyle,
205-
color = CodeTheme.colors.textMain,
206-
)
207-
208-
if (isSelected != null) {
209-
Image(
210-
modifier = Modifier
211-
.wrapContentWidth()
212-
.padding(start = CodeTheme.dimens.grid.x3),
213-
painter = painterResource(
214-
if (isSelected)
215-
R.drawable.ic_checked else R.drawable.ic_unchecked
216-
),
217-
contentDescription = ""
218-
)
231+
when (val displayStyle = styling.balanceDisplayStyle) {
232+
is TokenBalanceStyle.Large -> {
233+
val resolvedTextStyle = displayStyle.textStyle
234+
.takeUnless { it == TextStyle.Default }
235+
?: CodeTheme.typography.screenTitle
236+
237+
AnimatedNumberText(
238+
value = formattedBalance(balance),
239+
style = resolvedTextStyle,
240+
color = CodeTheme.colors.textMain,
241+
)
242+
}
243+
244+
is TokenBalanceStyle.Pill -> {
245+
val resolvedTextStyle = displayStyle.textStyle
246+
.takeUnless { it == TextStyle.Default }
247+
?: CodeTheme.typography.caption
248+
249+
Text(
250+
modifier = Modifier
251+
.padding(start = CodeTheme.dimens.grid.x1)
252+
.border(
253+
width = CodeTheme.dimens.border,
254+
color = White20,
255+
shape = CodeTheme.shapes.extraSmall,
256+
)
257+
.padding(
258+
horizontal = 4.dp,
259+
vertical = 3.dp
260+
),
261+
text = formattedBalance(balance),
262+
color = CodeTheme.colors.textSecondary,
263+
style = resolvedTextStyle,
264+
)
265+
}
266+
}
267+
268+
when (styling.selectionStyle) {
269+
TokenSelectionStyle.Chevron -> {
270+
Icon(
271+
modifier = Modifier.padding(start = CodeTheme.dimens.grid.x1),
272+
painter = painterResource(R.drawable.ic_chevron_right),
273+
contentDescription = null,
274+
tint = CodeTheme.colors.secondary,
275+
)
276+
}
277+
278+
TokenSelectionStyle.Checkbox -> {
279+
if (isSelected != null) {
280+
Image(
281+
modifier = Modifier
282+
.wrapContentWidth()
283+
.padding(start = CodeTheme.dimens.grid.x3),
284+
painter = painterResource(
285+
if (isSelected)
286+
R.drawable.ic_checked else R.drawable.ic_unchecked
287+
),
288+
contentDescription = ""
289+
)
290+
}
291+
}
292+
293+
TokenSelectionStyle.None -> Unit
219294
}
220295
}
221296
}
222-
}
297+
}

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import kotlinx.serialization.Serializable
1414
@Serializable
1515
sealed interface WithdrawalStep : FlowStep, Parcelable {
1616
@Parcelize
17-
object UsdcInformational: WithdrawalStep
17+
data class UsdcInformational(val showOtherOptions: Boolean): WithdrawalStep
18+
19+
@Parcelize
20+
@Serializable
21+
data object SelectToken: WithdrawalStep
1822
@Parcelize
1923
@Serializable
2024
data class Amount(val mint: Mint) : WithdrawalStep

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,4 +669,7 @@
669669
<string name="description_buyWithPhantomConnected">Confirm the transaction in Phantom to continue</string>
670670

671671
<string name="title_depositToken">Deposit %1$s</string>
672+
673+
<string name="action_depositOtherCurrencies">Deposit Other Flipcash Currencies</string>
674+
<string name="action_withdrawOtherCurrencies">Withdraw Other Flipcash Currencies</string>
672675
</resources>

apps/flipcash/features/advanced/src/main/kotlin/com/flipcash/app/advanced/internal/AdvancedFeatureMenuItems.kt

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,6 @@ import com.flipcash.app.core.tokens.TokenPurpose
1414
import com.flipcash.app.menu.FullMenuItem
1515
import com.flipcash.features.advanced.R
1616

17-
internal data object CurrencyCreator : FullMenuItem<AdvancedFeaturesScreenViewModel.Event>() {
18-
override val icon: Painter
19-
@Composable get() = rememberVectorPainter(Icons.Default.AddCircle)
20-
override val name: String
21-
@Composable get() = stringResource(R.string.title_createYourCurrency)
22-
override val action: AdvancedFeaturesScreenViewModel.Event = AdvancedFeaturesScreenViewModel.Event.OpenScreen(
23-
AppRoute.Token.CurrencyCreator
24-
)
25-
}
26-
2717
internal data object BillCustomizer : FullMenuItem<AdvancedFeaturesScreenViewModel.Event>() {
2818
override val icon: Painter
2919
@Composable get() = rememberVectorPainter(Icons.Outlined.Palette)
@@ -32,16 +22,6 @@ internal data object BillCustomizer : FullMenuItem<AdvancedFeaturesScreenViewMod
3222
override val action: AdvancedFeaturesScreenViewModel.Event = AdvancedFeaturesScreenViewModel.Event.OpenBillPlayground
3323
}
3424

35-
internal data object Deposit : FullMenuItem<AdvancedFeaturesScreenViewModel.Event>() {
36-
override val icon: Painter
37-
@Composable get() = painterResource(R.drawable.ic_menu_deposit)
38-
override val name: String
39-
@Composable get() = stringResource(R.string.title_depositFunds)
40-
override val action: AdvancedFeaturesScreenViewModel.Event = AdvancedFeaturesScreenViewModel.Event.OpenScreen(
41-
AppRoute.Sheets.TokenSelection(purpose = TokenPurpose.Deposit)
42-
)
43-
}
44-
4525
internal data object DeviceLogs : FullMenuItem<AdvancedFeaturesScreenViewModel.Event>() {
4626
override val icon: Painter
4727
@Composable get() = rememberVectorPainter(Icons.Outlined.Description)

0 commit comments

Comments
 (0)