Re-add rich-text formatting actions in Compose

This commit is contained in:
Shadowfacts 2025-02-26 11:08:56 -05:00
parent 2178621350
commit 67e362d6da
2 changed files with 46 additions and 9 deletions

View File

@ -10,6 +10,7 @@ import Combine
import UIKit import UIKit
import SwiftUI import SwiftUI
@MainActor
protocol ComposeInput: AnyObject, ObservableObject { protocol ComposeInput: AnyObject, ObservableObject {
var toolbarElements: [ToolbarElement] { get } var toolbarElements: [ToolbarElement] { get }
var textInputMode: UITextInputMode? { get } var textInputMode: UITextInputMode? { get }

View File

@ -52,6 +52,7 @@ private struct NewMainTextViewRepresentable: UIViewRepresentable {
} }
view.addInteraction(UIDropInteraction(delegate: context.coordinator)) view.addInteraction(UIDropInteraction(delegate: context.coordinator))
view.delegate = context.coordinator view.delegate = context.coordinator
context.coordinator.textView = view
view.adjustsFontForContentSizeCategory = true view.adjustsFontForContentSizeCategory = true
view.textContainer.lineBreakMode = .byWordWrapping view.textContainer.lineBreakMode = .byWordWrapping
view.isScrollEnabled = false view.isScrollEnabled = false
@ -110,9 +111,9 @@ private struct NewMainTextViewRepresentable: UIViewRepresentable {
func makeCoordinator() -> WrappedTextViewCoordinator { func makeCoordinator() -> WrappedTextViewCoordinator {
let coordinator = WrappedTextViewCoordinator(value: $value, handleAttachmentDrop: handleAttachmentDrop) let coordinator = WrappedTextViewCoordinator(value: $value, handleAttachmentDrop: handleAttachmentDrop)
// DispatchQueue.main.async { DispatchQueue.main.async {
// inputBox.wrappedValue = coordinator inputBox.wrappedValue = coordinator
// } }
return 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") // 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 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 = { private static let attachment: NSTextAttachment = {
let font = UIFont.systemFont(ofSize: 20) let font = UIFont.systemFont(ofSize: 20)
let size = /*1.4 * */font.capHeight let size = /*1.4 * */font.capHeight
@ -144,6 +145,9 @@ private final class WrappedTextViewCoordinator: NSObject {
var value: Binding<String> var value: Binding<String>
var handleAttachmentDrop: ([NSItemProvider]) -> Void var handleAttachmentDrop: ([NSItemProvider]) -> Void
weak var textView: UITextView?
@Published var autocompleteState: AutocompleteState?
init(value: Binding<String>, handleAttachmentDrop: @escaping ([NSItemProvider]) -> Void) { init(value: Binding<String>, handleAttachmentDrop: @escaping ([NSItemProvider]) -> Void) {
self.value = value self.value = value
@ -293,9 +297,41 @@ extension WrappedTextViewCoordinator: UITextViewDelegate {
} }
} }
//extension WrappedTextViewCoordinator: ComposeInput { extension WrappedTextViewCoordinator: ComposeInput {
// var autocompleteStatePublisher: Published<AutocompleteState?>.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..<end]
textView.insertText(insertionResult.prefix + String(Substring(selectedText)) + insertionResult.suffix)
textView.selectedRange = NSRange(location: currentSelectedRange.location + insertionResult.insertionPoint, length: currentSelectedRange.length)
}
func beginAutocompletingEmoji() {
textView?.insertText(":")
}
func autocomplete(with string: String) {
textView?.autocomplete(with: string, permittedModes: .all, autocompleteState: &autocompleteState)
}
}
// Because of FB11790805, we can't handle drops for the entire screen. // Because of FB11790805, we can't handle drops for the entire screen.
// The onDrop modifier also doesn't work when applied to the NewMainTextView. // The onDrop modifier also doesn't work when applied to the NewMainTextView.
@ -327,11 +363,11 @@ private final class WrappedTextView: UITextView {
} }
override func toggleBoldface(_ sender: Any?) { override func toggleBoldface(_ sender: Any?) {
// TODO (delegate as! WrappedTextViewCoordinator).applyFormat(.bold)
} }
override func toggleItalics(_ sender: Any?) { override func toggleItalics(_ sender: Any?) {
// TODO (delegate as! WrappedTextViewCoordinator).applyFormat(.italics)
} }
override func validate(_ command: UICommand) { override func validate(_ command: UICommand) {