SGToolbar for media

This commit is contained in:
Kylmakalle 2025-01-26 15:13:51 +02:00
parent 9e1acf72dd
commit 2a1b4bc828

View File

@ -1704,11 +1704,129 @@ extension TextFieldComponent.InputState {
extension TextFieldComponent.View { extension TextFieldComponent.View {
func sgToolbarAction(_ action: String) { func sgToolbarAction(_ action: String) {
switch action { switch action {
case "quote":
self.sgSelectLastWordIfIdle()
self.toggleAttribute(key: ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote, isCollapsed: false))
case "spoiler":
self.sgSelectLastWordIfIdle()
self.toggleAttribute(key: ChatTextInputAttributes.spoiler)
case "bold":
self.sgSelectLastWordIfIdle()
self.toggleAttribute(key: ChatTextInputAttributes.bold)
case "italic":
self.sgSelectLastWordIfIdle()
self.toggleAttribute(key: ChatTextInputAttributes.italic)
case "monospace":
self.sgSelectLastWordIfIdle()
self.toggleAttribute(key: ChatTextInputAttributes.monospace)
case "link":
self.sgSelectLastWordIfIdle()
self.openLinkEditing()
case "strikethrough":
self.sgSelectLastWordIfIdle()
self.toggleAttribute(key: ChatTextInputAttributes.strikethrough)
case "underline":
self.sgSelectLastWordIfIdle()
self.toggleAttribute(key: ChatTextInputAttributes.underline)
case "code":
self.sgSelectLastWordIfIdle()
self.toggleAttribute(key: ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .code(language: nil), isCollapsed: false))
case "newline":
self.sgSetNewLine()
case "clearFormatting":
self.updateInputState { current in
return current.clearFormattingAttributes()
}
default: default:
print("action: \(action)") assert(false, "Unhandled action \(action)")
// assert(false, "Unhandled action \(action)") }
}
func sgSelectLastWordIfIdle() {
self.updateInputState { current in
// No changes to current selection
if !current.selectionRange.isEmpty {
return current
}
let inputText = (current.inputText.mutableCopy() as? NSMutableAttributedString) ?? NSMutableAttributedString()
// If text is empty or cursor is at the start, return current state
guard inputText.length > 0, current.selectionRange.lowerBound > 0 else {
return current
}
let plainText = inputText.string
let nsString = plainText as NSString
// Create character set for word boundaries
let wordBoundaries = CharacterSet.whitespacesAndNewlines
// Start from cursor position instead of end of text
var endIndex = current.selectionRange.lowerBound - 1
// Find last non-whitespace character before cursor
while endIndex >= 0 &&
(nsString.substring(with: NSRange(location: endIndex, length: 1)) as NSString)
.rangeOfCharacter(from: wordBoundaries).location != NSNotFound {
endIndex -= 1
}
// If we only had whitespace before cursor, return current state
guard endIndex >= 0 else {
return current
}
// Find start of the current word by looking backwards for whitespace
var startIndex = endIndex
while startIndex > 0 {
let char = nsString.substring(with: NSRange(location: startIndex - 1, length: 1))
if (char as NSString).rangeOfCharacter(from: wordBoundaries).location != NSNotFound {
break
}
startIndex -= 1
}
// Create range for the word at cursor
let wordLength = endIndex - startIndex + 1
let wordRange = NSRange(location: startIndex, length: wordLength)
// Create new selection range
let newSelectionRange = wordRange.location ..< (wordRange.location + wordLength)
return TextFieldComponent.InputState(inputText: inputText, selectionRange: newSelectionRange)
}
}
func sgSetNewLine() {
self.updateInputState { current in
let inputText = (current.inputText.mutableCopy() as? NSMutableAttributedString) ?? NSMutableAttributedString()
// Check if there's selected text
let hasSelection = current.selectionRange.count > 0
if hasSelection {
// Move selected text to new line
let selectedText = inputText.attributedSubstring(from: NSRange(current.selectionRange))
let newLineAttr = NSAttributedString(string: "\n")
// Insert newline and selected text
inputText.replaceCharacters(in: NSRange(current.selectionRange), with: newLineAttr)
inputText.insert(selectedText, at: current.selectionRange.lowerBound + 1)
// Update selection range to end of moved text
let newPosition = current.selectionRange.lowerBound + 1 + selectedText.length
return TextFieldComponent.InputState(inputText: inputText, selectionRange: newPosition ..< newPosition)
} else {
// Simple newline insertion at current position
let attributedString = NSAttributedString(string: "\n")
inputText.replaceCharacters(in: NSRange(current.selectionRange), with: attributedString)
// Update cursor position
let newPosition = current.selectionRange.lowerBound + attributedString.length
return TextFieldComponent.InputState(inputText: inputText, selectionRange: newPosition ..< newPosition)
}
} }
} }
} }