This commit is contained in:
fmodf 2024-06-26 10:00:59 +02:00
parent e23a312538
commit 20c89c65e9
5 changed files with 72 additions and 12 deletions

View file

@ -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])
}

View file

@ -6,6 +6,7 @@ final class DatabaseMiddleware {
static let shared = DatabaseMiddleware()
private let database = Database.shared
private var cancellables: Set<AnyCancellable> = []
private var conversationCancellables: Set<AnyCancellable> = []
private init() {
// Database changes
@ -35,6 +36,7 @@ final class DatabaseMiddleware {
func middleware(state _: AppState, action: AppAction) -> AnyPublisher<AppAction, Never> {
switch action {
// MARK: Accounts
case .startAction(.loadStoredAccounts):
return Future<AppAction, Never> { 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<AppAction, Never> { 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<AppAction, Never> { 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<AppAction, Never> { [weak self] promise in
guard let wSelf = self else {
promise(.success(.empty))
return
}
// TODO: Store msg here!
// 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))
}
.eraseToAnyPublisher()
case .xmppAction(.xmppMessageReceived(let message)):
return Future<AppAction, Never> { 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:

View file

@ -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

View file

@ -7,6 +7,9 @@ extension ConversationState {
state.currentChat = chat
state.currentRoster = roster
case .messagesUpdated(let messages):
state.currentMessages = messages
default:
break
}

View file

@ -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)
}