ios: fix message view updates (refactor model to make it shallow) (#254)
This commit is contained in:
committed by
GitHub
parent
1d1ba8607e
commit
7ce305e16f
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user