From 20c89c65e9926ef22b15ebb0ce4eb923c7d83aa9 Mon Sep 17 00:00:00 2001 From: fmodf Date: Wed, 26 Jun 2024 10:00:59 +0200 Subject: [PATCH] wip --- .../AppCore/Actions/ConversationActions.swift | 4 ++ .../Middlewares/DatabaseMiddleware.swift | 61 +++++++++++++++++-- .../AppCore/Models/Message.swift | 2 +- .../Reducers/ConversationReducer.swift | 3 + .../View/Screens/ConversationScreen.swift | 14 ++--- 5 files changed, 72 insertions(+), 12 deletions(-) diff --git a/ConversationsClassic/AppCore/Actions/ConversationActions.swift b/ConversationsClassic/AppCore/Actions/ConversationActions.swift index c8cb715..3d6e254 100644 --- a/ConversationsClassic/AppCore/Actions/ConversationActions.swift +++ b/ConversationsClassic/AppCore/Actions/ConversationActions.swift @@ -1,3 +1,7 @@ enum ConversationAction: Codable { case makeConversationActive(chat: Chat, roster: Roster?) + + case sendMessage(from: String, to: String, body: String) + + case messagesUpdated(messages: [Message]) } diff --git a/ConversationsClassic/AppCore/Middlewares/DatabaseMiddleware.swift b/ConversationsClassic/AppCore/Middlewares/DatabaseMiddleware.swift index 959ab19..e97518b 100644 --- a/ConversationsClassic/AppCore/Middlewares/DatabaseMiddleware.swift +++ b/ConversationsClassic/AppCore/Middlewares/DatabaseMiddleware.swift @@ -6,6 +6,7 @@ final class DatabaseMiddleware { static let shared = DatabaseMiddleware() private let database = Database.shared private var cancellables: Set = [] + private var conversationCancellables: Set = [] private init() { // Database changes @@ -35,6 +36,7 @@ final class DatabaseMiddleware { func middleware(state _: AppState, action: AppAction) -> AnyPublisher { switch action { + // MARK: Accounts case .startAction(.loadStoredAccounts): return Future { promise in Task(priority: .background) { [weak self] in @@ -81,6 +83,7 @@ final class DatabaseMiddleware { } .eraseToAnyPublisher() + // MARK: Rosters case .rostersAction(.markRosterAsLocallyDeleted(let ownerJID, let contactJID)): return Future { promise in Task(priority: .background) { [weak self] in @@ -125,6 +128,7 @@ final class DatabaseMiddleware { } .eraseToAnyPublisher() + // MARK: Chats case .chatsAction(.createNewChat(let accountJid, let participantJid)): return Future { promise in Task(priority: .background) { [weak self] in @@ -150,11 +154,60 @@ final class DatabaseMiddleware { } .eraseToAnyPublisher() - case .xmppAction(.xmppMessageReceived(let message)): - if message.type != .chat { - return Empty().eraseToAnyPublisher() + // MARK: Conversation and messages + case .conversationAction(.makeConversationActive(let chat, _)): + return Future { [weak self] promise in + guard let wSelf = self else { + promise(.success(.empty)) + return + } + // Observe changes for current conversation + wSelf.conversationCancellables = [] + ValueObservation + .tracking( + Message + .filter( + Column("from") == chat.account || + Column("from") == chat.participant || + Column("to") == chat.participant || + Column("to") == chat.participant + ) + .order(Column("timestamp").asc) + .fetchAll + ) + .publisher(in: wSelf.database._db, scheduling: .immediate) + .sink { _ in + // Handle completion + } receiveValue: { messages in + DispatchQueue.main.async { + store.dispatch(.conversationAction(.messagesUpdated(messages: messages))) + } + } + .store(in: &wSelf.conversationCancellables) + promise(.success(.empty)) } - // TODO: Store msg here! + .eraseToAnyPublisher() + + case .xmppAction(.xmppMessageReceived(let message)): + return Future { promise in + Task(priority: .background) { [weak self] in + guard let database = self?.database else { + promise(.success(.empty)) + return + } + do { + try database._db.write { db in + try message.insert(db) + promise(.success(.empty)) + } + } catch { + promise(.success(.databaseAction(.updateAccountFailed))) + } + } + } + .eraseToAnyPublisher() + + case .conversationAction(.sendMessage(let from, let to, let body)): return Empty().eraseToAnyPublisher() default: diff --git a/ConversationsClassic/AppCore/Models/Message.swift b/ConversationsClassic/AppCore/Models/Message.swift index 7c7ba5c..6c0c101 100644 --- a/ConversationsClassic/AppCore/Models/Message.swift +++ b/ConversationsClassic/AppCore/Models/Message.swift @@ -14,7 +14,7 @@ enum MessageContentType: String, Codable, DatabaseValueConvertible { case invite } -struct Message: Stateable, Identifiable, DatabaseValueConvertible { +struct Message: DBStorable, Equatable { let id: String let type: MessageType let contentType: MessageContentType diff --git a/ConversationsClassic/AppCore/Reducers/ConversationReducer.swift b/ConversationsClassic/AppCore/Reducers/ConversationReducer.swift index ad87e81..164afb0 100644 --- a/ConversationsClassic/AppCore/Reducers/ConversationReducer.swift +++ b/ConversationsClassic/AppCore/Reducers/ConversationReducer.swift @@ -7,6 +7,9 @@ extension ConversationState { state.currentChat = chat state.currentRoster = roster + case .messagesUpdated(let messages): + state.currentMessages = messages + default: break } diff --git a/ConversationsClassic/View/Screens/ConversationScreen.swift b/ConversationsClassic/View/Screens/ConversationScreen.swift index 759bdda..c302d31 100644 --- a/ConversationsClassic/View/Screens/ConversationScreen.swift +++ b/ConversationsClassic/View/Screens/ConversationScreen.swift @@ -70,13 +70,13 @@ struct ConversationScreenTextInput: View { .padding(.trailing, 8) .tappablePadding(.symmetric(8)) { if !messageStr.isEmpty { - // guard let acc = store.state.conversationsState.currentChat?.account else { return } - // guard let contact = store.state.conversationsState.currentChat?.participant else { return } - // store.dispatch(.conversationAction(.sendMessage( - // from: acc, - // to: contact, - // body: messageStr - // ))) + guard let acc = store.state.conversationsState.currentChat?.account else { return } + guard let contact = store.state.conversationsState.currentChat?.participant else { return } + store.dispatch(.conversationAction(.sendMessage( + from: acc, + to: contact, + body: messageStr + ))) messageStr = "" UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) }