Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

# Upcoming

### ✅ Added
- Add support for pasting images into composer text input

### 🐞 Fixed
- Fix visibility of tabbar when reactions are shown [#750](https://github.com/GetStream/stream-chat-swiftui/pull/750)
### 🔄 Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct ComposerTextInputView: UIViewRepresentable {
var editable: Bool
var maxMessageLength: Int?
var currentHeight: CGFloat
var onImagePasted: ((UIImage) -> Void)?

func makeUIView(context: Context) -> InputTextView {
let inputTextView: InputTextView
Expand All @@ -33,6 +34,7 @@ struct ComposerTextInputView: UIViewRepresentable {
inputTextView.placeholderLabel.text = placeholder
inputTextView.contentInsetAdjustmentBehavior = .never
inputTextView.setContentCompressionResistancePriority(.streamLow, for: .horizontal)
inputTextView.onImagePasted = onImagePasted

if utils.messageListConfig.becomesFirstResponderOnOpen {
inputTextView.becomeFirstResponder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ public struct ComposerInputView<Factory: ViewFactory>: View, KeyboardReadable {
placeholder: isInCooldown ? L10n.Composer.Placeholder.slowMode : L10n.Composer.Placeholder.message,
editable: !isInCooldown,
maxMessageLength: maxMessageLength,
currentHeight: textFieldHeight
currentHeight: textFieldHeight,
onImagePasted: viewModel.imagePasted(_:)
)
.accessibilityIdentifier("ComposerTextInputView")
.accessibilityElement(children: .contain)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,20 @@ open class MessageComposerViewModel: ObservableObject {
addedAssets = images
}

public func imagePasted(_ image: UIImage) {
guard let imageURL = try? image.temporaryLocalFileUrl() else {
log.error("Failed to write image to local temporary file")
return
}
let addedImage = AddedAsset(
image: image,
id: UUID().uuidString,
url: imageURL,
type: .image
)
addedAssets.append(addedImage)
}

public func removeAttachment(with id: String) {
if id.isURL, let url = URL(string: id) {
var urls = [URL]()
Expand Down
6 changes: 4 additions & 2 deletions Sources/StreamChatSwiftUI/DefaultViewFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,8 @@ extension ViewFactory {
placeholder: String,
editable: Bool,
maxMessageLength: Int?,
currentHeight: CGFloat
currentHeight: CGFloat,
onImagePasted: ((UIImage) -> Void)?
) -> some View {
ComposerTextInputView(
text: text,
Expand All @@ -633,7 +634,8 @@ extension ViewFactory {
placeholder: placeholder,
editable: editable,
maxMessageLength: maxMessageLength,
currentHeight: currentHeight
currentHeight: currentHeight,
onImagePasted: onImagePasted
)
}

Expand Down
15 changes: 15 additions & 0 deletions Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class InputTextView: UITextView, AccessibilityView {
}
}
}

var onImagePasted: ((UIImage) -> Void)?

override open func didMoveToSuperview() {
super.didMoveToSuperview()
Expand Down Expand Up @@ -143,9 +145,22 @@ class InputTextView: UITextView, AccessibilityView {

override open func paste(_ sender: Any?) {
super.paste(sender)
if let pastedImage = UIPasteboard.general.image,
let onImagePasted {
onImagePasted(pastedImage)
return
}
handleTextChange()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
self?.scrollToBottom()
}
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(paste(_:)) && onImagePasted != nil && UIPasteboard.general.image != nil {
return true
} else {
return super.canPerformAction(action, withSender: sender)
}
}
}
3 changes: 2 additions & 1 deletion Sources/StreamChatSwiftUI/ViewFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,8 @@ public protocol ViewFactory: AnyObject {
placeholder: String,
editable: Bool,
maxMessageLength: Int?,
currentHeight: CGFloat
currentHeight: CGFloat,
onImagePasted: ((UIImage) -> Void)?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anh-ngquang Thanks for the PR 👍 The implementation will probably require some changes because this is a breaking change. We will take it from here once we have time. We are planning on working on this in the next sprint.

) -> ComposerTextInputViewType

associatedtype TrailingComposerViewType: View
Expand Down
3 changes: 2 additions & 1 deletion StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,8 @@ class ViewFactory_Tests: StreamChatTestCase {
placeholder: "Send a message",
editable: true,
maxMessageLength: nil,
currentHeight: 40
currentHeight: 40,
onImagePasted: nil
)

// Then
Expand Down