core, ui: prevent old sent items re-added to chat, and "new" status overriding "sent" (#3246)
* core, ui: prevent old sent items re-added to chat, and "new" status overriding "sent" * clear item statuses when changing current chat * remove iOS hack * remote state/published from chatItemStatuses
This commit is contained in:
parent
a02886ca5d
commit
706d6bf65b
@ -62,6 +62,7 @@ final class ChatModel: ObservableObject {
|
||||
// current chat
|
||||
@Published var chatId: String?
|
||||
@Published var reversedChatItems: [ChatItem] = []
|
||||
var chatItemStatuses: Dictionary<Int64, CIStatus> = [:]
|
||||
@Published var chatToTop: String?
|
||||
@Published var groupMembers: [GroupMember] = []
|
||||
// items in the terminal view
|
||||
@ -306,7 +307,11 @@ final class ChatModel: ObservableObject {
|
||||
return false
|
||||
} else {
|
||||
withAnimation(itemAnimation()) {
|
||||
reversedChatItems.insert(cItem, at: hasLiveDummy ? 1 : 0)
|
||||
var ci = cItem
|
||||
if let status = chatItemStatuses.removeValue(forKey: ci.id), case .sndNew = ci.meta.itemStatus {
|
||||
ci.meta.itemStatus = status
|
||||
}
|
||||
reversedChatItems.insert(ci, at: hasLiveDummy ? 1 : 0)
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -319,23 +324,19 @@ final class ChatModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func updateChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) {
|
||||
func updateChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem, status: CIStatus? = nil) {
|
||||
if chatId == cInfo.id, let i = getChatItemIndex(cItem) {
|
||||
withAnimation {
|
||||
_updateChatItem(at: i, with: cItem)
|
||||
}
|
||||
} else if let status = status {
|
||||
chatItemStatuses.updateValue(status, forKey: cItem.id)
|
||||
}
|
||||
}
|
||||
|
||||
private func _updateChatItem(at i: Int, with cItem: ChatItem) {
|
||||
let ci = reversedChatItems[i]
|
||||
reversedChatItems[i] = cItem
|
||||
reversedChatItems[i].viewTimestamp = .now
|
||||
// on some occasions the confirmation of message being accepted by the server (tick)
|
||||
// arrives earlier than the response from API, and item remains without tick
|
||||
if case .sndNew = cItem.meta.itemStatus {
|
||||
reversedChatItems[i].meta.itemStatus = ci.meta.itemStatus
|
||||
}
|
||||
}
|
||||
|
||||
private func getChatItemIndex(_ cItem: ChatItem) -> Int? {
|
||||
@ -474,6 +475,7 @@ final class ChatModel: ObservableObject {
|
||||
}
|
||||
// clear current chat
|
||||
if chatId == cInfo.id {
|
||||
chatItemStatuses = [:]
|
||||
reversedChatItems = []
|
||||
}
|
||||
}
|
||||
|
@ -312,6 +312,7 @@ func loadChat(chat: Chat, search: String = "") {
|
||||
do {
|
||||
let cInfo = chat.chatInfo
|
||||
let m = ChatModel.shared
|
||||
m.chatItemStatuses = [:]
|
||||
m.reversedChatItems = []
|
||||
let chat = try apiGetChat(type: cInfo.chatType, id: cInfo.apiId, search: search)
|
||||
m.updateChatInfo(chat.chatInfo)
|
||||
@ -1421,11 +1422,8 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
||||
case let .chatItemStatusUpdated(user, aChatItem):
|
||||
let cInfo = aChatItem.chatInfo
|
||||
let cItem = aChatItem.chatItem
|
||||
if !cItem.isDeletedContent {
|
||||
let added = active(user) ? await MainActor.run { m.upsertChatItem(cInfo, cItem) } : true
|
||||
if added && cItem.showNotification {
|
||||
NtfManager.shared.notifyMessageReceived(user, cInfo, cItem)
|
||||
}
|
||||
if !cItem.isDeletedContent && active(user) {
|
||||
await MainActor.run { m.updateChatItem(cInfo, cItem, status: cItem.meta.itemStatus) }
|
||||
}
|
||||
if let endTask = m.messageDelivery[cItem.id] {
|
||||
switch cItem.meta.itemStatus {
|
||||
|
@ -91,6 +91,7 @@ struct ChatView: View {
|
||||
chatModel.chatId = nil
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
|
||||
if chatModel.chatId == nil {
|
||||
chatModel.chatItemStatuses = [:]
|
||||
chatModel.reversedChatItems = []
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ object ChatModel {
|
||||
// current chat
|
||||
val chatId = mutableStateOf<String?>(null)
|
||||
val chatItems = mutableStateListOf<ChatItem>()
|
||||
val chatItemStatuses = mutableMapOf<Long, CIStatus>()
|
||||
val groupMembers = mutableStateListOf<GroupMember>()
|
||||
|
||||
val terminalItems = mutableStateListOf<TerminalItem>()
|
||||
@ -272,7 +273,13 @@ object ChatModel {
|
||||
Log.d(TAG, "TODOCHAT: upsertChatItem: updated in chat $chatId from ${cInfo.id} ${cItem.id}, size ${chatItems.size}")
|
||||
false
|
||||
} else {
|
||||
chatItems.add(cItem)
|
||||
val status = chatItemStatuses.remove(cItem.id)
|
||||
val ci = if (status != null && cItem.meta.itemStatus is CIStatus.SndNew) {
|
||||
cItem.copy(meta = cItem.meta.copy(itemStatus = status))
|
||||
} else {
|
||||
cItem
|
||||
}
|
||||
chatItems.add(ci)
|
||||
Log.d(TAG, "TODOCHAT: upsertChatItem: added to chat $chatId from ${cInfo.id} ${cItem.id}, size ${chatItems.size}")
|
||||
true
|
||||
}
|
||||
@ -282,13 +289,15 @@ object ChatModel {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateChatItem(cInfo: ChatInfo, cItem: ChatItem) {
|
||||
suspend fun updateChatItem(cInfo: ChatInfo, cItem: ChatItem, status: CIStatus? = null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
if (chatId.value == cInfo.id) {
|
||||
val itemIndex = chatItems.indexOfFirst { it.id == cItem.id }
|
||||
if (itemIndex >= 0) {
|
||||
chatItems[itemIndex] = cItem
|
||||
}
|
||||
} else if (status != null) {
|
||||
chatItemStatuses[cItem.id] = status
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -326,6 +335,7 @@ object ChatModel {
|
||||
}
|
||||
// clear current chat
|
||||
if (chatId.value == cInfo.id) {
|
||||
chatItemStatuses.clear()
|
||||
chatItems.clear()
|
||||
}
|
||||
}
|
||||
|
@ -1489,11 +1489,8 @@ object ChatController {
|
||||
is CR.ChatItemStatusUpdated -> {
|
||||
val cInfo = r.chatItem.chatInfo
|
||||
val cItem = r.chatItem.chatItem
|
||||
if (!cItem.isDeletedContent) {
|
||||
val added = if (active(r.user)) chatModel.upsertChatItem(cInfo, cItem) else true
|
||||
if (added && cItem.showNotification) {
|
||||
ntfManager.notifyMessageReceived(r.user, cInfo, cItem)
|
||||
}
|
||||
if (!cItem.isDeletedContent && active(r.user)) {
|
||||
chatModel.updateChatItem(cInfo, cItem, status = cItem.meta.itemStatus)
|
||||
}
|
||||
}
|
||||
is CR.ChatItemUpdated ->
|
||||
|
@ -73,6 +73,7 @@ fun GroupMemberInfoView(
|
||||
chatModel.addChat(c)
|
||||
}
|
||||
chatModel.chatItems.clear()
|
||||
chatModel.chatItemStatuses.clear()
|
||||
chatModel.chatItems.addAll(c.chatItems)
|
||||
chatModel.chatId.value = c.id
|
||||
closeAll()
|
||||
|
@ -141,6 +141,7 @@ suspend fun openChat(chatInfo: ChatInfo, chatModel: ChatModel) {
|
||||
|
||||
suspend fun openChat(chat: Chat, chatModel: ChatModel) {
|
||||
chatModel.chatItems.clear()
|
||||
chatModel.chatItemStatuses.clear()
|
||||
chatModel.chatItems.addAll(chat.chatItems)
|
||||
chatModel.chatId.value = chat.chatInfo.id
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ fun AddGroupView(chatModel: ChatModel, close: () -> Unit) {
|
||||
if (groupInfo != null) {
|
||||
chatModel.addChat(Chat(chatInfo = ChatInfo.Group(groupInfo), chatItems = listOf()))
|
||||
chatModel.chatItems.clear()
|
||||
chatModel.chatItemStatuses.clear()
|
||||
chatModel.chatId.value = groupInfo.id
|
||||
setGroupMembers(groupInfo, chatModel)
|
||||
close.invoke()
|
||||
|
@ -584,11 +584,11 @@ processChatCommand = \case
|
||||
timed_ <- sndContactCITimed live ct itemTTL
|
||||
(msgContainer, quotedItem_) <- prepareMsg fInv_ timed_
|
||||
(msg@SndMessage {sharedMsgId}, _) <- sendDirectContactMessage ct (XMsgNew msgContainer)
|
||||
ci <- saveSndChatItem' user (CDDirectSnd ct) msg (CISndMsgContent mc) ciFile_ quotedItem_ timed_ live
|
||||
case ft_ of
|
||||
Just ft@FileTransferMeta {fileInline = Just IFMSent} ->
|
||||
sendDirectFileInline ct ft sharedMsgId
|
||||
_ -> pure ()
|
||||
ci <- saveSndChatItem' user (CDDirectSnd ct) msg (CISndMsgContent mc) ciFile_ quotedItem_ timed_ live
|
||||
forM_ (timed_ >>= timedDeleteAt') $
|
||||
startProximateTimedItemThread user (ChatRef CTDirect contactId, chatItemId' ci)
|
||||
pure $ CRNewChatItem user (AChatItem SCTDirect SMDSnd (DirectChat ct) ci)
|
||||
@ -649,11 +649,11 @@ processChatCommand = \case
|
||||
timed_ <- sndGroupCITimed live gInfo itemTTL
|
||||
(msgContainer, quotedItem_) <- prepareMsg fInv_ timed_ membership
|
||||
(msg@SndMessage {sharedMsgId}, sentToMembers) <- sendGroupMessage user gInfo ms (XMsgNew msgContainer)
|
||||
mapM_ (sendGroupFileInline ms sharedMsgId) ft_
|
||||
ci <- saveSndChatItem' user (CDGroupSnd gInfo) msg (CISndMsgContent mc) ciFile_ quotedItem_ timed_ live
|
||||
withStore' $ \db ->
|
||||
forM_ sentToMembers $ \GroupMember {groupMemberId} ->
|
||||
createGroupSndStatus db (chatItemId' ci) groupMemberId CISSndNew
|
||||
mapM_ (sendGroupFileInline ms sharedMsgId) ft_
|
||||
forM_ (timed_ >>= timedDeleteAt') $
|
||||
startProximateTimedItemThread user (ChatRef CTGroup groupId, chatItemId' ci)
|
||||
pure $ CRNewChatItem user (AChatItem SCTGroup SMDSnd (GroupChat gInfo) ci)
|
||||
@ -5208,9 +5208,7 @@ deliverMessage conn@Connection {connId} cmEventTag msgBody msgId = do
|
||||
let msgFlags = MsgFlags {notification = hasNotification cmEventTag}
|
||||
agentMsgId <- withAgent $ \a -> sendMessage a (aConnId conn) msgFlags msgBody
|
||||
let sndMsgDelivery = SndMsgDelivery {connId, agentMsgId}
|
||||
withStoreCtx'
|
||||
(Just $ "createSndMsgDelivery, sndMsgDelivery: " <> show sndMsgDelivery <> ", msgId: " <> show msgId <> ", cmEventTag: " <> show cmEventTag <> ", msgDeliveryStatus: MDSSndAgent")
|
||||
$ \db -> createSndMsgDelivery db sndMsgDelivery msgId
|
||||
withStore' $ \db -> createSndMsgDelivery db sndMsgDelivery msgId
|
||||
|
||||
sendGroupMessage :: (MsgEncodingI e, ChatMonad m) => User -> GroupInfo -> [GroupMember] -> ChatMsgEvent e -> m (SndMessage, [GroupMember])
|
||||
sendGroupMessage user GroupInfo {groupId} members chatMsgEvent =
|
||||
|
Loading…
Reference in New Issue
Block a user