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 @@ -52,7 +52,6 @@ class IntentPrivateTransferTest {
val rendezvous = PublicKey.generate()

val intent = IntentPrivateTransfer.newInstance(
context = context,
rendezvousKey = rendezvous,
organizer = organizer,
destination = destination,
Expand Down
10 changes: 8 additions & 2 deletions api/src/main/java/com/getcode/model/IntentMetadata.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sealed class IntentMetadata {
metadata.receivePaymentsPublicly.exchangeData.currency,
metadata.receivePaymentsPublicly.exchangeData.quarks,
metadata.receivePaymentsPublicly.exchangeData.exchangeRate,
metadata.sendPrivatePayment.isChat,
)?.let { ReceivePaymentsPublicly(it) }
}
TransactionService.Metadata.TypeCase.UPGRADE_PRIVACY -> UpgradePrivacy
Expand All @@ -30,13 +31,15 @@ sealed class IntentMetadata {
metadata.sendPrivatePayment.exchangeData.currency,
metadata.sendPrivatePayment.exchangeData.quarks,
metadata.sendPrivatePayment.exchangeData.exchangeRate,
metadata.sendPrivatePayment.isChat,
)?.let { SendPrivatePayment(it) }
}
TransactionService.Metadata.TypeCase.SEND_PUBLIC_PAYMENT -> {
getPaymentMetadata(
metadata.sendPublicPayment.exchangeData.currency,
metadata.sendPrivatePayment.exchangeData.quarks,
metadata.sendPublicPayment.exchangeData.exchangeRate,
metadata.sendPrivatePayment.isChat,
)?.let { SendPublicPayment(it) }
}
else -> null
Expand All @@ -47,6 +50,7 @@ sealed class IntentMetadata {
currencyString: String,
quarks: Long,
exchangeRate: Double,
isChat: Boolean,
): PaymentMetadata? {
val currency = CurrencyCode.tryValueOf(currencyString.uppercase())
?: return null
Expand All @@ -58,12 +62,14 @@ sealed class IntentMetadata {
fx = exchangeRate,
currency = currency
)
)
),
isChat = isChat,
)
}
}
}

data class PaymentMetadata(
val amount: KinAmount
val amount: KinAmount,
val isChat: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import com.getcode.utils.serializer.PublicKeyAsStringSerializer
import kotlinx.serialization.Serializable

@Serializable
sealed interface TipMetadata {
sealed interface SocialUser {
val platform: String
val username: String
@Serializable(with = PublicKeyAsStringSerializer::class)
val tipAddress: PublicKey
val imageUrl: String?

val imageUrlSanitized: String?

val costOfFriendship: Fiat
val isFriend: Boolean
val chatId: ID
}
24 changes: 12 additions & 12 deletions api/src/main/java/com/getcode/model/TwitterUser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@ package com.getcode.model

import android.webkit.MimeTypeMap
import com.codeinc.gen.user.v1.IdentityService
import com.codeinc.gen.user.v1.friendChatIdOrNull
import com.codeinc.gen.user.v1.friendshipCostOrNull
import com.getcode.solana.keys.PublicKey
import com.getcode.solana.keys.base58
import com.getcode.utils.serializer.PublicKeyAsStringSerializer
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

@Serializable
data class TwitterUser(
Expand All @@ -22,9 +17,10 @@ data class TwitterUser(
val displayName: String,
val followerCount: Int,
val verificationStatus: VerificationStatus,
val costOfFriendship: Fiat,
val isFriend: Boolean,
): TipMetadata {
override val costOfFriendship: Fiat,
override val isFriend: Boolean,
override val chatId: ID,
): SocialUser {

override val platform: String = "X"

Expand Down Expand Up @@ -55,8 +51,12 @@ data class TwitterUser(
followerCount = proto.followerCount,
tipAddress = tipAddress,
verificationStatus = VerificationStatus.entries.getOrNull(proto.verifiedTypeValue) ?: VerificationStatus.unknown,
costOfFriendship = Fiat(currency = CurrencyCode.USD, amount = 1.00),
isFriend = proto.isFriend
costOfFriendship = proto.friendshipCostOrNull?.let {
val currency = CurrencyCode.tryValueOf(it.currency) ?: return@let null
Fiat(currency, it.nativeAmount)
} ?: Fiat(currency = CurrencyCode.USD, amount = 1.00),
isFriend = proto.isFriend,
chatId = proto.friendChatId.value.toList()
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/java/com/getcode/model/chat/Chats.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ typealias ChatGrpcV1 = com.codeinc.gen.chat.v1.ChatGrpc
typealias ChatGrpcV2 = com.codeinc.gen.chat.v2.ChatGrpc

typealias ChatIdV1 = com.codeinc.gen.chat.v1.ChatService.ChatId
typealias ChatIdV2 = com.codeinc.gen.chat.v2.ChatService.ChatId
typealias ChatIdV2 = com.codeinc.gen.common.v1.Model.ChatId

typealias MessageContentV1 = com.codeinc.gen.chat.v1.ChatService.Content
typealias MessageContentV2 = com.codeinc.gen.chat.v2.ChatService.Content
Expand Down
6 changes: 5 additions & 1 deletion api/src/main/java/com/getcode/model/chat/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ enum class Platform {
}

fun named(name: String): Platform {
return entries.firstOrNull { it.name.lowercase() == name.lowercase() } ?: Unknown
val normalizedName = name.lowercase()
return entries.firstOrNull {
it.name.lowercase() == normalizedName ||
(normalizedName == "x" && it.name.lowercase() == "twitter")
} ?: Unknown
}
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
package com.getcode.model.intents

import android.content.Context
import com.codeinc.gen.chat.v2.ChatService
import com.codeinc.gen.transaction.v2.TransactionService
import com.codeinc.gen.transaction.v2.TransactionService.TippedUser.Platform
import com.getcode.model.TipMetadata
import com.getcode.model.Fee
import com.getcode.model.ID
import com.getcode.model.Kin
import com.getcode.model.KinAmount
import com.getcode.model.SocialUser
import com.getcode.model.chat.ChatIdV2
import com.getcode.model.chat.Platform
import com.getcode.model.intents.actions.ActionFeePayment
import com.getcode.model.intents.actions.ActionOpenAccount
import com.getcode.model.intents.actions.ActionTransfer
import com.getcode.model.intents.actions.ActionWithdraw
import com.getcode.network.repository.toByteString
import com.getcode.network.repository.toPublicKey
import com.getcode.network.repository.toSolanaAccount
import com.getcode.solana.keys.*
import com.getcode.solana.keys.PublicKey
import com.getcode.solana.organizer.AccountType
import com.getcode.solana.organizer.Organizer
import com.getcode.solana.organizer.Tray
import timber.log.Timber

sealed interface PrivateTransferMetadata {
data class Tip(val socialUser: SocialUser): PrivateTransferMetadata
data class Chat(val socialUser: SocialUser): PrivateTransferMetadata
}

class IntentPrivateTransfer(
override val id: PublicKey,
private val organizer: Organizer,
Expand All @@ -30,7 +38,7 @@ class IntentPrivateTransfer(
private val fee: Kin,
private val additionalFees: List<Fee>,
private val isWithdrawal: Boolean,
private val tipMetadata: TipMetadata?,
private val metadata: PrivateTransferMetadata?,
val resultTray: Tray,

override val actionGroup: ActionGroup,
Expand All @@ -49,12 +57,24 @@ class IntentPrivateTransfer(
.setNativeAmount(grossAmount.fiat)
)

if (tipMetadata != null) {
setIsTip(true)
setTippedUser(TransactionService.TippedUser.newBuilder()
.setPlatformValue(Platform.TWITTER_VALUE)
.setUsername(tipMetadata.username)
)
when (metadata) {
is PrivateTransferMetadata.Chat -> {
setIsChat(true)
setChatId(ChatIdV2.newBuilder()
.setValue(metadata.socialUser.chatId.toByteString())
)
}
is PrivateTransferMetadata.Tip -> {
setIsTip(true)
setTippedUser(TransactionService.TippedUser.newBuilder()
.setPlatformValue(when (Platform.named(metadata.socialUser.platform)) {
Platform.Unknown -> ChatService.Platform.UNKNOWN_PLATFORM_VALUE
Platform.Twitter -> ChatService.Platform.TWITTER_VALUE
})
.setUsername(metadata.socialUser.username)
)
}
null -> Unit
}
}
)
Expand All @@ -63,15 +83,14 @@ class IntentPrivateTransfer(

companion object {
fun newInstance(
context: Context,
rendezvousKey: PublicKey,
organizer: Organizer,
destination: PublicKey,
amount: KinAmount,
fee: Kin,
additionalFees: List<Fee>,
isWithdrawal: Boolean,
tipMetadata: TipMetadata?
metadata: PrivateTransferMetadata?,
): IntentPrivateTransfer {
if (fee > amount.kin) {
throw IntentPrivateTransferException.InvalidFeeException()
Expand Down Expand Up @@ -153,7 +172,7 @@ class IntentPrivateTransfer(
kind = ActionWithdraw.Kind.NoPrivacyWithdraw(netAmount.kin),
cluster = currentTray.outgoing.getCluster(),
destination = destination,
tipMetadata = tipMetadata
metadata = metadata
)

// 3. Redistribute the funds to optimize for a
Expand Down Expand Up @@ -217,7 +236,7 @@ class IntentPrivateTransfer(
fee = fee,
additionalFees = additionalFees,
isWithdrawal = isWithdrawal,
tipMetadata = tipMetadata,
metadata = metadata,
actionGroup = group,
resultTray = currentTray,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package com.getcode.model.intents.actions

import com.codeinc.gen.transaction.v2.TransactionService
import com.getcode.ed25519.Ed25519
import com.getcode.model.TipMetadata
import com.getcode.model.SocialUser
import com.getcode.model.Kin
import com.getcode.model.intents.PrivateTransferMetadata
import com.getcode.model.intents.ServerParameter
import com.getcode.network.repository.toPublicKey
import com.getcode.network.repository.toSolanaAccount
Expand All @@ -23,7 +24,7 @@ class ActionWithdraw(
val cluster: AccountCluster,
val destination: PublicKey,
val legacy: Boolean,
val tipMetadata: TipMetadata? = null,
val metadata: PrivateTransferMetadata? = null,
) : ActionType() {

override fun transactions(): List<SolanaTransaction> {
Expand All @@ -37,7 +38,7 @@ class ActionWithdraw(
recentBlockhash = config.blockhash,
kreIndex = kreIndex,
legacy = legacy,
tipMetadata = tipMetadata,
metadata = metadata,
)
}.orEmpty()
}
Expand Down Expand Up @@ -87,7 +88,7 @@ class ActionWithdraw(
cluster: AccountCluster,
destination: PublicKey,
legacy: Boolean = false,
tipMetadata: TipMetadata? = null,
metadata: PrivateTransferMetadata? = null,
): ActionWithdraw {
return ActionWithdraw(
id = 0,
Expand All @@ -97,7 +98,7 @@ class ActionWithdraw(
cluster = cluster,
destination = destination,
legacy = legacy,
tipMetadata = tipMetadata
metadata = metadata
)
}

Expand Down
17 changes: 12 additions & 5 deletions api/src/main/java/com/getcode/network/ChatHistoryController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.getcode.ed25519.Ed25519.KeyPair
import com.getcode.manager.SessionManager
import com.getcode.mapper.ConversationMapper
import com.getcode.mapper.ConversationMessageMapper
import com.getcode.model.Conversation
import com.getcode.model.chat.Chat
import com.getcode.model.chat.ChatMessage
import com.getcode.model.Cursor
Expand Down Expand Up @@ -156,6 +157,15 @@ class ChatHistoryController @Inject constructor(
chatEntries.value = updatedWithMessages.sortedByDescending { it.lastMessageMillis }
}

fun addChat(chat: Chat) {
chatEntries.value = (chatEntries.value.orEmpty() + chat)
.sortedByDescending { it.lastMessageMillis }
}

fun findChat(predicate: (Chat) -> Boolean): Chat? {
return chatEntries.value?.firstOrNull(predicate)
}

suspend fun advanceReadPointer(chatId: ID) {
val owner = owner() ?: return

Expand All @@ -181,17 +191,14 @@ class ChatHistoryController @Inject constructor(
}
}

fun advanceReadPointerUpTo(chatId: ID, timestamp: Long) {
fun resetUnreadCount(chatId: ID) {
chatEntries.update {
it?.toMutableList()?.apply chats@{
indexOfFirst { chat -> chat.id == chatId }
.takeIf { index -> index >= 0 }
?.let { index ->
val chat = this[index]
val newestMessage = chat.newestMessage
if (newestMessage != null) {
this[index] = chat.resetUnreadCount()
}
this[index] = chat.resetUnreadCount()
}
}?.toList()
}
Expand Down
Loading