// // ComposeInput.swift // ComposeUI // // Created by Shadowfacts on 3/5/23. // import Foundation import Combine import UIKit import SwiftUI protocol ComposeInput: AnyObject, ObservableObject { var toolbarElements: [ToolbarElement] { get } var textInputMode: UITextInputMode? { get } var autocompleteState: AutocompleteState? { get } var autocompleteStatePublisher: Published.Publisher { get } func autocomplete(with string: String) func applyFormat(_ format: StatusFormat) func beginAutocompletingEmoji() } enum ToolbarElement { case emojiPicker case formattingButtons } private struct FocusedComposeInput: FocusedValueKey { typealias Value = (any ComposeInput)? } extension FocusedValues { // double optional is necessary pre-iOS 16 var composeInput: (any ComposeInput)?? { get { self[FocusedComposeInput.self] } set { self[FocusedComposeInput.self] = newValue } } } @propertyWrapper final class MutableObservableBox: ObservableObject { @Published var wrappedValue: Value init(wrappedValue: Value) { self.wrappedValue = wrappedValue } } private struct FocusedComposeInputBox: EnvironmentKey { static let defaultValue: MutableObservableBox<(any ComposeInput)?> = .init(wrappedValue: nil) } extension EnvironmentValues { var composeInputBox: MutableObservableBox<(any ComposeInput)?> { get { self[FocusedComposeInputBox.self] } set { self[FocusedComposeInputBox.self] = newValue } } } struct FocusedInputModifier: ViewModifier { @StateObject var box: MutableObservableBox<(any ComposeInput)?> = .init(wrappedValue: nil) func body(content: Content) -> some View { content .environment(\.composeInputBox, box) .focusedValue(\.composeInput, box.wrappedValue) } }