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
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 @@ -797,4 +797,8 @@
<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="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>

</resources>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package com.flipcash.app.directsend.internal

import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.snapshotFlow
Expand Down Expand Up @@ -99,7 +100,8 @@ internal class SendFlowViewModel @Inject constructor(
val phoneNumberSendEnabled = phoneNumberSendFlag ||
userState.flags?.enablePhoneNumberSend == true
val hasContacts = contactState.contacts.isNotEmpty()
val needsContacts = phoneNumberSendEnabled && !hasContacts && !contactState.hasEverSynced
val needsContacts =
phoneNumberSendEnabled && !hasContacts && !contactState.hasEverSynced

val steps = buildList {
if (!hasLinkedPhone) add(SendStep.PhoneGate)
Expand Down Expand Up @@ -263,7 +265,8 @@ internal class SendFlowViewModel @Inject constructor(
val contact = if (deviceContact != null) {
if (searchString.isNotBlank() &&
!deviceContact.displayName.contains(searchString, ignoreCase = true) &&
!deviceContact.e164.contains(searchString, ignoreCase = true)) {
!deviceContact.e164.contains(searchString, ignoreCase = true)
) {
return@mapNotNull null
}
recentsE164s += deviceContact.e164
Expand All @@ -287,7 +290,8 @@ internal class SendFlowViewModel @Inject constructor(
displayNumber = formattedPhone,
)
if (searchString.isNotBlank() &&
!unknown.displayName.contains(searchString, ignoreCase = true)) {
!unknown.displayName.contains(searchString, ignoreCase = true)
) {
return@mapNotNull null
}
if (unknown.e164.isNotEmpty()) {
Expand Down Expand Up @@ -346,11 +350,17 @@ internal class SendFlowViewModel @Inject constructor(
is MessageContent.Text -> content.text.takeIf { it.isNotEmpty() }
is MessageContent.Cash -> {
val formatted = content.amount.formatted()
val name = content.tokenName.ifBlank {
tokensByMint[content.mint]?.name.orEmpty()
val name = content.tokenName.ifBlank { tokensByMint[content.mint]?.name.orEmpty() }
val label = if (name.isNotBlank()) {
resources.getString(R.string.label_chat_preview_cash_suffix, formatted, name)
} else {
formatted
}
if (sentBySelf) {
resources.getString(R.string.label_chat_preview_sentCash, label)
} else {
resources.getString(R.string.label_chat_preview_receivedCash, label)
}
val label = if (name.isNotBlank()) "$formatted of $name" else formatted
if (sentBySelf) "You sent $label" else "You received $label"
}

// TODO:
Expand All @@ -368,9 +378,11 @@ internal class SendFlowViewModel @Inject constructor(
is Event.StepsUpdated -> { state ->
state.copy(steps = event.steps, isPickerMode = event.isPickerMode)
}

is Event.OnStepChanged -> { state ->
state.copy(currentStep = event.step)
}

is Event.ContactsGranted -> { state -> state }
is Event.ContactsPicked -> { state -> state }
is Event.ContactSyncStateUpdated -> { state ->
Expand All @@ -382,6 +394,7 @@ internal class SendFlowViewModel @Inject constructor(
)
)
}

is Event.ContactRemoved -> { state -> state }
is Event.ContactSyncComplete -> { state -> state }
is Event.OnItemsPopulated -> { state -> state.copy(listItems = event.items) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ class EventStreamDelegate @Inject constructor(
val latest = delta.messages.maxByOrNull { it.messageId }
latest?.let { msg ->
metadataDataSource.updateLastMessageId(chatId, msg.messageId)
metadataDataSource.updateLastActivity(chatId, msg.timestamp.toEpochMilliseconds())
// Only advance lastActivity — a partial page from a
// delta sync must not regress it to an older timestamp.
val existing = metadataDataSource.getLastActivity(chatId)
val incoming = msg.timestamp.toEpochMilliseconds()
if (existing == null || incoming > existing) {
metadataDataSource.updateLastActivity(chatId, incoming)
}
}
}
if (delta.latestSequence > afterSequence) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.flipcash.app.onramp
import com.coinbase.onramp.api.CoinbaseApi
import com.coinbase.onramp.data.OnRampApiConfig
import com.flipcash.app.featureflags.FeatureFlagController
import com.flipcash.app.userflags.UserFlagsCoordinator
import com.flipcash.services.models.UserProfile
import com.flipcash.services.user.UserManager
import com.getcode.opencode.exchange.Exchange
Expand Down Expand Up @@ -47,6 +48,7 @@ class CoinbaseOnRampControllerTest {
private val featureFlags = mockk<FeatureFlagController>(relaxed = true)
private val googlePayReadiness = mockk<GooglePayReadiness>(relaxed = true)
private val webViewChannelDetector = mockk<WebViewChannelDetector>(relaxed = true)
private val userFlags = mockk<UserFlagsCoordinator>(relaxed = true)

private val onRampApiEndpoint = OnRampApiConfig(
scheme = "https",
Expand Down Expand Up @@ -86,6 +88,7 @@ class CoinbaseOnRampControllerTest {
transactionController = mockk(relaxed = true),
googlePayReadiness = googlePayReadiness,
webViewChannelDetector = webViewChannelDetector,
userFlags = userFlags,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ interface ChatMetadataDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun upsert(entities: List<ChatMetadataEntity>)

@Query("SELECT last_activity_epoch_ms FROM chat_metadata WHERE chat_id_hex = :chatIdHex")
suspend fun getLastActivity(chatIdHex: String): Long?

@Query("UPDATE chat_metadata SET last_activity_epoch_ms = :epochMs WHERE chat_id_hex = :chatIdHex")
suspend fun updateLastActivity(chatIdHex: String, epochMs: Long)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class ChatMetadataDataSource @Inject constructor(
db?.chatMetadataDao()?.upsert(metadatas.map { mapper.toEntity(it) })
}

suspend fun getLastActivity(chatId: ChatId): Long? =
db?.chatMetadataDao()?.getLastActivity(mapper.chatIdHex(chatId))

suspend fun updateLastActivity(chatId: ChatId, epochMs: Long) {
db?.chatMetadataDao()?.updateLastActivity(mapper.chatIdHex(chatId), epochMs)
}
Expand Down
Loading