Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import com.flipcash.app.core.ui.rememberNavigationBarState
import com.flipcash.app.featureflags.FeatureFlag
import com.flipcash.app.featureflags.LocalFeatureFlags
import com.flipcash.app.session.LocalSessionController
import com.getcode.manager.BottomBarManager
import com.getcode.navigation.core.CodeNavigator
import com.getcode.theme.CodeTheme
import kotlinx.coroutines.flow.flowOf
Expand Down Expand Up @@ -55,10 +54,6 @@ internal fun AppNavigationBar(
val selectedTab = navigator.backStack.firstNotNullOfOrNull { (it as? AppRoute)?.asNavBarTab() }
val topTab = (navigator.currentRouteKey as? AppRoute)?.asNavBarTab()

// A BottomBar message (e.g. the deposit-options modal) renders above the nav host; hide the bar
// while one is showing so it sits below the modal instead of floating over it.
val bottomBarMessages by BottomBarManager.messages.collectAsStateWithLifecycle()

// A bill/tip card renders at the app root above everything; hide the bar so it doesn't show
// beneath the presented bill.
val session = LocalSessionController.current
Expand All @@ -71,8 +66,11 @@ internal fun AppNavigationBar(
.then(modifier),
contentAlignment = Alignment.BottomCenter,
) {
// Keep the bar in place for BottomBar modals (e.g. Add Money): the modal's scrim renders over
// it via z-order, and hiding it would collapse the scaffold's bottom slot and re-lay-out the
// tab content beneath (visibly re-fanning the wallet's collapsing card stack).
AnimatedVisibility(
visible = topTab != null && bottomBarMessages.isEmpty() && !billUp,
visible = topTab != null && !billUp,
enter = slideInVertically { it } + fadeIn(),
exit = slideOutVertically { it } + fadeOut(),
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
android:viewportHeight="24">
<path
android:pathData="M28.743,11.672V18.749H26.482V1.275H32.476C33.994,1.275 35.29,1.778 36.35,2.784C37.433,3.789 37.974,5.018 37.974,6.468C37.974,7.953 37.433,9.181 36.35,10.175C35.302,11.17 34.006,11.661 32.476,11.661H28.743V11.672ZM28.743,3.427V9.52H32.523C33.418,9.52 34.171,9.216 34.76,8.62C35.361,8.023 35.667,7.298 35.667,6.48C35.667,5.673 35.361,4.959 34.76,4.363C34.171,3.743 33.429,3.439 32.523,3.439H28.743V3.427Z"
android:fillColor="#5F6368"/>
android:fillColor="#FFFFFF"/>
<path
android:pathData="M43.886,6.398C45.558,6.398 46.876,6.842 47.842,7.731C48.808,8.62 49.29,9.836 49.29,11.38V18.749H47.136V17.088H47.041C46.111,18.456 44.863,19.135 43.309,19.135C41.978,19.135 40.871,18.749 39.976,17.965C39.081,17.181 38.634,16.211 38.634,15.041C38.634,13.801 39.105,12.819 40.047,12.094C40.989,11.357 42.249,10.994 43.815,10.994C45.157,10.994 46.264,11.24 47.124,11.731V11.216C47.124,10.433 46.818,9.778 46.194,9.228C45.569,8.678 44.839,8.409 44.003,8.409C42.743,8.409 41.743,8.936 41.013,10L39.022,8.76C40.118,7.181 41.743,6.398 43.886,6.398ZM40.965,15.076C40.965,15.661 41.213,16.152 41.719,16.538C42.214,16.924 42.802,17.123 43.473,17.123C44.427,17.123 45.275,16.772 46.017,16.07C46.759,15.368 47.136,14.55 47.136,13.602C46.429,13.053 45.452,12.772 44.192,12.772C43.273,12.772 42.508,12.994 41.896,13.427C41.272,13.883 40.965,14.433 40.965,15.076Z"
android:fillColor="#5F6368"/>
android:fillColor="#FFFFFF"/>
<path
android:pathData="M61.584,6.784L54.048,24H51.716L54.519,17.977L49.549,6.784H52.011L55.59,15.368H55.637L59.123,6.784H61.584Z"
android:fillColor="#5F6368"/>
android:fillColor="#FFFFFF"/>
<path
android:pathData="M19.75,10.246C19.75,9.513 19.684,8.813 19.562,8.139H10.085V11.999L15.543,12C15.322,13.284 14.609,14.379 13.518,15.109V17.613H16.767C18.663,15.869 19.75,13.291 19.75,10.246Z"
android:fillColor="#4285F4"/>
Expand Down
26 changes: 26 additions & 0 deletions apps/flipcash/core/src/main/res/drawable/ic_qr_code.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:pathData="M4,7.66667C4,5.64163 5.64163,4 7.66667,4H11C13.025,4 14.6667,5.64163 14.6667,7.66667V11C14.6667,13.025 13.025,14.6667 11,14.6667H7.66667C5.64163,14.6667 4,13.025 4,11V7.66667ZM7.66667,6C6.74619,6 6,6.74619 6,7.66667V11C6,11.9205 6.74619,12.6667 7.66667,12.6667H11C11.9205,12.6667 12.6667,11.9205 12.6667,11V7.66667C12.6667,6.74619 11.9205,6 11,6H7.66667ZM17.3333,7.66667C17.3333,5.64163 18.9749,4 21,4H24.3333C26.3584,4 28,5.64163 28,7.66667V11C28,13.025 26.3584,14.6667 24.3333,14.6667H21C18.9749,14.6667 17.3333,13.025 17.3333,11V7.66667ZM21,6C20.0795,6 19.3333,6.74619 19.3333,7.66667V11C19.3333,11.9205 20.0795,12.6667 21,12.6667H24.3333C25.2539,12.6667 26,11.9205 26,11V7.66667C26,6.74619 25.2539,6 24.3333,6H21ZM4,21C4,18.9749 5.64163,17.3333 7.66667,17.3333H11C13.025,17.3333 14.6667,18.9749 14.6667,21V24.3333C14.6667,26.3584 13.025,28 11,28H7.66667C5.64163,28 4,26.3584 4,24.3333V21ZM7.66667,19.3333C6.74619,19.3333 6,20.0795 6,21V24.3333C6,25.2539 6.74619,26 7.66667,26H11C11.9205,26 12.6667,25.2539 12.6667,24.3333V21C12.6667,20.0795 11.9205,19.3333 11,19.3333H7.66667Z" />
<path
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:pathData="M18.3333,17.3333C18.8856,17.3333 19.3333,17.7811 19.3333,18.3333V20.6667H21.6667C22.2189,20.6667 22.6667,21.1144 22.6667,21.6667C22.6667,22.2189 22.2189,22.6667 21.6667,22.6667H18.3333C17.7811,22.6667 17.3333,22.2189 17.3333,21.6667V18.3333C17.3333,17.7811 17.7811,17.3333 18.3333,17.3333ZM22.6667,18.3333C22.6667,17.7811 23.1144,17.3333 23.6667,17.3333H27C27.5523,17.3333 28,17.7811 28,18.3333C28,18.8856 27.5523,19.3333 27,19.3333H23.6667C23.1144,19.3333 22.6667,18.8856 22.6667,18.3333ZM22.6667,23.6667C22.6667,23.1144 23.1144,22.6667 23.6667,22.6667H27C27.5523,22.6667 28,23.1144 28,23.6667C28,24.2189 27.5523,24.6667 27,24.6667H24.6667V27C24.6667,27.5523 24.2189,28 23.6667,28C23.1144,28 22.6667,27.5523 22.6667,27V23.6667Z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M17.3333,26.6667C17.3333,25.9303 17.9303,25.3333 18.6667,25.3333C19.4031,25.3333 20,25.9303 20,26.6667C20,27.4031 19.4031,28 18.6667,28C17.9303,28 17.3333,27.4031 17.3333,26.6667Z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M7.33333,21.3333C7.33333,20.9652 7.63181,20.6667 8,20.6667H10.6667C11.0349,20.6667 11.3333,20.9652 11.3333,21.3333V24C11.3333,24.3681 11.0349,24.6667 10.6667,24.6667H8C7.63181,24.6667 7.33333,24.3681 7.33333,24V21.3333Z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M7.33333,8C7.33333,7.63181 7.63181,7.33333 8,7.33333H10.6667C11.0349,7.33333 11.3333,7.63181 11.3333,8V10.6667C11.3333,11.0349 11.0349,11.3333 10.6667,11.3333H8C7.63181,11.3333 7.33333,11.0349 7.33333,10.6667V8Z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M20.6667,8C20.6667,7.63181 20.9652,7.33333 21.3333,7.33333H24C24.3681,7.33333 24.6667,7.63181 24.6667,8V10.6667C24.6667,11.0349 24.3681,11.3333 24,11.3333H21.3333C20.9652,11.3333 20.6667,11.0349 20.6667,10.6667V8Z" />
</vector>
8 changes: 8 additions & 0 deletions apps/flipcash/core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,14 @@
<string name="title_onrampProviderSolflare">Solflare Wallet</string>
<string name="title_onrampProviderOtherWallet">Other Wallet</string>

<!-- v2 "Add Money With" method sheet -->
<string name="prompt_title_addMoneyWith">Add Money With</string>
<string name="label_debitCard">Debit Card</string>
<string name="label_cashReserves">Cash Reserves</string>
<string name="subtitle_depositDebitCard">Deposit funds from your debit card</string>
<string name="subtitle_depositPhantom">Deposit USDC from your Phantom wallet</string>
<string name="subtitle_depositOtherWallet">Deposit USDC from a crypto wallet</string>

<string name="action_addCashWithGooglePay">Add Cash with Google Pay</string>
<string name="action_addCashWithDebitCard">Add Cash with Debit Card</string>
<string name="action_addCashWithCreditCard">Add Cash with Credit Card</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
package com.flipcash.app.funding.internal

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.buildAnnotatedString
Expand All @@ -35,8 +43,10 @@ internal fun purchaseOptions(
state: PurchaseMethodState,
metadata: PurchaseMethodMetadata,
resources: ResourceHelper,
isNewUi: Boolean,
onClick: (PurchaseMethod) -> Unit
): List<BottomBarAction> {
if (isNewUi) return purchaseMethodCards(state, metadata, resources, onClick)
return buildList {
if (state.coinbaseOnRampAvailable) {
add(
Expand Down Expand Up @@ -101,6 +111,117 @@ internal fun purchaseOptions(
}
}

/**
* v2 "Add Money With" method rows — each a card (title + subtitle + trailing icon) rendered via the
* [BottomBarAction.content] slot. Same methods and conditions as the v1 buttons above.
*/
private fun purchaseMethodCards(
state: PurchaseMethodState,
metadata: PurchaseMethodMetadata,
resources: ResourceHelper,
onClick: (PurchaseMethod) -> Unit,
): List<BottomBarAction> = buildList {
if (state.coinbaseOnRampAvailable) {
add(
cardAction(
title = resources.getString(R.string.label_debitCard),
subtitle = resources.getString(R.string.subtitle_depositDebitCard),
iconRes = R.drawable.ic_google_pay_brand_mark,
tintIcon = false,
testTag = "purchase_method_coinbase",
onClick = { onClick(PurchaseMethod.CoinbaseOnRamp) },
)
)
}
if (state.hasReserves && metadata.showReserves) {
val minimumAmountNeeded = metadata.purchaseAmount ?: Fiat.MIN_VALUE
if (state.reservesBalance.nativeAmount >= minimumAmountNeeded) {
add(
cardAction(
title = resources.getString(R.string.label_cashReserves),
subtitle = state.reservesBalance.formatted(),
iconRes = R.drawable.ic_wallet,
testTag = "purchase_method_reserves",
onClick = { onClick(PurchaseMethod.CashReserves(state.reservesBalance)) },
)
)
}
}
add(
cardAction(
title = resources.getString(R.string.label_phantom),
subtitle = resources.getString(R.string.subtitle_depositPhantom),
iconRes = R.drawable.ic_phantom_wallet,
testTag = "purchase_method_phantom",
onClick = { onClick(PurchaseMethod.PhantomWallet) },
)
)
if (state.canUseOtherWallets) {
add(
cardAction(
title = resources.getString(R.string.title_onrampProviderOtherWallet),
subtitle = resources.getString(R.string.subtitle_depositOtherWallet),
iconRes = R.drawable.ic_qr_code,
testTag = "purchase_method_other_wallet",
onClick = { onClick(PurchaseMethod.OtherWallet) },
)
)
}
add(
BottomBarAction(
text = resources.getString(R.string.action_dismiss),
style = BottomBarManager.BottomBarButtonStyle.Text,
)
)
}

private fun cardAction(
title: String,
subtitle: String,
iconRes: Int,
tintIcon: Boolean = true,
testTag: String? = null,
onClick: () -> Unit,
): BottomBarAction = BottomBarAction(
text = AnnotatedString(title),
inlineContentMap = emptyMap(),
testTag = testTag,
onClick = onClick,
content = {
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
Text(
text = title,
style = CodeTheme.typography.textMedium,
color = Color.White,
)
Text(
text = subtitle,
style = CodeTheme.typography.textSmall,
color = CodeTheme.colors.textSecondary,
)
}
if (tintIcon) {
// Monochrome glyph (phantom, QR, reserves) — tint white and size square.
Icon(
modifier = Modifier.size(32.dp),
painter = painterResource(iconRes),
tint = Color.White,
contentDescription = null,
)
} else {
// Brand mark (Google Pay) — keep its own colours; constrain height, let width wrap.
Image(
modifier = Modifier.height(28.dp),
painter = painterResource(iconRes),
contentDescription = null,
)
}
},
)

private fun buildButtonAction(
prefix: String?,
suffix: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import com.flipcash.app.analytics.FlipcashAnalyticsService
import com.flipcash.app.core.AppRoute
import com.flipcash.app.core.tokens.FundingSource
import com.flipcash.app.core.tokens.SwapPurpose
import com.flipcash.app.featureflags.FeatureFlag
import com.flipcash.app.featureflags.FeatureFlagController
import com.flipcash.app.funding.PaymentAction
import com.flipcash.app.funding.PurchaseMethod
import com.flipcash.app.funding.PurchaseMethodController
Expand Down Expand Up @@ -54,6 +56,7 @@ class InternalPurchaseMethodController @Inject constructor(
private val resources: ResourceHelper,
private val userManager: UserManager,
private val analytics: FlipcashAnalyticsService,
private val featureFlags: FeatureFlagController,
) : PurchaseMethodController {

private val scope = CoroutineScope(SupervisorJob())
Expand Down Expand Up @@ -104,14 +107,17 @@ class InternalPurchaseMethodController @Inject constructor(

var selected = false

val title = when (metadata.purpose) {
val isNewUi = featureFlags.observe(FeatureFlag.NewUi).value
val title = if (isNewUi) {
resources.getString(R.string.prompt_title_addMoneyWith)
} else when (metadata.purpose) {
PurchasePurpose.Buy -> resources.getString(R.string.prompt_title_selectPurchaseMethod)
PurchasePurpose.Deposit -> resources.getString(R.string.prompt_title_selectMethod)
}

BottomBarManager.showMessage(
title = title,
actions = purchaseOptions(_state.value, metadata, resources) { method ->
actions = purchaseOptions(_state.value, metadata, resources, isNewUi) { method ->
selected = true
scope.launch {
val selection = PurchaseMethodSelection(method, metadata)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.getcode.manager

import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.AnnotatedString
import kotlinx.coroutines.flow.*
import java.util.*
Expand All @@ -14,6 +16,10 @@ data class BottomBarAction(
val enabled: Boolean = true,
// Optional UI-test anchor; surfaced as a resource-id when testTagsAsResourceId is on.
val testTag: String? = null,
// Optional custom body. When set, the renderer draws this inside a content-slot button (its own
// background/ripple/click) instead of the default centered text button — e.g. the v2 add-money
// method cards (title + subtitle + trailing icon).
val content: (@Composable RowScope.() -> Unit)? = null,
val onClick: () -> Unit = { }
) {
constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.ui.draw.clip
import com.getcode.theme.White10

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
Expand Down Expand Up @@ -304,6 +306,31 @@ fun BottomBarView(
}

actions.fastForEachIndexed { index, action ->
val actionContent = action.content
if (actionContent != null) {
// v2 card row: title + subtitle + trailing icon on its own surface, spread
// full-width. (A content-slot CodeButton centres and shrinks its body, so it
// can't lay a left title against a right-edge icon.)
Row(
modifier = Modifier
.fillMaxWidth()
.addIf(action.testTag != null) {
Modifier.testTag(action.testTag!!)
}
.clip(CodeTheme.shapes.medium)
.background(White10)
.clickable(enabled = action.enabled) {
action.onClick()
onClose(SelectedBottomBarAction(index.takeIf { action.isUser } ?: -1))
}
.padding(CodeTheme.dimens.grid.x3),
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x2),
verticalAlignment = Alignment.CenterVertically,
) {
actionContent()
}
return@fastForEachIndexed
}
CodeButton(
modifier = Modifier
.fillMaxWidth()
Expand Down
Loading