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

Implement sending image in ChatFeature

parent b0361af7
No related branches found
No related tags found
2 merge requests!124File transfers example,!102Release 1.0.0
......@@ -99,6 +99,11 @@ extension AppEnvironment {
db: dbManager.getDB,
now: Date.init
),
sendImage: .live(
messenger: messenger,
db: dbManager.getDB,
now: Date.init
),
mainQueue: mainQueue,
bgQueue: bgQueue
)
......
......@@ -66,6 +66,7 @@ public enum ChatAction: Equatable, BindableAction {
case didFetchMessages(IdentifiedArrayOf<ChatState.Message>)
case sendTapped
case sendFailed(String)
case imagePicked(Data)
case dismissSendFailureTapped
case binding(BindingAction<ChatState>)
}
......@@ -75,12 +76,14 @@ public struct ChatEnvironment {
messenger: Messenger,
db: DBManagerGetDB,
sendMessage: SendMessage,
sendImage: SendImage,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>
) {
self.messenger = messenger
self.db = db
self.sendMessage = sendMessage
self.sendImage = sendImage
self.mainQueue = mainQueue
self.bgQueue = bgQueue
}
......@@ -88,6 +91,7 @@ public struct ChatEnvironment {
public var messenger: Messenger
public var db: DBManagerGetDB
public var sendMessage: SendMessage
public var sendImage: SendImage
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
}
......@@ -98,6 +102,7 @@ extension ChatEnvironment {
messenger: .unimplemented,
db: .unimplemented,
sendMessage: .unimplemented,
sendImage: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented
)
......@@ -196,6 +201,28 @@ public let chatReducer = Reducer<ChatState, ChatAction, ChatEnvironment>
state.sendFailure = failure
return .none
case .imagePicked(let data):
let chatId = state.id
return Effect.run { subscriber in
switch chatId {
case .contact(let recipientId):
env.sendImage(
data,
to: recipientId,
onError: { error in
subscriber.send(.sendFailed(error.localizedDescription))
},
completion: {
subscriber.send(completion: .finished)
}
)
}
return AnyCancellable {}
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
case .dismissSendFailureTapped:
state.sendFailure = nil
return .none
......
......@@ -8,6 +8,7 @@ public struct ChatView: View {
}
let store: Store<ChatState, ChatAction>
@State var isPresentingImagePicker = false
struct ViewState: Equatable {
var myContactId: Data?
......@@ -87,12 +88,28 @@ public struct ChatView: View {
))
.textFieldStyle(.roundedBorder)
Button {
viewStore.send(.sendTapped)
} label: {
Image(systemName: "paperplane.fill")
if viewStore.text.isEmpty == false {
Button {
viewStore.send(.sendTapped)
} label: {
Image(systemName: "paperplane.fill")
}
.buttonStyle(.borderedProminent)
} else {
Button {
isPresentingImagePicker = true
} label: {
Image(systemName: "photo.on.rectangle.angled")
}
.buttonStyle(.borderedProminent)
.sheet(isPresented: $isPresentingImagePicker) {
ImagePicker { image in
if let data = image.jpegData(compressionQuality: 0.7) {
viewStore.send(.imagePicked(data))
}
}
}
}
.buttonStyle(.borderedProminent)
}
.padding()
}
......
......@@ -240,4 +240,70 @@ final class ChatFeatureTests: XCTestCase {
$0.sendFailure = nil
}
}
func testSendImage() {
struct SendImageParams: Equatable {
var image: Data
var recipientId: Data
}
var didSendImageWithParams: [SendImageParams] = []
var sendImageCompletion: SendImage.Completion?
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.sendImage.run = { image, recipientId, _, completion in
didSendImageWithParams.append(.init(image: image, recipientId: recipientId))
sendImageCompletion = completion
}
let image = "image-data".data(using: .utf8)!
store.send(.imagePicked(image))
XCTAssertNoDifference(didSendImageWithParams, [
.init(image: image, recipientId: "contact-id".data(using: .utf8)!)
])
sendImageCompletion?()
}
func testSendImageFailure() {
var sendImageOnError: SendImage.OnError?
var sendImageCompletion: SendImage.Completion?
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.sendImage.run = { _, _, onError, completion in
sendImageOnError = onError
sendImageCompletion = completion
}
store.send(.imagePicked(Data()))
let error = NSError(domain: "test", code: 123)
sendImageOnError?(error)
store.receive(.sendFailed(error.localizedDescription)) {
$0.sendFailure = error.localizedDescription
}
sendImageCompletion?()
store.send(.dismissSendFailureTapped) {
$0.sendFailure = nil
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment