fix(wallet): replace text-marker hack with proper raw event API (room.sendRaw + MsgLikeKind.Other)
- Add Timeline.sendRaw() to send custom Matrix events - Add CustomEventContent type for receiving custom events - Update TimelineEventContentMapper to handle MsgLikeKind.Other - Update TimelineItemContentFactory to intercept payment events - Rewrite DefaultPaymentEventSender to use sendRaw instead of text markers - Update TimelineItemContentPaymentFactory to parse raw JSON - Remove text-marker detection from TimelineItemContentMessageFactory - Update tests to use raw event API - Mark raw event SDK blocker as RESOLVED in BLOCKERS.md Event type: co.sulkta.payment.request (reverse-domain format) Status updates: co.sulkta.payment.status Benefits: - Proper Matrix protocol compliance - No JSON embedded in text messages - Events won't be indexed by search - Clean separation from regular messages
This commit is contained in:
parent
adee67cf0d
commit
f2b95d6b8a
10 changed files with 264 additions and 189 deletions
|
|
@ -35,7 +35,9 @@ import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
|||
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.CustomEventContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
|
||||
import io.element.android.features.wallet.impl.timeline.TimelineItemContentPaymentFactory
|
||||
|
||||
@Inject
|
||||
class TimelineItemContentFactory(
|
||||
|
|
@ -49,9 +51,25 @@ class TimelineItemContentFactory(
|
|||
private val stateFactory: TimelineItemContentStateFactory,
|
||||
private val failedToParseMessageFactory: TimelineItemContentFailedToParseMessageFactory,
|
||||
private val failedToParseStateFactory: TimelineItemContentFailedToParseStateFactory,
|
||||
private val paymentFactory: TimelineItemContentPaymentFactory,
|
||||
private val sessionId: SessionId,
|
||||
) {
|
||||
suspend fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
|
||||
val isOutgoing = sessionId == eventTimelineItem.sender
|
||||
|
||||
// Check for custom event types that we handle specially
|
||||
val content = eventTimelineItem.content
|
||||
if (content is CustomEventContent && paymentFactory.isPaymentEventType(content.eventType)) {
|
||||
// Try to get raw JSON from debug info for payment events
|
||||
val rawJson = eventTimelineItem.timelineItemDebugInfoProvider().originalJson
|
||||
if (rawJson != null) {
|
||||
val paymentContent = paymentFactory.createFromRaw(rawJson, isOutgoing)
|
||||
if (paymentContent != null) {
|
||||
return paymentContent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return create(
|
||||
itemContent = eventTimelineItem.content,
|
||||
eventId = eventTimelineItem.eventId,
|
||||
|
|
@ -78,7 +96,6 @@ class TimelineItemContentFactory(
|
|||
senderProfile = senderProfile,
|
||||
content = itemContent,
|
||||
eventId = eventId,
|
||||
isSentByMe = isOutgoing,
|
||||
)
|
||||
}
|
||||
is ProfileChangeContent -> {
|
||||
|
|
@ -100,6 +117,10 @@ class TimelineItemContentFactory(
|
|||
is UnableToDecryptContent -> utdFactory.create(itemContent)
|
||||
is CallNotifyContent -> TimelineItemRtcNotificationContent()
|
||||
is UnknownContent -> TimelineItemUnknownContent
|
||||
is CustomEventContent -> {
|
||||
// Custom events that weren't handled above (e.g., unknown custom event types)
|
||||
TimelineItemUnknownContent
|
||||
}
|
||||
is LiveLocationContent -> {
|
||||
val lastKnownLocation = itemContent.locations.mapNotNull { beacon ->
|
||||
Location.fromGeoUri(beacon.geoUri)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
|||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||
import io.element.android.features.messages.impl.utils.TextPillificationHelper
|
||||
import io.element.android.features.wallet.impl.timeline.TimelineItemContentPaymentFactory
|
||||
|
||||
import io.element.android.libraries.androidutils.filesize.FileSizeFormatter
|
||||
import io.element.android.libraries.androidutils.text.safeLinkify
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
|
|
@ -66,14 +66,12 @@ class TimelineItemContentMessageFactory(
|
|||
private val htmlConverterProvider: HtmlConverterProvider,
|
||||
private val permalinkParser: PermalinkParser,
|
||||
private val textPillificationHelper: TextPillificationHelper,
|
||||
private val paymentFactory: TimelineItemContentPaymentFactory,
|
||||
) {
|
||||
fun create(
|
||||
content: MessageContent,
|
||||
senderId: UserId,
|
||||
senderProfile: ProfileDetails,
|
||||
eventId: EventId?,
|
||||
isSentByMe: Boolean = false,
|
||||
): TimelineItemEventContent {
|
||||
return when (val messageType = content.type) {
|
||||
is EmoteMessageType -> {
|
||||
|
|
@ -257,13 +255,7 @@ class TimelineItemContentMessageFactory(
|
|||
}
|
||||
is TextMessageType -> {
|
||||
val body = messageType.body.trimEnd()
|
||||
// Check for Cardano payment events embedded in text messages
|
||||
if (paymentFactory.isPaymentEvent(body)) {
|
||||
paymentFactory.createFromBody(body, isSentByMe)
|
||||
?: createTextContent(body, messageType, content.isEdited)
|
||||
} else {
|
||||
createTextContent(body, messageType, content.isEdited)
|
||||
}
|
||||
createTextContent(body, messageType, content.isEdited)
|
||||
}
|
||||
is OtherMessageType -> {
|
||||
val body = messageType.body.trimEnd()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue