Skip to content

Commit 2ff40f2

Browse files
authored
Merge pull request #797 from GetStream/add/allow-pasting-images-to-composer
2 parents b12468a + 85ed8f8 commit 2ff40f2

File tree

5 files changed

+36
-2
lines changed

5 files changed

+36
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
33

44
# Upcoming
55

6-
### 🔄 Changed
6+
### ✅ Added
7+
- Allow pasting images to the composer [#797](https://github.com/GetStream/stream-chat-swiftui/pull/797)
78

89
# [4.76.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.76.0)
910
_March 31, 2025_

Sources/StreamChatSwiftUI/ChatChannel/Composer/ComposerTextInputView.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import UIKit
77

88
/// SwiftUI wrapper for a text field with multiple rows.
99
struct ComposerTextInputView: UIViewRepresentable {
10-
10+
@EnvironmentObject var composerViewModel: MessageComposerViewModel
1111
@Injected(\.utils) private var utils
1212

1313
@Binding var text: String
@@ -33,6 +33,9 @@ struct ComposerTextInputView: UIViewRepresentable {
3333
inputTextView.placeholderLabel.text = placeholder
3434
inputTextView.contentInsetAdjustmentBehavior = .never
3535
inputTextView.setContentCompressionResistancePriority(.streamLow, for: .horizontal)
36+
inputTextView.onImagePasted = {
37+
composerViewModel.imagePasted($0)
38+
}
3639

3740
if utils.messageListConfig.becomesFirstResponderOnOpen {
3841
inputTextView.becomeFirstResponder()

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ public struct ComposerInputView<Factory: ViewFactory>: View, KeyboardReadable {
374374
maxMessageLength: maxMessageLength,
375375
currentHeight: textFieldHeight
376376
)
377+
.environmentObject(viewModel)
377378
.accessibilityIdentifier("ComposerTextInputView")
378379
.accessibilityElement(children: .contain)
379380
.frame(height: textFieldHeight)

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,20 @@ open class MessageComposerViewModel: ObservableObject {
510510
addedAssets = images
511511
}
512512

513+
public func imagePasted(_ image: UIImage) {
514+
guard let imageURL = try? image.saveAsJpgToTemporaryUrl() else {
515+
log.error("Failed to write image to local temporary file")
516+
return
517+
}
518+
let addedImage = AddedAsset(
519+
image: image,
520+
id: UUID().uuidString,
521+
url: imageURL,
522+
type: .image
523+
)
524+
addedAssets.append(addedImage)
525+
}
526+
513527
public func removeAttachment(with id: String) {
514528
if id.isURL, let url = URL(string: id) {
515529
var urls = [URL]()

Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class InputTextView: UITextView, AccessibilityView {
5252
}
5353
}
5454
}
55+
56+
var onImagePasted: ((UIImage) -> Void)?
5557

5658
override open func didMoveToSuperview() {
5759
super.didMoveToSuperview()
@@ -143,9 +145,22 @@ class InputTextView: UITextView, AccessibilityView {
143145

144146
override open func paste(_ sender: Any?) {
145147
super.paste(sender)
148+
if let pastedImage = UIPasteboard.general.image,
149+
let onImagePasted {
150+
onImagePasted(pastedImage)
151+
return
152+
}
146153
handleTextChange()
147154
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
148155
self?.scrollToBottom()
149156
}
150157
}
158+
159+
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
160+
if action == #selector(paste(_:)) && onImagePasted != nil && UIPasteboard.general.image != nil {
161+
return true
162+
} else {
163+
return super.canPerformAction(action, withSender: sender)
164+
}
165+
}
151166
}

0 commit comments

Comments
 (0)