mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-29 04:39:53 +00:00
update model when messages arrive (#333)
* update model when messages arrive * update chat in the list when message is added * copy methods with optional parameters * use data classes to have pre-defined copy methods
This commit is contained in:
parent
f650308986
commit
bba2783aa4
4 changed files with 219 additions and 9 deletions
|
@ -12,6 +12,148 @@ class ChatModel(val controller: ChatController) {
|
|||
|
||||
var terminalItems = mutableStateListOf<TerminalItem>()
|
||||
|
||||
fun hasChat(id: String): Boolean = chats.firstOrNull() { it.id == id } != null
|
||||
fun getChat(id: String): Chat? = chats.firstOrNull { it.id == id }
|
||||
private fun getChatIndex(id: String): Int = chats.indexOfFirst { it.id == id }
|
||||
fun addChat(chat: Chat) = chats.add(index = 0, chat)
|
||||
|
||||
// func updateChatInfo(_ cInfo: ChatInfo) {
|
||||
// if let i = getChatIndex(cInfo.id) {
|
||||
// chats[i].chatInfo = cInfo
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func updateContact(_ contact: Contact) {
|
||||
// let cInfo = ChatInfo.direct(contact: contact)
|
||||
// if hasChat(contact.id) {
|
||||
// updateChatInfo(cInfo)
|
||||
// } else {
|
||||
// addChat(Chat(chatInfo: cInfo, chatItems: []))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func updateNetworkStatus(_ contact: Contact, _ status: Chat.NetworkStatus) {
|
||||
// if let ix = getChatIndex(contact.id) {
|
||||
// chats[ix].serverInfo.networkStatus = status
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func replaceChat(_ id: String, _ chat: Chat) {
|
||||
// if let i = getChatIndex(id) {
|
||||
// chats[i] = chat
|
||||
// } else {
|
||||
// // invalid state, correcting
|
||||
// chats.insert(chat, at: 0)
|
||||
// }
|
||||
// }
|
||||
|
||||
fun addChatItem(cInfo: ChatInfo, cItem: ChatItem) {
|
||||
// update previews
|
||||
val i = getChatIndex(cInfo.id)
|
||||
if (i >= 0) {
|
||||
val chat = chats[i]
|
||||
val updatedChat = chat.copy(
|
||||
chatItems = arrayListOf(cItem),
|
||||
chatStats =
|
||||
if (cItem.meta.itemStatus is CIStatus.RcvNew)
|
||||
chat.chatStats.copy(unreadCount = chat.chatStats.unreadCount + 1)
|
||||
else
|
||||
chat.chatStats
|
||||
)
|
||||
chats.set(i, updatedChat)
|
||||
if (i > 0) {
|
||||
popChat_(i)
|
||||
}
|
||||
} else {
|
||||
addChat(Chat(chatInfo = cInfo, chatItems = arrayListOf(cItem)))
|
||||
}
|
||||
// add to current chat
|
||||
if (chatId.value == cInfo.id) {
|
||||
chatItems.add(cItem)
|
||||
if (cItem.meta.itemStatus is CIStatus.RcvNew) {
|
||||
// TODO mark item read via api and model
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
// if self.chatId == cInfo.id {
|
||||
// SimpleX.markChatItemRead(cInfo, cItem)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// func upsertChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) -> Bool {
|
||||
// // update previews
|
||||
// var res: Bool
|
||||
// if let chat = getChat(cInfo.id) {
|
||||
// if let pItem = chat.chatItems.last, pItem.id == cItem.id {
|
||||
// chat.chatItems = [cItem]
|
||||
// }
|
||||
// res = false
|
||||
// } else {
|
||||
// addChat(Chat(chatInfo: cInfo, chatItems: [cItem]))
|
||||
// res = true
|
||||
// }
|
||||
// // update current chat
|
||||
// if chatId == cInfo.id {
|
||||
// if let i = chatItems.firstIndex(where: { $0.id == cItem.id }) {
|
||||
// withAnimation(.default) {
|
||||
// self.chatItems[i] = cItem
|
||||
// }
|
||||
// return false
|
||||
// } else {
|
||||
// withAnimation { chatItems.append(cItem) }
|
||||
// return true
|
||||
// }
|
||||
// } else {
|
||||
// return res
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func markChatItemsRead(_ cInfo: ChatInfo) {
|
||||
// // update preview
|
||||
// if let chat = getChat(cInfo.id) {
|
||||
// chat.chatStats = ChatStats()
|
||||
// }
|
||||
// // update current chat
|
||||
// if chatId == cInfo.id {
|
||||
// var i = 0
|
||||
// while i < chatItems.count {
|
||||
// if case .rcvNew = chatItems[i].meta.itemStatus {
|
||||
// chatItems[i].meta.itemStatus = .rcvRead
|
||||
// }
|
||||
// i = i + 1
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func markChatItemRead(_ cInfo: ChatInfo, _ cItem: ChatItem) {
|
||||
// // update preview
|
||||
// if let i = getChatIndex(cInfo.id) {
|
||||
// chats[i].chatStats.unreadCount = chats[i].chatStats.unreadCount - 1
|
||||
// }
|
||||
// // update current chat
|
||||
// if chatId == cInfo.id, let j = chatItems.firstIndex(where: { $0.id == cItem.id }) {
|
||||
// chatItems[j].meta.itemStatus = .rcvRead
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func popChat(_ id: String) {
|
||||
// if let i = getChatIndex(id) {
|
||||
// popChat_(i)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
private fun popChat_(i: Int) {
|
||||
val chat = chats.removeAt(i)
|
||||
chats.add(index = 0, chat)
|
||||
}
|
||||
//
|
||||
// func removeChat(_ id: String) {
|
||||
// withAnimation {
|
||||
// chats.removeAll(where: { $0.id == id })
|
||||
// }
|
||||
// }
|
||||
|
||||
companion object {
|
||||
val sampleData: ChatModel get() {
|
||||
val m = ChatModel(ChatController.Mock())
|
||||
|
@ -70,17 +212,16 @@ interface SomeChat {
|
|||
}
|
||||
|
||||
@Serializable
|
||||
class Chat (
|
||||
data class Chat (
|
||||
val chatInfo: ChatInfo,
|
||||
val chatItems: List<ChatItem>,
|
||||
val chatStats: ChatStats,
|
||||
val chatStats: ChatStats = ChatStats(),
|
||||
val serverInfo: ServerInfo = ServerInfo(NetworkStatus.Unknown())
|
||||
) {
|
||||
val id: String get() = chatInfo.id
|
||||
|
||||
@Serializable
|
||||
class ChatStats {
|
||||
|
||||
}
|
||||
data class ChatStats(val unreadCount: Int = 0, val minUnreadItemId: Long = 0)
|
||||
|
||||
@Serializable
|
||||
class ServerInfo(val networkStatus: NetworkStatus)
|
||||
|
|
|
@ -43,9 +43,10 @@ open class ChatController(val ctrl: ChatCtrl) {
|
|||
// val chatlog = FifoQueue<String>(500)
|
||||
while(true) {
|
||||
val json = chatRecvMsg(ctrl)
|
||||
Log.d("SIMPLEX chatRecvMsg: ", json)
|
||||
val r = APIResponse.decodeStr(json)
|
||||
chatModel.terminalItems.add(TerminalItem.resp(r.resp))
|
||||
val r = APIResponse.decodeStr(json).resp
|
||||
Log.d("SIMPLEX", "chatRecvMsg: ${r.responseType}")
|
||||
if (r is CR.Response || r is CR.Invalid) Log.d("SIMPLEX", "chatRecvMsg json: $json")
|
||||
processReceivedMsg(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +107,71 @@ open class ChatController(val ctrl: ChatCtrl) {
|
|||
return null
|
||||
}
|
||||
|
||||
fun processReceivedMsg(r: CR) {
|
||||
chatModel.terminalItems.add(TerminalItem.resp(r))
|
||||
when {
|
||||
// r is CR.ContactConnected -> return
|
||||
// r is CR.UpdateNetworkStatus -> return
|
||||
// r is CR.ReceivedContactRequest -> return
|
||||
// r is CR.ContactUpdated -> return
|
||||
// r is CR.ContactSubscribed -> return
|
||||
// r is CR.ContactSubError -> return
|
||||
// r is CR.UpdateContact -> return
|
||||
r is CR.NewChatItem -> {
|
||||
val cInfo = r.chatItem.chatInfo
|
||||
val cItem = r.chatItem.chatItem
|
||||
chatModel.addChatItem(cInfo, cItem)
|
||||
}
|
||||
// NtfManager.shared.notifyMessageReceived(cInfo, cItem)
|
||||
|
||||
// switch res {
|
||||
// case let .contactConnected(contact):
|
||||
// chatModel.updateContact(contact)
|
||||
// chatModel.updateNetworkStatus(contact, .connected)
|
||||
// NtfManager.shared.notifyContactConnected(contact)
|
||||
// case let .receivedContactRequest(contactRequest):
|
||||
// chatModel.addChat(Chat(
|
||||
// chatInfo: ChatInfo.contactRequest(contactRequest: contactRequest),
|
||||
// chatItems: []
|
||||
// ))
|
||||
// NtfManager.shared.notifyContactRequest(contactRequest)
|
||||
// case let .contactUpdated(toContact):
|
||||
// let cInfo = ChatInfo.direct(contact: toContact)
|
||||
// if chatModel.hasChat(toContact.id) {
|
||||
// chatModel.updateChatInfo(cInfo)
|
||||
// }
|
||||
// case let .contactSubscribed(contact):
|
||||
// chatModel.updateContact(contact)
|
||||
// chatModel.updateNetworkStatus(contact, .connected)
|
||||
// case let .contactDisconnected(contact):
|
||||
// chatModel.updateContact(contact)
|
||||
// chatModel.updateNetworkStatus(contact, .disconnected)
|
||||
// case let .contactSubError(contact, chatError):
|
||||
// chatModel.updateContact(contact)
|
||||
//// var err: String
|
||||
//// switch chatError {
|
||||
//// case .errorAgent(agentError: .BROKER(brokerErr: .NETWORK)): err = "network"
|
||||
//// case .errorAgent(agentError: .SMP(smpErr: .AUTH)): err = "contact deleted"
|
||||
//// default: err = String(describing: chatError)
|
||||
//// }
|
||||
//// chatModel.updateNetworkStatus(contact, .error(err))
|
||||
// case let .newChatItem(aChatItem):
|
||||
// let cInfo = aChatItem.chatInfo
|
||||
// let cItem = aChatItem.chatItem
|
||||
// chatModel.addChatItem(cInfo, cItem)
|
||||
// NtfManager.shared.notifyMessageReceived(cInfo, cItem)
|
||||
// case let .chatItemUpdated(aChatItem):
|
||||
// let cInfo = aChatItem.chatInfo
|
||||
// let cItem = aChatItem.chatItem
|
||||
// if chatModel.upsertChatItem(cInfo, cItem) {
|
||||
// NtfManager.shared.notifyMessageReceived(cInfo, cItem)
|
||||
// }
|
||||
// default:
|
||||
// logger.debug("unsupported event: \(res.responseType)")
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
class Mock: ChatController(0) {}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ fun ChatView(chatModel: ChatModel, nav: NavController) {
|
|||
mc = MsgContent.MCText(msg)
|
||||
)
|
||||
// hide "in progress"
|
||||
// TODO add new item
|
||||
if (newItem != null) chatModel.addChatItem(cInfo, newItem.chatItem)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -237,6 +237,9 @@ func chatSendCmd(_ cmd: ChatCommand) throws -> ChatResponse {
|
|||
logger.debug("chatSendCmd \(cmd.cmdType)")
|
||||
let resp = chatResponse(chat_send_cmd(getChatCtrl(), &c)!)
|
||||
logger.debug("chatSendCmd \(cmd.cmdType): \(resp.responseType)")
|
||||
if case let .response(_, json) = resp {
|
||||
logger.debug("chatSendCmd \(cmd.cmdType) response: \(json)")
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
ChatModel.shared.terminalItems.append(.cmd(.now, cmd))
|
||||
ChatModel.shared.terminalItems.append(.resp(.now, resp))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue