Skip to content

Commit 5bf014c

Browse files
committed
refactor(activity): simplify transaction row titles
Walk back the client-side title embellishments for buy/sell/deposit rows: Purchased, Sold and Added now render the server text verbatim instead of appending the token name or overriding USDF buys to "Added Money". Received tips read "Tip from <name>"; the label lives in strings.xml (title_activity_tipFrom) and is resolved through an injected ResourceHelper rather than a hardcoded literal.
1 parent 5c62554 commit 5bf014c

4 files changed

Lines changed: 33 additions & 37 deletions

File tree

‎apps/flipcash/shared/transaction-history/build.gradle.kts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ dependencies {
2121
implementation(project(":libs:datetime"))
2222

2323
testImplementation(libs.bundles.unit.testing)
24+
testImplementation(testFixtures(project(":ui:resources")))
2425
}

‎apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt‎

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import com.flipcash.app.core.feed.ActivityFeedMessageWithToken
44
import com.flipcash.app.core.feed.MessageMetadata
55
import com.flipcash.app.core.feed.MessageSubstitution
66
import com.flipcash.services.models.UserProfile
7+
import com.flipcash.shared.transactionhistory.R
78
import com.flipcash.shared.transactionhistory.TransactionAvatar
89
import com.flipcash.shared.transactionhistory.TransactionListItem
910
import com.getcode.opencode.mapper.Mapper
1011
import com.getcode.opencode.model.core.ID
11-
import com.getcode.opencode.model.financial.Token
12-
import com.getcode.solana.keys.Mint
12+
import com.getcode.util.resources.ResourceHelper
1313
import com.getcode.utils.hexEncodedString
1414
import javax.inject.Inject
1515

@@ -19,7 +19,9 @@ import javax.inject.Inject
1919
* inside the paging transform; profiles arrive reactively as the cache is observed, so a
2020
* not-yet-cached counterparty simply resolves later when its profile lands.
2121
*/
22-
internal class TransactionItemMapper @Inject constructor(): Mapper<Pair<ActivityFeedMessageWithToken, Map<String, UserProfile>>, TransactionListItem> {
22+
internal class TransactionItemMapper @Inject constructor(
23+
private val resources: ResourceHelper,
24+
): Mapper<Pair<ActivityFeedMessageWithToken, Map<String, UserProfile>>, TransactionListItem> {
2325
override fun map(from: Pair<ActivityFeedMessageWithToken, Map<String, UserProfile>>): TransactionListItem {
2426
val (source, profiles) = from
2527
val msg = source.message
@@ -45,7 +47,7 @@ internal class TransactionItemMapper @Inject constructor(): Mapper<Pair<Activity
4547
// row to the literal key "null". Duplicate keys wedge the LazyColumn under the app's
4648
// SharedTransitionLayout lookahead (whole-app freeze as a duplicate-keyed row scrolls in).
4749
id = msg.id.hexEncodedString(),
48-
title = resolveTitle(meta, msg.text, msg.textSubstitutions, counterparty, token, profiles),
50+
title = resolveTitle(resources, meta, msg.text, msg.textSubstitutions, counterparty, profiles),
4951
timestamp = msg.timestamp,
5052
avatar = avatar,
5153
signedAmountPrefix = prefix,
@@ -62,18 +64,20 @@ internal class TransactionItemMapper @Inject constructor(): Mapper<Pair<Activity
6264
* preferring the observed display name for `UserId` substitutions (server
6365
* [MessageSubstitution.fallback] otherwise).
6466
*
65-
* Otherwise the server sends a bare verb (e.g. "Tipped", "Purchased", "Received") and the client
66-
* completes it with the relevant subject, resolved reactively (the bare verb shows until it lands):
67-
* - buys/sells append the **token** name — "Purchased Dad Cash", "Sold Dad Cash";
68-
* - received tips read "Received Tip From <name>";
67+
* Otherwise the server sends a bare verb (e.g. "Tipped", "Received") and the client completes it
68+
* with the relevant subject, resolved reactively (the bare verb shows until it lands):
69+
* - received tips read "Tip from <name>";
6970
* - tips/sends and anything else with a counterparty append the **counterparty** name — "Tipped Sally".
71+
*
72+
* Buys/sells/deposits carry no counterparty, so they render the server text verbatim
73+
* ("Purchased", "Sold", "Added").
7074
*/
7175
private fun resolveTitle(
76+
resources: ResourceHelper,
7277
meta: MessageMetadata?,
7378
text: String,
7479
substitutions: List<MessageSubstitution>,
7580
counterparty: UserProfile?,
76-
token: Token?,
7781
profiles: Map<String, UserProfile>,
7882
): String {
7983
if (substitutions.isNotEmpty()) {
@@ -91,17 +95,9 @@ private fun resolveTitle(
9195
}
9296

9397
val counterpartyName = counterparty?.displayName?.takeIf { it.isNotBlank() }
94-
val tokenName = token?.name?.takeIf { it.isNotBlank() } ?: token?.symbol?.takeIf { it.isNotBlank() }
9598
return when (meta) {
9699
is MessageMetadata.ReceivedCrypto ->
97-
if (counterpartyName != null) "$text Tip From $counterpartyName" else text
98-
MessageMetadata.BoughtToken ->
99-
// Buying dollars (USDF — the only buyable stablecoin) is just adding money — read it as
100-
// such, not "Purchased Dollars".
101-
if (token?.address == Mint.usdf) "Added Money"
102-
else if (tokenName != null) "$text $tokenName" else text
103-
MessageMetadata.SoldToken ->
104-
if (tokenName != null) "$text $tokenName" else text
100+
if (counterpartyName != null) resources.getString(R.string.title_activity_tipFrom, counterpartyName) else text
105101
else ->
106102
if (counterpartyName != null) "$text $counterpartyName" else text
107103
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
<!-- Activity feed row title for a received tip; %1$s is the sender's display name. -->
4+
<string name="title_activity_tipFrom">Tip from %1$s</string>
5+
</resources>

‎apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt‎

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.flipcash.app.core.feed.MessageSubstitution
88
import com.flipcash.services.models.UserProfile
99
import com.flipcash.shared.transactionhistory.internal.TransactionItemMapper
1010
import com.getcode.opencode.model.core.ID
11+
import com.getcode.util.resources.FakeResourceHelper
1112
import com.getcode.opencode.model.financial.CurrencyCode
1213
import com.getcode.opencode.model.financial.Fiat
1314
import com.getcode.opencode.model.financial.HolderMetrics
@@ -24,7 +25,9 @@ import org.junit.Test
2425

2526
class TransactionItemMapperTest {
2627

27-
private val mapper = TransactionItemMapper()
28+
private val resources = FakeResourceHelper()
29+
.stub(R.string.title_activity_tipFrom, "Tip from %1\$s")
30+
private val mapper = TransactionItemMapper(resources)
2831

2932
private val knownUserId: ID = listOf<Byte>(0x0A, 0x0B, 0x0C)
3033
private val knownProfile = UserProfile.Empty.copy(displayName = "Sally The Streamer")
@@ -112,50 +115,41 @@ class TransactionItemMapperTest {
112115
}
113116

114117
@Test
115-
fun `received tip reads Received Tip From the counterparty`() {
118+
fun `received tip reads Tip from the counterparty`() {
116119
val msg = feedMessage(metadata = MessageMetadata.ReceivedCrypto(userId = knownUserId))
117120
.copy(text = "Received", textSubstitutions = emptyList())
118121
val item = mapper.map(ActivityFeedMessageWithToken(msg, token = null) to cached)
119122

120-
assertEquals("Received Tip From Sally The Streamer", item.title)
123+
assertEquals("Tip from Sally The Streamer", item.title)
121124
}
122125

123126
@Test
124-
fun `bought token appends the token name`() {
127+
fun `bought token renders the server text verbatim`() {
125128
val token = token(address = Mint.usdc, name = "Dad Cash", symbol = "DADCASH")
126129
val msg = feedMessage(metadata = MessageMetadata.BoughtToken)
127130
.copy(text = "Purchased", textSubstitutions = emptyList())
128131
val item = mapper.map(ActivityFeedMessageWithToken(msg, token) to emptyMap())
129132

130-
assertEquals("Purchased Dad Cash", item.title)
133+
assertEquals("Purchased", item.title)
131134
}
132135

133136
@Test
134-
fun `bought dollars reads Added Money instead of Purchased Dollars`() {
137+
fun `bought dollars renders the server text verbatim`() {
135138
val msg = feedMessage(metadata = MessageMetadata.BoughtToken)
136-
.copy(text = "Purchased", textSubstitutions = emptyList())
139+
.copy(text = "Added", textSubstitutions = emptyList())
137140
val item = mapper.map(ActivityFeedMessageWithToken(msg, usdfToken()) to emptyMap())
138141

139-
assertEquals("Added Money", item.title)
142+
assertEquals("Added", item.title)
140143
}
141144

142145
@Test
143-
fun `sold token appends the token name`() {
146+
fun `sold token renders the server text verbatim`() {
144147
val token = token(address = Mint.usdc, name = "Dad Cash", symbol = "DADCASH")
145148
val msg = feedMessage(metadata = MessageMetadata.SoldToken)
146149
.copy(text = "Sold", textSubstitutions = emptyList())
147150
val item = mapper.map(ActivityFeedMessageWithToken(msg, token) to emptyMap())
148151

149-
assertEquals("Sold Dad Cash", item.title)
150-
}
151-
152-
@Test
153-
fun `bought token stays bare until token metadata resolves`() {
154-
val msg = feedMessage(metadata = MessageMetadata.BoughtToken)
155-
.copy(text = "Purchased", textSubstitutions = emptyList())
156-
val item = mapper.map(ActivityFeedMessageWithToken(msg, token = null) to emptyMap())
157-
158-
assertEquals("Purchased", item.title)
152+
assertEquals("Sold", item.title)
159153
}
160154

161155
@Test

0 commit comments

Comments
 (0)