From ba9780fb176011fb81ec8dc654e7825ba1acdfa6 Mon Sep 17 00:00:00 2001 From: Swift Coder Date: Tue, 8 Oct 2024 13:52:30 -0400 Subject: [PATCH 1/3] Allow-pasting-image-option --- damus/Models/ImageUploadModel.swift | 7 +++++ damus/Views/AttachMediaUtility.swift | 2 ++ damus/Views/PostView.swift | 15 ++++++++++- damus/Views/TextViewWrapper.swift | 38 +++++++++++++++++++++++++++- 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/damus/Models/ImageUploadModel.swift b/damus/Models/ImageUploadModel.swift index a8c9ce72..782991bc 100644 --- a/damus/Models/ImageUploadModel.swift +++ b/damus/Models/ImageUploadModel.swift @@ -18,6 +18,7 @@ enum PreUploadedMedia { enum MediaUpload { case image(URL) + case uiImage(UIImage) case video(URL) var genericFileName: String { @@ -30,6 +31,8 @@ enum MediaUpload { return url.pathExtension case .video(let url): return url.pathExtension + case .uiImage(_): + return "jpeg" } } @@ -39,6 +42,8 @@ enum MediaUpload { return url case .video(let url): return url + case .uiImage(_): + return URL(string: "about:blank")! // Safe placeholder URL } } @@ -72,6 +77,8 @@ enum MediaUpload { return "image/jpg" case .video: return "video/mp4" + case .uiImage(_): + return "image/jpg" } } } diff --git a/damus/Views/AttachMediaUtility.swift b/damus/Views/AttachMediaUtility.swift index 66862302..7ac0ca67 100644 --- a/damus/Views/AttachMediaUtility.swift +++ b/damus/Views/AttachMediaUtility.swift @@ -61,6 +61,8 @@ func create_upload_request(mediaToUpload: MediaUpload, mediaUploader: MediaUploa } catch { return .failed(error) } + case .uiImage(_): + return .failed(nil) // no need to handle for uiimage case } guard let mediaData else { diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift index 2aab4298..1f4e48f0 100644 --- a/damus/Views/PostView.swift +++ b/damus/Views/PostView.swift @@ -54,6 +54,8 @@ struct PostView: View { @State var error: String? = nil @State var uploadedMedias: [UploadedMedia] = [] @State var image_upload_confirm: Bool = false + @State var imagePastedFromPasteboard: UIImage? = nil + @State var imageUploadConfirmPasteboard: Bool = false @State var references: [RefId] = [] @State var filtered_pubkeys: Set = [] @State var focusWordAttributes: (String?, NSRange?) = (nil, nil) @@ -246,7 +248,9 @@ struct PostView: View { TextViewWrapper( attributedText: $post, textHeight: $textHeight, - initialTextSuffix: initial_text_suffix, + initialTextSuffix: initial_text_suffix, + imagePastedFromPasteboard: $imagePastedFromPasteboard, + imageUploadConfirmPasteboard: $imageUploadConfirmPasteboard, cursorIndex: newCursorIndex, getFocusWordForMention: { word, range in focusWordAttributes = (word, range) @@ -463,6 +467,15 @@ struct PostView: View { self.attach_media = true } } + .alert(NSLocalizedString("Are you sure you want to upload this media?", comment: "Alert message asking if the user wants to upload media."), isPresented: $imageUploadConfirmPasteboard) { + Button(NSLocalizedString("Upload", comment: "Button to proceed with uploading."), role: .none) { + if let image = imagePastedFromPasteboard, + let mediaToUpload = generateMediaUpload(PreUploadedMedia.uiimage(image)) { + self.handle_upload(media: mediaToUpload) + } + } + Button(NSLocalizedString("Cancel", comment: "Button to cancel the upload."), role: .cancel) {} + } .onAppear() { let loaded_draft = load_draft() diff --git a/damus/Views/TextViewWrapper.swift b/damus/Views/TextViewWrapper.swift index 20ae430e..46a56677 100644 --- a/damus/Views/TextViewWrapper.swift +++ b/damus/Views/TextViewWrapper.swift @@ -12,13 +12,16 @@ struct TextViewWrapper: UIViewRepresentable { @EnvironmentObject var tagModel: TagModel @Binding var textHeight: CGFloat? let initialTextSuffix: String? + @Binding var imagePastedFromPasteboard: UIImage? + @Binding var imageUploadConfirmPasteboard: Bool let cursorIndex: Int? var getFocusWordForMention: ((String?, NSRange?) -> Void)? = nil let updateCursorPosition: ((Int) -> Void) func makeUIView(context: Context) -> UITextView { - let textView = UITextView() + let textView = CustomPostTextView(imagePastedFromPasteboard: $imagePastedFromPasteboard, + imageUploadConfirm: $imageUploadConfirmPasteboard) textView.backgroundColor = UIColor(DamusColors.adaptableWhite) textView.delegate = context.coordinator @@ -240,3 +243,36 @@ struct TextViewWrapper: UIViewRepresentable { } } +class CustomPostTextView: UITextView { + @Binding var imagePastedFromPasteboard: UIImage? + @Binding var imageUploadConfirm: Bool + + // Custom initializer + init(imagePastedFromPasteboard: Binding, imageUploadConfirm: Binding) { + self._imagePastedFromPasteboard = imagePastedFromPasteboard + self._imageUploadConfirm = imageUploadConfirm + super.init(frame: .zero, textContainer: nil) + } + + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + // Override canPerformAction to enable image pasting + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + if action == #selector(UIResponderStandardEditActions.paste(_:)), + UIPasteboard.general.image != nil { + return true // Show `Paste` option while long-pressing if there is an image present in the clipboard + } + return super.canPerformAction(action, withSender: sender) // Default behavior for other actions + } + + // Override paste to handle image pasting + override func paste(_ sender: Any?) { + if let image = UIPasteboard.general.image { + imagePastedFromPasteboard = image + // Show alert view in PostView for Confirming upload + imageUploadConfirm = true + } else { + super.paste(sender) // Fall back to default paste behavior if no image + } + } +} From 847ae7b39698eae349fd0903e299f07b1f7dae06 Mon Sep 17 00:00:00 2001 From: Swift Coder Date: Tue, 8 Oct 2024 14:45:34 -0400 Subject: [PATCH 2/3] Documenting --- damus/Views/PostView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift index 1f4e48f0..2850b327 100644 --- a/damus/Views/PostView.swift +++ b/damus/Views/PostView.swift @@ -467,6 +467,7 @@ struct PostView: View { self.attach_media = true } } + // This alert seeks confirmation about Image-upload when user taps Paste option .alert(NSLocalizedString("Are you sure you want to upload this media?", comment: "Alert message asking if the user wants to upload media."), isPresented: $imageUploadConfirmPasteboard) { Button(NSLocalizedString("Upload", comment: "Button to proceed with uploading."), role: .none) { if let image = imagePastedFromPasteboard, From 686d6d6e926767c7efbad9a576a61030240ed54b Mon Sep 17 00:00:00 2001 From: Swift Coder Date: Tue, 8 Oct 2024 17:05:04 -0400 Subject: [PATCH 3/3] Code optimization --- damus/Models/ImageUploadModel.swift | 7 ------- damus/Views/AttachMediaUtility.swift | 2 -- 2 files changed, 9 deletions(-) diff --git a/damus/Models/ImageUploadModel.swift b/damus/Models/ImageUploadModel.swift index 782991bc..a8c9ce72 100644 --- a/damus/Models/ImageUploadModel.swift +++ b/damus/Models/ImageUploadModel.swift @@ -18,7 +18,6 @@ enum PreUploadedMedia { enum MediaUpload { case image(URL) - case uiImage(UIImage) case video(URL) var genericFileName: String { @@ -31,8 +30,6 @@ enum MediaUpload { return url.pathExtension case .video(let url): return url.pathExtension - case .uiImage(_): - return "jpeg" } } @@ -42,8 +39,6 @@ enum MediaUpload { return url case .video(let url): return url - case .uiImage(_): - return URL(string: "about:blank")! // Safe placeholder URL } } @@ -77,8 +72,6 @@ enum MediaUpload { return "image/jpg" case .video: return "video/mp4" - case .uiImage(_): - return "image/jpg" } } } diff --git a/damus/Views/AttachMediaUtility.swift b/damus/Views/AttachMediaUtility.swift index 7ac0ca67..66862302 100644 --- a/damus/Views/AttachMediaUtility.swift +++ b/damus/Views/AttachMediaUtility.swift @@ -61,8 +61,6 @@ func create_upload_request(mediaToUpload: MediaUpload, mediaUploader: MediaUploa } catch { return .failed(error) } - case .uiImage(_): - return .failed(nil) // no need to handle for uiimage case } guard let mediaData else {