Skip to content

Commit 0258378

Browse files
committed
feat: add support for multi-mint cash links
Signed-off-by: Brandon McAnsh <[email protected]>
1 parent 819aa10 commit 0258378

File tree

82 files changed

+1251
-469
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+1251
-469
lines changed

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/bill/BillState.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import androidx.compose.ui.res.stringResource
77
import com.flipcash.core.R
88
import com.getcode.opencode.model.financial.Fiat
99
import com.getcode.opencode.model.financial.LocalFiat
10+
import com.getcode.opencode.model.financial.Token
11+
import com.getcode.solana.keys.Mint
1012
import kotlin.time.Duration
1113

1214
data class BillState(
@@ -85,6 +87,7 @@ data class BillState(
8587
sealed interface Bill {
8688
val didReceive: Boolean
8789
val confirmationDelay: Duration
90+
val token: Token
8891
val amount: LocalFiat
8992
val data: List<Byte>
9093

@@ -103,13 +106,15 @@ sealed interface Bill {
103106
get() {
104107
return when (this) {
105108
is Cash -> Metadata(
109+
token = token,
106110
amount = amount,
107111
data = data
108112
)
109113
}
110114
}
111115

112116
data class Cash(
117+
override val token: Token,
113118
override val amount: LocalFiat,
114119
override val didReceive: Boolean = false,
115120
override val confirmationDelay: Duration = Duration.ZERO,
@@ -135,6 +140,7 @@ data class BillToast(
135140
}
136141

137142
data class Metadata(
143+
val token: Token,
138144
val amount: LocalFiat,
139145
val data: List<Byte>,
140146
val request: DeepLinkRequest? = null

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/feed/ActivityFeedMessage.kt

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

33
import com.flipcash.app.core.pools.PoolResolution
4-
import com.flipcash.services.models.NetworkPoolResolution
54
import com.getcode.opencode.model.core.ID
65
import com.getcode.opencode.model.financial.LocalFiat
76
import com.getcode.solana.keys.PublicKey
@@ -24,7 +23,7 @@ data class ActivityFeedMessage(
2423
get() {
2524
metadata ?: return false
2625
val metadata =
27-
(metadata as? MessageMetadata.SentUsdc) ?: return false
26+
(metadata as? MessageMetadata.SentCrypto) ?: return false
2827
return metadata.canCancel
2928
}
3029
}
@@ -52,30 +51,30 @@ sealed interface MessageMetadata {
5251
data object WelcomeBonus : MessageMetadata
5352

5453
@Serializable
55-
data object GaveUsdc : MessageMetadata
54+
data object GaveCrypto : MessageMetadata
5655

5756
@Serializable
58-
data class SentUsdc(
57+
data class SentCrypto(
5958
val creator: PublicKey,
6059
val canCancel: Boolean,
6160
) : MessageMetadata
6261

6362
@Serializable
64-
data object ReceivedUsdc : MessageMetadata
63+
data object ReceivedCrypto : MessageMetadata
6564

6665
@Serializable
67-
data object WithdrewUsdc : MessageMetadata
66+
data object WithdrewCrypto : MessageMetadata
6867

6968
@Serializable
70-
data object DepositedUsdc : MessageMetadata
69+
data object DepositedCrypto : MessageMetadata
7170

7271
@Serializable
73-
data class PaidUsdc(
72+
data class PaidCrypto(
7473
val poolId: ID,
7574
): MessageMetadata
7675

7776
@Serializable
78-
data class DistributedUsdc(
77+
data class DistributedCrypto(
7978
val poolId: ID,
8079
val outcome: PoolResolution,
8180
): MessageMetadata

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/bill/BillController.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import com.getcode.opencode.managers.BillTransactionManager
66
import com.getcode.opencode.model.accounts.GiftCardAccount
77
import com.getcode.opencode.model.core.OpenCodePayload
88
import com.getcode.opencode.model.financial.LocalFiat
9+
import com.getcode.opencode.model.financial.Token
10+
import com.getcode.solana.keys.Mint
911
import kotlinx.coroutines.flow.MutableStateFlow
1012
import kotlinx.coroutines.flow.StateFlow
1113
import kotlinx.coroutines.flow.update
@@ -33,35 +35,37 @@ class BillController @Inject constructor(
3335

3436
fun awaitGrab(
3537
amount: LocalFiat,
38+
token: Token,
3639
owner: AccountCluster,
3740
present: (List<Byte>) -> Unit,
3841
onGrabbed: () -> Unit,
3942
onTimeout: () -> Unit,
4043
onError: (Throwable) -> Unit,
41-
) = transactionManager.awaitGrabFromRecipient(amount, owner, present, onGrabbed, onTimeout, onError)
44+
) = transactionManager.awaitGrabFromRecipient(token, amount, owner, present, onGrabbed, onTimeout, onError)
4245

4346
fun cancelAwaitForGrab() = transactionManager.cancelAwaitForGrab()
4447

4548
fun attemptGrab(
4649
owner: AccountCluster,
4750
payload: OpenCodePayload,
48-
onGrabbed: (LocalFiat) -> Unit,
51+
onGrabbed: (Token, LocalFiat) -> Unit,
4952
onError: (Throwable) -> Unit,
5053
) = transactionManager.attemptGrabFromSender(owner, payload, onGrabbed, onError)
5154

5255
fun fundGiftCard(
5356
giftCard: GiftCardAccount,
5457
amount: LocalFiat,
58+
token: Token,
5559
owner: AccountCluster,
5660
onFunded: (LocalFiat) -> Unit,
5761
onError: (Throwable) -> Unit,
58-
) = transactionManager.fundGiftCard(giftCard, amount, owner, onFunded, onError)
62+
) = transactionManager.fundGiftCard(giftCard, amount, owner, token, onFunded, onError)
5963

6064
fun receiveGiftCard(
6165
entropy: String,
6266
owner: AccountCluster,
6367
claimIfOwned: Boolean,
64-
onReceived: (LocalFiat) -> Unit,
68+
onReceived: (Token, LocalFiat) -> Unit,
6569
onError: (Throwable) -> Unit,
6670
) = transactionManager.receiveGiftCard(owner, entropy, claimIfOwned, onReceived, onError)
6771
}

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/money/FormatUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,5 @@ fun Int.withCommas(): String {
4141
}
4242

4343
fun LocalFiat.formatted(formatting: Fiat.Formatting = Fiat.Formatting.None, suffix: String? = null): String {
44-
return converted.formatted(formatting = formatting, suffix = suffix)
44+
return nativeAmount.formatted(formatting = formatting, suffix = suffix)
4545
}

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

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,16 @@ import androidx.compose.foundation.layout.Arrangement
55
import androidx.compose.foundation.layout.Row
66
import androidx.compose.foundation.layout.Spacer
77
import androidx.compose.foundation.layout.padding
8-
import androidx.compose.foundation.layout.size
9-
import androidx.compose.foundation.shape.CircleShape
108
import androidx.compose.material.Text
119
import androidx.compose.runtime.Composable
1210
import androidx.compose.ui.Alignment
1311
import androidx.compose.ui.Modifier
14-
import androidx.compose.ui.draw.clip
15-
import coil3.compose.AsyncImage
16-
import coil3.compose.LocalPlatformContext
17-
import coil3.request.ImageRequest
18-
import coil3.request.error
12+
import androidx.compose.ui.unit.dp
1913
import com.getcode.opencode.model.financial.Fiat
2014
import com.getcode.opencode.model.financial.Token
2115
import com.getcode.opencode.model.financial.TokenWithBalance
2216
import com.getcode.opencode.model.financial.TokenWithLocalizedBalance
2317
import com.getcode.theme.CodeTheme
24-
import com.getcode.ui.components.R
2518

2619
@Composable
2720
fun TokenBalanceRow(
@@ -32,7 +25,7 @@ fun TokenBalanceRow(
3225
val (token, balance) = tokenWithBalance
3326
TokenBalanceRow(
3427
token = token,
35-
balance = balance.converted,
28+
balance = balance.nativeAmount,
3629
modifier = modifier,
3730
onClick = onClick
3831
)
@@ -71,22 +64,12 @@ fun TokenBalanceRow(
7164
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x2),
7265
verticalAlignment = Alignment.CenterVertically,
7366
) {
74-
AsyncImage(
75-
modifier = Modifier
76-
.size(CodeTheme.dimens.staticGrid.x5)
77-
.clip(CircleShape),
78-
model = ImageRequest.Builder(LocalPlatformContext.current)
79-
.data(token.imageUrl)
80-
.error(R.drawable.ic_placeholder_user)
81-
.placeholderMemoryCacheKey(token.symbol)
82-
.build(),
83-
contentDescription = null,
84-
)
85-
86-
Text(
87-
text = token.name,
88-
style = CodeTheme.typography.screenTitle,
89-
color = CodeTheme.colors.textMain,
67+
TokenIconWithName(
68+
token = token,
69+
imageSize = CodeTheme.dimens.staticGrid.x6,
70+
textStyle = CodeTheme.typography.screenTitle,
71+
textColor = CodeTheme.colors.textMain,
72+
spacing = CodeTheme.dimens.grid.x2,
9073
)
9174

9275
Spacer(Modifier.weight(1f))
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.flipcash.app.core.ui
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Row
5+
import androidx.compose.foundation.layout.size
6+
import androidx.compose.foundation.shape.CircleShape
7+
import androidx.compose.material.Text
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.ui.Alignment
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.draw.clip
12+
import androidx.compose.ui.graphics.Color
13+
import androidx.compose.ui.text.TextStyle
14+
import androidx.compose.ui.unit.Dp
15+
import androidx.compose.ui.unit.dp
16+
import coil3.compose.AsyncImage
17+
import coil3.compose.LocalPlatformContext
18+
import coil3.request.ImageRequest
19+
import coil3.request.error
20+
import com.getcode.opencode.model.financial.Token
21+
import com.getcode.theme.CodeTheme
22+
import com.getcode.ui.components.R
23+
24+
@Composable
25+
fun TokenIconWithName(
26+
token: Token,
27+
imageSize: Dp,
28+
textStyle: TextStyle = CodeTheme.typography.screenTitle,
29+
textColor: Color = CodeTheme.colors.textMain,
30+
modifier: Modifier = Modifier,
31+
spacing: Dp = 0.dp,
32+
) {
33+
Row(
34+
modifier = modifier,
35+
horizontalArrangement = Arrangement.spacedBy(spacing),
36+
verticalAlignment = Alignment.CenterVertically
37+
) {
38+
TokenIcon(
39+
token = token,
40+
modifier = Modifier.size(imageSize)
41+
)
42+
Text(
43+
text = token.name,
44+
style = textStyle,
45+
color = textColor,
46+
)
47+
}
48+
}
49+
50+
@Composable
51+
fun TokenIcon(
52+
token: Token,
53+
modifier: Modifier
54+
) {
55+
AsyncImage(
56+
modifier = modifier.clip(CircleShape),
57+
model = ImageRequest.Builder(LocalPlatformContext.current)
58+
.data(token.imageUrl)
59+
.error(R.drawable.ic_placeholder_user)
60+
.placeholderMemoryCacheKey(token.symbol)
61+
.build(),
62+
contentDescription = null,
63+
)
64+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,4 +409,6 @@
409409
<string name="title_otherRegions">Other Regions</string>
410410
<string name="subtitle_searchRegions">Search regions</string>
411411
<string name="title_enterAmount">Enter Amount</string>
412+
413+
<string name="of">of</string>
412414
</resources>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ internal fun BalanceHeader(
3434
CodeCircularProgressIndicator()
3535
}
3636
} else {
37-
Crossfade(balance.converted) { amount ->
37+
Crossfade(balance.nativeAmount) { amount ->
3838
val captionText = stringResource(R.string.subtitle_currentValueOfAllCurrencies)
3939
AmountArea(
4040
amountText = amount.formatted(),

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.flipcash.app.balance.internal.components
22

33
import androidx.compose.animation.AnimatedContent
4-
import androidx.compose.animation.animateColorAsState
54
import androidx.compose.animation.core.animateDpAsState
65
import androidx.compose.animation.slideInVertically
76
import androidx.compose.animation.slideOutVertically
@@ -16,24 +15,19 @@ import androidx.compose.runtime.Composable
1615
import androidx.compose.runtime.CompositionLocalProvider
1716
import androidx.compose.runtime.getValue
1817
import androidx.compose.ui.Modifier
19-
import androidx.compose.ui.graphics.Color
20-
import androidx.compose.ui.graphics.compositeOver
2118
import androidx.compose.ui.platform.LocalContext
2219
import androidx.compose.ui.tooling.preview.Preview
2320
import androidx.compose.ui.unit.dp
24-
import com.flipcash.app.balance.internal.BalanceViewModel
2521
import com.flipcash.app.core.feed.ActivityFeedMessage
2622
import com.flipcash.app.core.feed.MessageMetadata
2723
import com.flipcash.app.core.feed.MessageState
2824
import com.flipcash.app.theme.FlipcashDesignSystem
29-
import com.getcode.ed25519.Ed25519
3025
import com.getcode.opencode.compose.ExchangeStub
3126
import com.getcode.opencode.compose.LocalExchange
3227
import com.getcode.opencode.model.financial.CurrencyCode
3328
import com.getcode.opencode.model.financial.LocalFiat
3429
import com.getcode.opencode.model.financial.Rate
3530
import com.getcode.opencode.model.financial.toFiat
36-
import com.getcode.solana.keys.PublicKey
3731
import com.getcode.theme.CodeTheme
3832
import com.getcode.utils.decodeBase58
3933
import kotlinx.datetime.Instant
@@ -97,15 +91,15 @@ val rates = mapOf(
9791
)
9892
private val oneDollarLocalized = LocalFiat(
9993
usdc = oneDollarCad.convertingTo(usdCadRate),
100-
converted = oneDollarCad,
94+
nativeAmount = oneDollarCad,
10195
)
10296
private val sampleItem = ActivityFeedMessage(
10397
id = "3GHjGey5F3fVProC3mYpiBpi7dCegFNz3wYtHSTiQnPt".decodeBase58().toList(),
10498
text = "Gave",
10599
amount = oneDollarLocalized,
106100
timestamp = Instant.parse("2025-06-03T16:25:00-04:00"),
107101
state = MessageState.COMPLETED,
108-
metadata = MessageMetadata.GaveUsdc
102+
metadata = MessageMetadata.GaveCrypto
109103
)
110104

111105
@Preview

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ internal fun FeedItemDetails(
7373
)
7474
DetailItem(
7575
label = "Currency",
76-
value = amount.converted.currencyCode.name,
76+
value = amount.nativeAmount.currencyCode.name,
7777
modifier = Modifier.weight(1f)
7878
)
7979
DetailItem(
8080
label = "USDC",
81-
value = amount.usdc.formatted(formatting = Fiat.Formatting.Length(6)),
81+
value = amount.underlyingTokenAmount.formatted(formatting = Fiat.Formatting.Length(6)),
8282
)
8383
}
8484
}

0 commit comments

Comments
 (0)