From 67e362d6dab56b8ed2a7054b25996194701039be Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Wed, 26 Feb 2025 11:08:56 -0500 Subject: [PATCH] Re-add rich-text formatting actions in Compose --- .../Sources/ComposeUI/ComposeInput.swift | 1 + .../ComposeUI/Views/NewMainTextView.swift | 54 +++++++++++++++---- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/Packages/ComposeUI/Sources/ComposeUI/ComposeInput.swift b/Packages/ComposeUI/Sources/ComposeUI/ComposeInput.swift index b1f32f3a..4759ba26 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/ComposeInput.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/ComposeInput.swift @@ -10,6 +10,7 @@ import Combine import UIKit import SwiftUI +@MainActor protocol ComposeInput: AnyObject, ObservableObject { var toolbarElements: [ToolbarElement] { get } var textInputMode: UITextInputMode? { get } diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/NewMainTextView.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/NewMainTextView.swift index 8335f2d9..ffc9cad5 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/NewMainTextView.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/NewMainTextView.swift @@ -52,6 +52,7 @@ private struct NewMainTextViewRepresentable: UIViewRepresentable { } view.addInteraction(UIDropInteraction(delegate: context.coordinator)) view.delegate = context.coordinator + context.coordinator.textView = view view.adjustsFontForContentSizeCategory = true view.textContainer.lineBreakMode = .byWordWrapping view.isScrollEnabled = false @@ -110,9 +111,9 @@ private struct NewMainTextViewRepresentable: UIViewRepresentable { func makeCoordinator() -> WrappedTextViewCoordinator { let coordinator = WrappedTextViewCoordinator(value: $value, handleAttachmentDrop: handleAttachmentDrop) -// DispatchQueue.main.async { -// inputBox.wrappedValue = coordinator -// } + DispatchQueue.main.async { + inputBox.wrappedValue = coordinator + } return coordinator } @@ -127,7 +128,7 @@ private struct NewMainTextViewRepresentable: UIViewRepresentable { // laxer than the CharacterCounter regex, because we want to find mentions that are being typed but aren't yet complete (e.g., "@a@b") private let mentionRegex = try! NSRegularExpression(pattern: "(@[a-z0-9_]+)(?:@[a-z0-9\\-\\.]+)?", options: .caseInsensitive) -private final class WrappedTextViewCoordinator: NSObject { +private final class WrappedTextViewCoordinator: NSObject, ObservableObject { private static let attachment: NSTextAttachment = { let font = UIFont.systemFont(ofSize: 20) let size = /*1.4 * */font.capHeight @@ -144,7 +145,10 @@ private final class WrappedTextViewCoordinator: NSObject { var value: Binding var handleAttachmentDrop: ([NSItemProvider]) -> Void + weak var textView: UITextView? + @Published var autocompleteState: AutocompleteState? + init(value: Binding, handleAttachmentDrop: @escaping ([NSItemProvider]) -> Void) { self.value = value self.handleAttachmentDrop = handleAttachmentDrop @@ -293,9 +297,41 @@ extension WrappedTextViewCoordinator: UITextViewDelegate { } } -//extension WrappedTextViewCoordinator: ComposeInput { -// -//} +extension WrappedTextViewCoordinator: ComposeInput { + var autocompleteStatePublisher: Published.Publisher { $autocompleteState } + + var toolbarElements: [ToolbarElement] { + [.emojiPicker, .formattingButtons] + } + + var textInputMode: UITextInputMode? { + textView?.textInputMode + } + + func applyFormat(_ format: StatusFormat) { + guard let textView, + textView.isFirstResponder, + let insertionResult = format.insertionResult(for: Preferences.shared.statusContentType) else { + return + } + + let currentSelectedRange = textView.selectedRange + let utf16 = textView.text.utf16 + let start = utf16.index(utf16.startIndex, offsetBy: currentSelectedRange.location) + let end = utf16.index(start, offsetBy: currentSelectedRange.length) + let selectedText = utf16[start..