diff --git a/Tusker/Models/StatusFormat.swift b/Tusker/Models/StatusFormat.swift index da2096fc8c..47579a7ff9 100644 --- a/Tusker/Models/StatusFormat.swift +++ b/Tusker/Models/StatusFormat.swift @@ -10,7 +10,7 @@ import UIKit import Pachyderm enum StatusFormat: CaseIterable { - case italics, bold, strikethrough, code + case bold, italics, strikethrough, code var insertionResult: FormatInsertionResult? { switch Preferences.shared.statusContentType { diff --git a/Tusker/Screens/Compose/ComposeEmojiTextField.swift b/Tusker/Screens/Compose/ComposeEmojiTextField.swift index 3df54e0186..b3ac0ea1c7 100644 --- a/Tusker/Screens/Compose/ComposeEmojiTextField.swift +++ b/Tusker/Screens/Compose/ComposeEmojiTextField.swift @@ -111,6 +111,17 @@ struct ComposeEmojiTextField: UIViewRepresentable { self.updateAutocompleteState(textField: textField) } + func textField(_ textField: UITextField, editMenuForCharactersIn range: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu? { + var actions = suggestedActions + if range.length == 0 { + actions.append(UIAction(title: "Insert Emoji", image: UIImage(systemName: "face.smiling"), handler: { [weak self] _ in + self?.uiState.shouldEmojiAutocompletionBeginExpanded = true + self?.beginAutocompletingEmoji() + })) + } + return UIMenu(children: actions) + } + func beginAutocompletingEmoji() { textField?.insertText(":") } diff --git a/Tusker/Screens/Compose/MainComposeTextView.swift b/Tusker/Screens/Compose/MainComposeTextView.swift index 2ab8b872d7..8c8e613533 100644 --- a/Tusker/Screens/Compose/MainComposeTextView.swift +++ b/Tusker/Screens/Compose/MainComposeTextView.swift @@ -193,8 +193,42 @@ struct MainComposeWrappedTextView: UIViewRepresentable { self.updateAutocompleteState() } + func textView(_ textView: UITextView, editMenuForTextIn range: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu? { + var actions = suggestedActions + if Preferences.shared.statusContentType != .plain, + let index = suggestedActions.firstIndex(where: { ($0 as? UIMenu)?.identifier.rawValue == "com.apple.menu.format" }) { + if range.length > 0 { + let formatMenu = suggestedActions[index] as! UIMenu + let newFormatMenu = formatMenu.replacingChildren(StatusFormat.allCases.map { fmt in + UIAction(title: fmt.accessibilityLabel, image: fmt.image) { [weak self] _ in + self?.applyFormat(fmt) + } + }) + actions[index] = newFormatMenu + } else { + actions.remove(at: index) + } + } + if range.length == 0 { + actions.append(UIAction(title: "Insert Emoji", image: UIImage(systemName: "face.smiling"), handler: { [weak self] _ in + self?.uiState.shouldEmojiAutocompletionBeginExpanded = true + self?.beginAutocompletingEmoji() + })) + } + return UIMenu(children: actions) + } + func beginAutocompletingEmoji() { - textView?.insertText(":") + guard let textView = textView else { + return + } + var insertSpace = false + if let text = textView.text, + textView.selectedRange.upperBound > 0 { + let characterBeforeCursorIndex = text.utf16.index(before: text.utf16.index(text.startIndex, offsetBy: textView.selectedRange.upperBound)) + insertSpace = !text[characterBeforeCursorIndex].isWhitespace + } + textView.insertText((insertSpace ? " " : "") + ":") } func autocomplete(with string: String) {