From 71a57e9859646c924346fe1c42d3bf3f50300833 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 11 Dec 2022 12:54:25 -0500 Subject: [PATCH] Fix images copied from Safari pasting as URLs Closes #301 --- Tusker/Screens/Compose/ComposeUIState.swift | 1 + Tusker/Screens/Compose/ComposeView.swift | 18 ++++++++++++++++- .../Screens/Compose/MainComposeTextView.swift | 20 ++++++++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Tusker/Screens/Compose/ComposeUIState.swift b/Tusker/Screens/Compose/ComposeUIState.swift index ca8b24d7..f5d40ffc 100644 --- a/Tusker/Screens/Compose/ComposeUIState.swift +++ b/Tusker/Screens/Compose/ComposeUIState.swift @@ -16,6 +16,7 @@ protocol ComposeUIStateDelegate: AnyObject { func presentAssetPickerSheet() func presentComposeDrawing() func selectDraft(_ draft: Draft) + func paste(itemProviders: [NSItemProvider]) } class ComposeUIState: ObservableObject { diff --git a/Tusker/Screens/Compose/ComposeView.swift b/Tusker/Screens/Compose/ComposeView.swift index a5ef90bb..db54926c 100644 --- a/Tusker/Screens/Compose/ComposeView.swift +++ b/Tusker/Screens/Compose/ComposeView.swift @@ -72,8 +72,24 @@ struct ComposeView: View { return attachmentIds.contains { uiState.attachmentsMissingDescriptions.contains($0) } } + private var validAttachmentCombination: Bool { + if !mastodonController.instanceFeatures.mastodonAttachmentRestrictions { + return true + } else if draft.attachments.contains(where: { $0.data.type == .video }) && draft.attachments.count > 1 { + return false + } else if draft.attachments.count > 4 { + return false + } + return true + } + private var postButtonEnabled: Bool { - draft.hasContent && charactersRemaining >= 0 && !isPosting && !requiresAttachmentDescriptions && (draft.poll == nil || draft.poll!.options.allSatisfy { !$0.text.isEmpty }) + draft.hasContent + && charactersRemaining >= 0 + && !isPosting + && !requiresAttachmentDescriptions + && validAttachmentCombination + && (draft.poll == nil || draft.poll!.options.allSatisfy { !$0.text.isEmpty }) } var body: some View { diff --git a/Tusker/Screens/Compose/MainComposeTextView.swift b/Tusker/Screens/Compose/MainComposeTextView.swift index 7bef6b67..830b3f71 100644 --- a/Tusker/Screens/Compose/MainComposeTextView.swift +++ b/Tusker/Screens/Compose/MainComposeTextView.swift @@ -83,7 +83,7 @@ struct MainComposeWrappedTextView: UIViewRepresentable { @Environment(\.isEnabled) var isEnabled: Bool func makeUIView(context: Context) -> UITextView { - let textView = WrappedTextView() + let textView = WrappedTextView(uiState: uiState) textView.delegate = context.coordinator textView.isEditable = true textView.backgroundColor = .clear @@ -128,6 +128,16 @@ struct MainComposeWrappedTextView: UIViewRepresentable { class WrappedTextView: UITextView { private let formattingActions = [#selector(toggleBoldface(_:)), #selector(toggleItalics(_:))] + unowned var uiState: ComposeUIState + + init(uiState: ComposeUIState) { + self.uiState = uiState + super.init(frame: .zero, textContainer: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { if formattingActions.contains(action) { @@ -154,6 +164,14 @@ struct MainComposeWrappedTextView: UIViewRepresentable { } } + override func paste(_ sender: Any?) { + if UIPasteboard.general.contains(pasteboardTypes: CompositionAttachment.readableTypeIdentifiersForItemProvider) { + uiState.delegate?.paste(itemProviders: UIPasteboard.general.itemProviders) + } else { + super.paste(sender) + } + } + } class Coordinator: NSObject, UITextViewDelegate, ComposeInput, ComposeTextViewCaretScrolling {