ios: fix message view updates (refactor model to make it shallow) (#254)

This commit is contained in:
Evgeny Poberezkin
2022-02-02 12:51:39 +00:00
committed by GitHub
parent 1d1ba8607e
commit 7ce305e16f
9 changed files with 153 additions and 130 deletions

View File

@@ -12,29 +12,76 @@ import SwiftUI
final class ChatModel: ObservableObject {
@Published var currentUser: User?
@Published var chats: Dictionary<String, Chat> = [:]
@Published var chatPreviews: [Chat] = []
// list of chat "previews"
@Published var chats: [Chat] = []
// current chat
@Published var chatId: String?
@Published var chatItems: [ChatItem] = []
// items in the terminal view
@Published var terminalItems: [TerminalItem] = []
@Published var userAddress: String?
@Published var appOpenUrl: URL?
@Published var connectViaUrl = false
func hasChat(_ id: String) -> Bool {
chats.first(where: { $0.id == id }) != nil
}
func getChat(_ id: String) -> Chat? {
chats.first(where: { $0.id == id })
}
func addChat(_ chat: Chat) {
chats.insert(chat, at: 0)
}
func updateChatInfo(_ cInfo: ChatInfo) {
if let ix = chats.firstIndex(where: { $0.id == cInfo.id }) {
chats[ix].chatInfo = cInfo
}
}
func replaceChat(_ id: String, _ chat: Chat) {
if let ix = chats.firstIndex(where: { $0.id == id }) {
chats[ix] = chat
} else {
// invalid state, correcting
chats.insert(chat, at: 0)
}
}
func addChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) {
if let ix = chats.firstIndex(where: { $0.id == cInfo.id }) {
chats[ix].chatItems = [cItem]
if chatId != cInfo.id {
let chat = chats.remove(at: ix)
chats.insert(chat, at: 0)
}
}
if chatId == cInfo.id {
chatItems.append(cItem)
}
}
func removeChat(_ id: String) {
chats.removeAll(where: { $0.id == id })
}
}
class User: Decodable {
struct User: Decodable {
var userId: Int64
var userContactId: Int64
var localDisplayName: ContactName
var profile: Profile
var activeUser: Bool
internal init(userId: Int64, userContactId: Int64, localDisplayName: ContactName, profile: Profile, activeUser: Bool) {
self.userId = userId
self.userContactId = userContactId
self.localDisplayName = localDisplayName
self.profile = profile
self.activeUser = activeUser
}
// internal init(userId: Int64, userContactId: Int64, localDisplayName: ContactName, profile: Profile, activeUser: Bool) {
// self.userId = userId
// self.userContactId = userContactId
// self.localDisplayName = localDisplayName
// self.profile = profile
// self.activeUser = activeUser
// }
}
let sampleUser = User(
@@ -103,9 +150,9 @@ enum ChatInfo: Identifiable, Decodable {
var apiId: Int64 {
get {
switch self {
case let .direct(contact): return contact.contactId
case let .group(groupInfo): return groupInfo.groupId
case let .contactRequest(contactRequest): return contactRequest.contactRequestId
case let .direct(contact): return contact.apiId
case let .group(groupInfo): return groupInfo.apiId
case let .contactRequest(contactRequest): return contactRequest.apiId
}
}
}
@@ -117,11 +164,16 @@ let sampleGroupChatInfo = ChatInfo.group(groupInfo: sampleGroupInfo)
let sampleContactRequestChatInfo = ChatInfo.contactRequest(contactRequest: sampleContactRequest)
class Chat: Decodable, Identifiable {
var chatInfo: ChatInfo
var chatItems: [ChatItem]
final class Chat: ObservableObject, Identifiable {
@Published var chatInfo: ChatInfo
@Published var chatItems: [ChatItem]
init(chatInfo: ChatInfo, chatItems: [ChatItem]) {
init(_ cData: ChatData) {
self.chatInfo = cData.chatInfo
self.chatItems = cData.chatItems
}
init(chatInfo: ChatInfo, chatItems: [ChatItem] = []) {
self.chatInfo = chatInfo
self.chatItems = chatItems
}
@@ -129,6 +181,13 @@ class Chat: Decodable, Identifiable {
var id: String { get { chatInfo.id } }
}
struct ChatData: Decodable, Identifiable {
var chatInfo: ChatInfo
var chatItems: [ChatItem]
var id: String { get { chatInfo.id } }
}
struct Contact: Identifiable, Decodable {
var contactId: Int64
var localDisplayName: ContactName
@@ -137,7 +196,7 @@ struct Contact: Identifiable, Decodable {
var viaGroup: Int64?
var id: String { get { "@\(contactId)" } }
var apiId: Int64 { get { contactId } }
var connected: Bool { get { activeConn.connStatus == "ready" || activeConn.connStatus == "snd-ready" } }
}
@@ -160,6 +219,8 @@ struct UserContactRequest: Decodable {
var profile: Profile
var id: String { get { "<@\(contactRequestId)" } }
var apiId: Int64 { get { contactRequestId } }
}
let sampleContactRequest = UserContactRequest(
@@ -174,6 +235,8 @@ struct GroupInfo: Identifiable, Decodable {
var groupProfile: GroupProfile
var id: String { get { "#\(groupId)" } }
var apiId: Int64 { get { groupId } }
}
let sampleGroupInfo = GroupInfo(

View File

@@ -69,8 +69,8 @@ struct APIResponse: Decodable {
enum ChatResponse: Decodable, Error {
case response(type: String, json: String)
case apiChats(chats: [Chat])
case apiChat(chat: Chat)
case apiChats(chats: [ChatData])
case apiChat(chat: ChatData)
case invitation(connReqInvitation: String)
case sentConfirmation
case sentInvitation
@@ -210,13 +210,13 @@ func chatRecvMsg() throws -> ChatResponse {
func apiGetChats() throws -> [Chat] {
let r = try chatSendCmd(.apiGetChats)
if case let .apiChats(chats) = r { return chats }
if case let .apiChats(chats) = r { return chats.map { Chat.init($0) } }
throw r
}
func apiGetChat(type: ChatType, id: Int64) throws -> Chat {
let r = try chatSendCmd(.apiGetChat(type: type, id: id))
if case let .apiChat(chat) = r { return chat }
if case let .apiChat(chat) = r { return Chat.init(chat) }
throw r
}
@@ -296,27 +296,19 @@ func processReceivedMsg(_ chatModel: ChatModel, _ res: ChatResponse) {
chatModel.terminalItems.append(.resp(Date.now, res))
switch res {
case let .contactConnected(contact):
if let chat = chatModel.chats[contact.id] {
chat.chatInfo = ChatInfo.direct(contact: contact)
let cInfo = ChatInfo.direct(contact: contact)
if chatModel.hasChat(contact.id) {
chatModel.updateChatInfo(cInfo)
} else {
let chat = Chat(chatInfo: ChatInfo.direct(contact: contact), chatItems: [])
chatModel.chats[contact.id] = chat
chatModel.chatPreviews.insert(chat, at: 0)
chatModel.addChat(Chat(chatInfo: cInfo, chatItems: []))
}
case let .receivedContactRequest(contactRequest):
let chat = Chat(chatInfo: ChatInfo.contactRequest(contactRequest: contactRequest), chatItems: [])
chatModel.chats[contactRequest.id] = chat
chatModel.chatPreviews.insert(chat, at: 0)
chatModel.addChat(Chat(
chatInfo: ChatInfo.contactRequest(contactRequest: contactRequest),
chatItems: []
))
case let .newChatItem(aChatItem):
let ci = aChatItem.chatInfo
let chat = chatModel.chats[ci.id] ?? Chat(chatInfo: ci, chatItems: [])
chatModel.chats[ci.id] = chat
chat.chatItems.append(aChatItem.chatItem)
if let cp = chatModel.chatPreviews.first(where: { $0.id == ci.id } ) {
cp.chatItems = [aChatItem.chatItem]
} else {
chatModel.chatPreviews.insert(Chat(chatInfo: ci, chatItems: [aChatItem.chatItem]), at: 0)
}
chatModel.addChatItem(aChatItem.chatInfo, aChatItem.chatItem)
default:
print("unsupported response: ", res.responseType)
}