Skip to content

Commit 39632f9

Browse files
committed
chore(fc): add deletedBy support for deleted messages
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent dabe9ae commit 39632f9

27 files changed

Lines changed: 598 additions & 141 deletions

File tree

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/conversation/ConversationItem.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable
44
import com.getcode.model.ID
55
import com.getcode.model.Kin
66
import com.getcode.model.KinAmount
7+
import com.getcode.model.chat.Deleter
78
import com.getcode.model.chat.MessageContent
89
import com.getcode.model.chat.Sender
910
import xyz.flipchat.services.domain.model.chat.ConversationMember

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/conversation/ConversationScreen.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import com.getcode.ui.components.OnLifecycleEvent
5858
import com.getcode.ui.components.chat.TypingIndicator
5959
import com.getcode.ui.components.chat.messagecontents.MessageReplyPreview
6060
import com.getcode.ui.components.chat.utils.ChatItem
61+
import com.getcode.ui.components.chat.utils.ReplyMessageAnchor
6162
import com.getcode.ui.theme.CodeScaffold
6263
import com.getcode.ui.utils.addIf
6364
import com.getcode.ui.utils.keyboardAsState
@@ -286,8 +287,13 @@ private fun ConversationScreenContent(
286287
) {
287288
MessageReplyPreview(
288289
modifier = Modifier.weight(1f),
289-
sender = replyingTo.sender,
290-
message = replyingTo.message
290+
originalMessage = ReplyMessageAnchor(
291+
id = replyingTo.id,
292+
sender = replyingTo.sender,
293+
message = replyingTo.message,
294+
isDeleted = false,
295+
deletedBy = null,
296+
),
291297
)
292298
Image(
293299
modifier = Modifier

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/conversation/ConversationViewModel.kt

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.getcode.manager.TopBarManager
1515
import com.getcode.model.ID
1616
import com.getcode.model.Kin
1717
import com.getcode.model.KinAmount
18+
import com.getcode.model.chat.Deleter
1819
import com.getcode.model.chat.MessageContent
1920
import com.getcode.model.chat.MessageStatus
2021
import com.getcode.model.chat.Sender
@@ -232,12 +233,12 @@ class ConversationViewModel @Inject constructor(
232233
.onEach { dispatchEvent(Event.OnStartAtUnread(it)) }
233234
.launchIn(viewModelScope)
234235

235-
eventFlow
236-
.filterIsInstance<Event.OnChatIdChanged>()
237-
.map { it.chatId }
238-
.filterNotNull()
239-
.onEach { roomController.getChatMembers(it) }
240-
.launchIn(viewModelScope)
236+
// eventFlow
237+
// .filterIsInstance<Event.OnChatIdChanged>()
238+
// .map { it.chatId }
239+
// .filterNotNull()
240+
// .onEach { roomController.getChatMembers(it) }
241+
// .launchIn(viewModelScope)
241242

242243
eventFlow
243244
.filterIsInstance<Event.OnChatIdChanged>()
@@ -281,7 +282,7 @@ class ConversationViewModel @Inject constructor(
281282
.distinctUntilChanged()
282283
.onEach {
283284
val (_, members, _) = it
284-
val selfMember = members.firstOrNull { it.id == userManager.userId }
285+
val selfMember = members.firstOrNull { userManager.isSelf(it.id) }
285286
val chattableState = if (selfMember != null) {
286287
val isMuted = selfMember.isMuted
287288
val isSpectator = !selfMember.isFullMember
@@ -679,23 +680,6 @@ class ConversationViewModel @Inject constructor(
679680
.filterNotNull()
680681
.distinctUntilChanged()
681682
.flatMapLatest { roomController.messages(it).flow }
682-
.map { page ->
683-
page.map { mwc ->
684-
if (mwc.message.isDeleted) {
685-
ConversationMessageIndice(
686-
mwc.message,
687-
mwc.member,
688-
MessageContent.RawText("", mwc.message.senderId == userManager.userId),
689-
)
690-
} else {
691-
ConversationMessageIndice(
692-
mwc.message,
693-
mwc.member,
694-
mwc.content
695-
)
696-
}
697-
}
698-
}
699683
.map { page ->
700684
val currentState = stateFlow.value // Cache state upfront
701685
val pointerRefs = currentState.pointerRefs // cache expensive pointer ref map upfront
@@ -712,19 +696,27 @@ class ConversationViewModel @Inject constructor(
712696

713697
val anchor = if (contents is MessageContent.Reply) {
714698
val originalMessage = roomController.getMessage(contents.originalMessageId)
715-
originalMessage?.let {
699+
originalMessage?.let { container ->
716700
ReplyMessageAnchor(
717701
id = contents.originalMessageId,
718-
message = it.content,
702+
message = container.content,
703+
isDeleted = container.message.isDeleted,
704+
deletedBy = container.message.deletedBy?.let { id ->
705+
Deleter(
706+
id = id,
707+
isSelf = userManager.isSelf(id),
708+
isHost = currentState.hostId == message.deletedBy
709+
)
710+
},
719711
sender = Sender(
720-
id = it.message.senderId,
721-
profileImage = it.member?.imageUri.takeIf {
712+
id = container.message.senderId,
713+
profileImage = container.member?.imageUri.takeIf {
722714
it.orEmpty().isNotEmpty()
723715
},
724-
displayName = it.member?.memberName ?: "Deleted",
725-
isSelf = it.content.isFromSelf,
726-
isBlocked = it.member?.isBlocked == true,
727-
isHost = it.message.senderId == currentState.hostId && !contents.isFromSelf,
716+
displayName = container.member?.memberName ?: "Deleted",
717+
isSelf = container.content.isFromSelf,
718+
isBlocked = container.member?.isBlocked == true,
719+
isHost = container.message.senderId == currentState.hostId && !contents.isFromSelf,
728720
)
729721
)
730722
}
@@ -738,6 +730,15 @@ class ConversationViewModel @Inject constructor(
738730
date = message.dateMillis.toInstantFromMillis(),
739731
status = status,
740732
isDeleted = message.isDeleted,
733+
deletedBy = if (message.isDeleted) {
734+
Deleter(
735+
id = message.deletedBy,
736+
isSelf = userManager.isSelf(message.deletedBy),
737+
isHost = currentState.hostId == message.deletedBy
738+
)
739+
} else {
740+
null
741+
},
741742
showAsChatBubble = true,
742743
enableMarkup = true,
743744
enableReply = enableReply,

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/conversation/MessageActionContextSheet.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ internal data class MessageActionContextSheet(val actions: List<MessageControlAc
4646
.fillMaxWidth()
4747
.padding(
4848
horizontal = CodeTheme.dimens.inset,
49-
vertical = CodeTheme.dimens.grid.x2
49+
vertical = CodeTheme.dimens.grid.x3
5050
),
5151
verticalAlignment = Alignment.CenterVertically,
5252
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x2)
@@ -88,7 +88,7 @@ internal data class MessageActionContextSheet(val actions: List<MessageControlAc
8888

8989
is MessageControlAction.Reply -> stringResource(R.string.action_reply)
9090
},
91-
style = CodeTheme.typography.textSmall.copy(
91+
style = CodeTheme.typography.textMedium.copy(
9292
color = if (action.isDestructive) CodeTheme.colors.errorText else CodeTheme.colors.textMain
9393
),
9494
modifier = Modifier.weight(1f)

libs/models/src/main/kotlin/com/getcode/model/chat/MessageContent.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,14 @@ sealed interface MessageContent {
306306
@Serializable
307307
data class DeletedMessage(
308308
val originalMessageId: ID,
309+
val messageDeleter: ID,
309310
override val isFromSelf: Boolean,
310311
) : MessageContent {
311312
override val kind: Int = 9
312313

313314
override fun hashCode(): Int {
314315
var result = originalMessageId.hashCode()
316+
result += messageDeleter.hashCode()
315317
result += isFromSelf.hashCode()
316318
result += kind.hashCode()
317319

@@ -325,6 +327,7 @@ sealed interface MessageContent {
325327
other as DeletedMessage
326328

327329
if (originalMessageId != other.originalMessageId) return false
330+
if (messageDeleter != other.messageDeleter) return false
328331
if (isFromSelf != other.isFromSelf) return false
329332
if (kind != other.kind) return false
330333

@@ -334,14 +337,15 @@ sealed interface MessageContent {
334337
@Serializable
335338
internal data class Content(
336339
val originalMessageId: ID,
340+
val messageDeleter: ID,
337341
)
338342

339343
@Transient
340-
override val content: String = Json.encodeToString(Content(originalMessageId))
344+
override val content: String = Json.encodeToString(Content(originalMessageId, messageDeleter))
341345
}
342346

343347
companion object {
344-
fun fromData(type: Int, content: String, isFromSelf: Boolean): MessageContent {
348+
fun fromData(type: Int, content: String, isFromSelf: Boolean): MessageContent? {
345349
return when (type) {
346350
0 -> Localized(content, isFromSelf)
347351
1 -> RawText(content, isFromSelf)
@@ -365,9 +369,9 @@ sealed interface MessageContent {
365369
}
366370
9 -> {
367371
val data = Json.decodeFromString<DeletedMessage.Content>(content)
368-
DeletedMessage(data.originalMessageId, isFromSelf)
372+
DeletedMessage(data.originalMessageId, data.messageDeleter, isFromSelf)
369373
}
370-
else -> throw IllegalArgumentException()
374+
else -> null
371375
}
372376
}
373377
}

libs/models/src/main/kotlin/com/getcode/model/chat/Sender.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ data class Sender(
1010
val isSelf: Boolean = false,
1111
val isBlocked: Boolean = false,
1212
)
13+
14+
data class Deleter(
15+
val id: ID? = null,
16+
val isHost: Boolean = false,
17+
val isSelf: Boolean = false,
18+
)

services/flipchat/chat/src/main/kotlin/xyz/flipchat/services/domain/mapper/ConversationMessageMapper.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ class ConversationMessageMapper @Inject constructor() :
1919
conversationIdBase58 = conversationId.base58,
2020
senderIdBase58 = message.senderId.base58,
2121
dateMillis = message.dateMillis,
22-
deleted = false, // TODO:
22+
// deletions happen as a by-product of a sent message with delete content type
23+
deleted = false,
24+
deletedByBase58 = null,
2325
type = content.kind,
2426
content = content.content
2527
)

services/flipchat/chat/src/main/kotlin/xyz/flipchat/services/domain/model/chat/ConversationMessage.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ data class ConversationMessage(
2929
val senderIdBase58: String,
3030
val dateMillis: Long,
3131
private val deleted: Boolean?,
32+
private val deletedByBase58: String? = null,
3233
@ColumnInfo(defaultValue = "1")
3334
val type: Int,
3435
@ColumnInfo(defaultValue = "")
3536
val content: String,
3637
) {
38+
fun getDeletedByBase58(): String? = deletedByBase58
39+
3740
@Ignore
3841
val id: ID = Base58.decode(idBase58).toList()
3942

@@ -43,6 +46,9 @@ data class ConversationMessage(
4346
@Ignore
4447
val senderId: ID = Base58.decode(senderIdBase58).toList()
4548

49+
@Ignore
50+
val deletedBy: ID? = deletedByBase58?.let { Base58.decode(deletedByBase58).toList() }
51+
4652
@Ignore
4753
val isDeleted: Boolean = deleted == true
4854
}

services/flipchat/chat/src/main/kotlin/xyz/flipchat/services/internal/data/mapper/ChatMessageMapper.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class ChatMessageMapper @Inject constructor(): Mapper<Pair<ID, Model.Message>, C
2626
contents = message.contentList.mapNotNull {
2727
MessageContent.invoke(
2828
it,
29+
messageSenderId,
2930
isFromSelf
3031
)
3132
},

services/flipchat/chat/src/main/kotlin/xyz/flipchat/services/internal/data/mapper/LastMessageMapper.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class LastMessageMapper @Inject constructor(
2323
contents = message.contentList.mapNotNull {
2424
MessageContent.invoke(
2525
it,
26+
messageSenderId,
2627
isFromSelf
2728
)
2829
},

0 commit comments

Comments
 (0)