Skip to content
Snippets Groups Projects
Commit 2d709642 authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Implement message sending

parent e2cf40af
Branches
Tags
2 merge requests!102Release 1.0.0,!87Messenger example - chat
...@@ -70,6 +70,11 @@ extension AppEnvironment { ...@@ -70,6 +70,11 @@ extension AppEnvironment {
ChatEnvironment( ChatEnvironment(
messenger: messenger, messenger: messenger,
db: dbManager.getDB, db: dbManager.getDB,
sendMessage: .live(
messenger: messenger,
db: dbManager.getDB,
now: Date.init
),
mainQueue: mainQueue, mainQueue: mainQueue,
bgQueue: bgQueue bgQueue: bgQueue
) )
......
import AppCore import AppCore
import Combine
import ComposableArchitecture import ComposableArchitecture
import Foundation import Foundation
import XCTestDynamicOverlay import XCTestDynamicOverlay
...@@ -34,40 +35,48 @@ public struct ChatState: Equatable, Identifiable { ...@@ -34,40 +35,48 @@ public struct ChatState: Equatable, Identifiable {
id: ID, id: ID,
myContactId: Data? = nil, myContactId: Data? = nil,
messages: IdentifiedArrayOf<Message> = [], messages: IdentifiedArrayOf<Message> = [],
failure: String? = nil failure: String? = nil,
text: String = ""
) { ) {
self.id = id self.id = id
self.myContactId = myContactId self.myContactId = myContactId
self.messages = messages self.messages = messages
self.failure = failure self.failure = failure
self.text = text
} }
public var id: ID public var id: ID
public var myContactId: Data? public var myContactId: Data?
public var messages: IdentifiedArrayOf<Message> public var messages: IdentifiedArrayOf<Message>
public var failure: String? public var failure: String?
@BindableState public var text: String
} }
public enum ChatAction: Equatable { public enum ChatAction: Equatable, BindableAction {
case start case start
case didFetchMessages(IdentifiedArrayOf<ChatState.Message>) case didFetchMessages(IdentifiedArrayOf<ChatState.Message>)
case sendTapped
case binding(BindingAction<ChatState>)
} }
public struct ChatEnvironment { public struct ChatEnvironment {
public init( public init(
messenger: Messenger, messenger: Messenger,
db: DBManagerGetDB, db: DBManagerGetDB,
sendMessage: SendMessage,
mainQueue: AnySchedulerOf<DispatchQueue>, mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue> bgQueue: AnySchedulerOf<DispatchQueue>
) { ) {
self.messenger = messenger self.messenger = messenger
self.db = db self.db = db
self.sendMessage = sendMessage
self.mainQueue = mainQueue self.mainQueue = mainQueue
self.bgQueue = bgQueue self.bgQueue = bgQueue
} }
public var messenger: Messenger public var messenger: Messenger
public var db: DBManagerGetDB public var db: DBManagerGetDB
public var sendMessage: SendMessage
public var mainQueue: AnySchedulerOf<DispatchQueue> public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue> public var bgQueue: AnySchedulerOf<DispatchQueue>
} }
...@@ -77,6 +86,7 @@ extension ChatEnvironment { ...@@ -77,6 +86,7 @@ extension ChatEnvironment {
public static let unimplemented = ChatEnvironment( public static let unimplemented = ChatEnvironment(
messenger: .unimplemented, messenger: .unimplemented,
db: .unimplemented, db: .unimplemented,
sendMessage: .unimplemented,
mainQueue: .unimplemented, mainQueue: .unimplemented,
bgQueue: .unimplemented bgQueue: .unimplemented
) )
...@@ -126,5 +136,32 @@ public let chatReducer = Reducer<ChatState, ChatAction, ChatEnvironment> ...@@ -126,5 +136,32 @@ public let chatReducer = Reducer<ChatState, ChatAction, ChatEnvironment>
case .didFetchMessages(let messages): case .didFetchMessages(let messages):
state.messages = messages state.messages = messages
return .none return .none
case .sendTapped:
let text = state.text
let chatId = state.id
state.text = ""
return Effect.run { subscriber in
switch chatId {
case .contact(let recipientId):
env.sendMessage(
text: text,
to: recipientId,
onError: { error in
// TODO: handle error
print("^^^ ERROR: \(error)")
}
)
}
subscriber.send(completion: .finished)
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .binding(_):
return .none
} }
} }
.binding()
...@@ -13,11 +13,13 @@ public struct ChatView: View { ...@@ -13,11 +13,13 @@ public struct ChatView: View {
var myContactId: Data? var myContactId: Data?
var messages: IdentifiedArrayOf<ChatState.Message> var messages: IdentifiedArrayOf<ChatState.Message>
var failure: String? var failure: String?
var text: String
init(state: ChatState) { init(state: ChatState) {
myContactId = state.myContactId myContactId = state.myContactId
messages = state.messages messages = state.messages
failure = state.failure failure = state.failure
text = state.text
} }
} }
...@@ -52,11 +54,14 @@ public struct ChatView: View { ...@@ -52,11 +54,14 @@ public struct ChatView: View {
VStack(spacing: 0) { VStack(spacing: 0) {
Divider() Divider()
HStack { HStack {
TextField("Text", text: .constant("")) TextField("Text", text: viewStore.binding(
get: \.text,
send: { ChatAction.set(\.$text, $0) }
))
.textFieldStyle(.roundedBorder) .textFieldStyle(.roundedBorder)
Button { Button {
viewStore.send(.sendTapped)
} label: { } label: {
Image(systemName: "paperplane.fill") Image(systemName: "paperplane.fill")
} }
......
...@@ -130,4 +130,36 @@ final class ChatFeatureTests: XCTestCase { ...@@ -130,4 +130,36 @@ final class ChatFeatureTests: XCTestCase {
$0.failure = error.localizedDescription $0.failure = error.localizedDescription
} }
} }
func testSend() {
struct SendMessageParams: Equatable {
var text: String
var recipientId: Data
}
var didSendMessageWithParams: [SendMessageParams] = []
let store = TestStore(
initialState: ChatState(id: .contact("contact-id".data(using: .utf8)!)),
reducer: chatReducer,
environment: .unimplemented
)
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.sendMessage.run = { text, recipientId, _ in
didSendMessageWithParams.append(.init(text: text, recipientId: recipientId))
}
store.send(.set(\.$text, "Hello")) {
$0.text = "Hello"
}
store.send(.sendTapped) {
$0.text = ""
}
XCTAssertNoDifference(didSendMessageWithParams, [
.init(text: "Hello", recipientId: "contact-id".data(using: .utf8)!)
])
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment