Files
bsky-social-app/patches/expo-paste-input@0.1.15.patch
T
Samuel Newman ac01992a76 run script
2026-05-18 19:33:08 +03:00

136 lines
4.9 KiB
Diff

diff --git a/ios/ExpoPasteInputView.swift b/ios/ExpoPasteInputView.swift
index 2164aec4ec1d8380fd690850aec0931e4f65194d..d216db6d2927c9cbb1eb5e10783ff1cc83c103e7 100644
--- a/ios/ExpoPasteInputView.swift
+++ b/ios/ExpoPasteInputView.swift
@@ -511,14 +511,17 @@ class ExpoPasteInputView: ExpoView {
var attachmentRanges: [NSRange] = []
var mediaPayloads: [MediaPayload] = []
+ // Only track ranges for attachments we successfully extract a real payload
+ // from. Attachments without a payload (e.g. iOS dictation placeholders)
+ // are left alone — sanitizing them would delete characters the system
+ // manages itself, and emitting "unsupported" would raise a spurious error.
attributedText.enumerateAttribute(.attachment, in: NSRange(location: 0, length: attributedText.length), options: []) { value, range, _ in
guard let attachment = value as? NSTextAttachment else {
return
}
- attachmentRanges.append(range)
-
if let payload = self.extractMediaPayload(from: attachment, textView: textView, range: range) {
+ attachmentRanges.append(range)
mediaPayloads.append(payload)
}
}
@@ -529,9 +532,8 @@ class ExpoPasteInputView: ExpoView {
return
}
- attachmentRanges.append(range)
-
if let payload = self.extractMediaPayload(from: adaptiveGlyph) {
+ attachmentRanges.append(range)
mediaPayloads.append(payload)
}
}
@@ -539,17 +541,12 @@ class ExpoPasteInputView: ExpoView {
attachmentRanges = uniqueRanges(attachmentRanges)
- guard !attachmentRanges.isEmpty else {
+ guard !mediaPayloads.isEmpty else {
return
}
sanitizeAttachments(in: textView, ranges: attachmentRanges)
- guard !mediaPayloads.isEmpty else {
- handleUnsupportedPaste()
- return
- }
-
emitImagesAsync(for: mediaPayloads)
}
@@ -651,6 +648,11 @@ class ExpoPasteInputView: ExpoView {
}
private func extractMediaPayload(from attachment: NSTextAttachment, textView: UITextView, range: NSRange) -> MediaPayload? {
+ // Only accept attachments that carry real image payloads. We intentionally
+ // do not fall back to `image(forBounds:)` or rendering the text view's
+ // hierarchy, because system-inserted attachments (e.g. the iOS dictation
+ // placeholder) draw themselves via those paths and would cause us to
+ // emit a screenshot of the composer as a "pasted image".
if let fileWrapperData = attachment.fileWrapper?.regularFileContents,
let payload = extractMediaPayload(fromData: fileWrapperData) {
return payload
@@ -667,20 +669,6 @@ class ExpoPasteInputView: ExpoView {
return .image(image)
}
- let attachmentBounds = attachment.bounds.size.width > 0 && attachment.bounds.size.height > 0
- ? attachment.bounds
- : CGRect(origin: .zero, size: CGSize(width: 128, height: 128))
-
- if let image = attachment.image(forBounds: attachmentBounds, textContainer: textView.textContainer, characterIndex: range.location),
- image.size.width > 0,
- image.size.height > 0 {
- return .image(image)
- }
-
- if let renderedImage = renderTextAttachment(in: textView, range: range) {
- return .image(renderedImage)
- }
-
return nil
}
@@ -701,47 +689,6 @@ class ExpoPasteInputView: ExpoView {
return .imageData(data)
}
- private func renderTextAttachment(in textView: UITextView, range: NSRange) -> UIImage? {
- let glyphRange = textView.layoutManager.glyphRange(forCharacterRange: range, actualCharacterRange: nil)
- var rect = textView.layoutManager.boundingRect(forGlyphRange: glyphRange, in: textView.textContainer)
-
- rect.origin.x += textView.textContainerInset.left - textView.contentOffset.x
- rect.origin.y += textView.textContainerInset.top - textView.contentOffset.y
- rect = rect.integral
-
- guard rect.width > 1, rect.height > 1 else {
- return nil
- }
-
- let format = UIGraphicsImageRendererFormat.default()
- format.scale = textView.window?.screen.scale ?? UIScreen.main.scale
- format.opaque = false
-
- let image = UIGraphicsImageRenderer(size: rect.size, format: format).image { _ in
- let drawRect = CGRect(
- origin: CGPoint(x: -rect.origin.x, y: -rect.origin.y),
- size: textView.bounds.size
- )
-
- if textView.window != nil {
- textView.drawHierarchy(in: drawRect, afterScreenUpdates: false)
- } else {
- guard let context = UIGraphicsGetCurrentContext() else {
- return
- }
-
- context.translateBy(x: -rect.origin.x, y: -rect.origin.y)
- textView.layer.render(in: context)
- }
- }
-
- guard image.size.width > 0, image.size.height > 0 else {
- return nil
- }
-
- return image
- }
-
@available(iOS 18.0, *)
private func handleAdaptiveImageGlyphInsertion(_ adaptiveGlyph: NSAdaptiveImageGlyph) -> Bool {
guard let payload = extractMediaPayload(from: adaptiveGlyph) else {