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 @@ -47,6 +47,7 @@ data class TipSelectionState(
val canTip: Boolean = false,
/** Suggested tip presets in the sender's preferred currency; updates when the region changes. */
val presets: List<Fiat> = emptyList(),
val minimum: Fiat? = null,
) {
/** A positive amount is chosen and no submission is currently in flight. */
val canConfirm: Boolean get() = amount != null && sendState.isIdle
Expand Down
4 changes: 4 additions & 0 deletions apps/flipcash/core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,10 @@
<string name="prompt_title_cancelCashLinkPostShare">Are You Sure?</string>
<string name="prompt_description_cancelCashLinkPostShare">Anyone you sent the link to won\'t be able to collect the cash</string>

<string name="subtitle_youTipped">You tipped</string>
<string name="subtitle_youReceived">You received</string>
<string name="subtitle_youSent">You sent</string>
<string name="subtitle_youReceivedTip">You received a tip</string>
<string name="label_chat_preview_cash_suffix">%1$s of %2$s</string>
<string name="label_chat_preview_sentCash">You sent %1$s</string>
<string name="label_chat_preview_receivedCash">You received %1$s</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ internal data class TipCardDecorator(private val tipCard: Scannable.TipCard) : S
// the UI, so we route directly rather than plumbing a callback through the session.
LaunchedEffect(tipPresented, selection.canTip) {
if (tipPresented && !selection.canTip) {
session?.presentDepositOptions { route ->
navigator.openAsSheet(route)
session?.presentDepositOptions(
// No giveable balance to tip with → steer to add-money / discover, and dismiss the
// tip card so we don't leave it stranded behind the prompt.
context.onDismiss()
onDismiss = { context.onDismiss() }
) { route ->
navigator.openAsSheet(route)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ internal fun TipUserModal(
token = selection.token,
modifier = Modifier.fillMaxWidth(),
onSelectToken = {
val threshold = selection.amount?.value ?: selection.presets.firstOrNull()
navigator.openAsSheet(AppRoute.Sheets.TokenSelection(TokenPurpose.Tip(threshold)))
navigator.openAsSheet(AppRoute.Sheets.TokenSelection(TokenPurpose.Tip( selection.minimum)))
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ import com.getcode.opencode.model.financial.Fiat
import com.getcode.theme.CodeTheme
import com.getcode.ui.components.PriceWithFlag
import com.getcode.ui.core.addIf
import com.getcode.util.resources.R

enum class BubblePosition { Solo, First, Middle, Last }

Expand Down Expand Up @@ -212,7 +211,7 @@ private fun CashBubble(
) {
val subtitleRes = when (action) {
MessageContent.Cash.Action.TIPPED ->
if (isFromSelf) R.string.subtitle_youTipped else R.string.subtitle_someoneTippedYou
if (isFromSelf) R.string.subtitle_youTipped else R.string.subtitle_youReceivedTip
MessageContent.Cash.Action.SENT ->
if (isFromSelf) R.string.subtitle_youSent else R.string.subtitle_youReceived
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ interface DepositOperations {
* an add-money prompt when the wallet is empty, or a discover-currencies prompt when
* the user has funds (e.g. reserves) but nothing giveable.
*/
fun presentDepositOptions(onRoute: ((AppRoute) -> Unit)? = null)
fun presentDepositOptions(onDismiss: (() -> Unit)? = null, onRoute: ((AppRoute) -> Unit)? = null)
}

interface SessionController : BillOperations, CodeScanOperations, CashLinkOperations, DepositOperations, TipCardOperations {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,25 @@ class DepositDelegate @Inject constructor(
.launchIn(scope)
}

override fun presentDepositOptions(onRoute: ((AppRoute) -> Unit)?) {
override fun presentDepositOptions(onDismiss: (() -> Unit)?, onRoute: ((AppRoute) -> Unit)?) {
// Prompt to add money only when the wallet is empty and add-money is available.
// Otherwise the user has funds (e.g. reserves) but nothing giveable — or can't
// add money at all — so steer them to discover/buy a currency.
val addMoneyEnabled = stateHolder.current.addMoneyUx
val hasBalance = stateHolder.current.hasBalance

if (!hasBalance) {
presentAddMoney(addMoneyEnabled, onRoute)
presentAddMoney(addMoneyEnabled, onRoute, onDismiss)
} else {
presentDiscoverCurrencies(onRoute)
presentDiscoverCurrencies(onRoute, onDismiss)
}
}

private fun presentAddMoney(addMoneyEnabled: Boolean, onRoute: ((AppRoute) -> Unit)?) {
private fun presentAddMoney(
addMoneyEnabled: Boolean,
onRoute: ((AppRoute) -> Unit)?,
onDismiss: (() -> Unit)?
) {
BottomBarManager.showInfo(
title = resources.getString(R.string.title_noBalanceYet),
message = if (addMoneyEnabled) {
Expand All @@ -90,10 +94,11 @@ class DepositDelegate @Inject constructor(
},
),
showCancel = true,
onDismiss = { onDismiss?.invoke() }
)
}

private fun presentDiscoverCurrencies(onRoute: ((AppRoute) -> Unit)?) {
private fun presentDiscoverCurrencies(onRoute: ((AppRoute) -> Unit)?, onDismiss: (() -> Unit)?) {
BottomBarManager.showInfo(
title = resources.getString(R.string.title_noCommunityCurrenciesYet),
message = resources.getString(R.string.description_noCommunityCurrenciesYet),
Expand All @@ -105,6 +110,7 @@ class DepositDelegate @Inject constructor(
},
),
showCancel = true,
onDismiss = { onDismiss?.invoke() }
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.getcode.opencode.exchange.VerifiedFiatCalculator
import com.getcode.opencode.model.core.errors.ComputeVerifiedFiatError
import com.getcode.opencode.model.financial.Fiat
import com.getcode.opencode.model.financial.Token
import com.getcode.opencode.utils.combine
import com.getcode.util.resources.ResourceHelper
import com.getcode.view.LoadingSuccessState
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -101,16 +102,23 @@ class TippingCoordinator @Inject constructor(
tokenCoordinator.tokens.map { tokens -> tokens.find { it.address == mint } }
}

/** The largest tippable amount (send-limit ∧ balance), surfaced by the amount entry. */
val maxTipAmount: StateFlow<Fiat?> get() = tipPaymentDelegate.maxTipAmount

/** The smallest tippable amount (lowest preset tier), surfaced by the amount entry. */
val minTipAmount: StateFlow<Fiat?> get() = tipPaymentDelegate.minTipAmount

/** The combined tip selection (amount chosen in the modal + app-global token + send state). */
override val selection: StateFlow<TipSelectionState> =
combine(
combine(_amount, selectedToken, _sendState, _userId, _canTip) { amount, token, sendState, userId, canTip ->
combine(_amount, selectedToken, _sendState, _userId, _canTip, minTipAmount) { amount, token, sendState, userId, canTip, min ->
TipSelectionState(
amount = amount,
token = token,
sendState = sendState,
userId = userId,
canTip = canTip,
minimum = min
)
},
tipPaymentDelegate.tipPresets,
Expand All @@ -128,12 +136,6 @@ class TippingCoordinator @Inject constructor(
.launchIn(scope)
}

/** The largest tippable amount (send-limit ∧ balance), surfaced by the amount entry. */
val maxTipAmount: StateFlow<Fiat?> get() = tipPaymentDelegate.maxTipAmount

/** The smallest tippable amount (lowest preset tier), surfaced by the amount entry. */
val minTipAmount: StateFlow<Fiat?> get() = tipPaymentDelegate.minTipAmount

/** Whether [amount] exceeds the per-transaction send limit for its currency. */
fun exceedsSendLimit(amount: Fiat): Boolean = tipPaymentDelegate.exceedsSendLimit(amount)

Expand Down
Loading