Toolbar for external attachments

This commit is contained in:
Kylmakalle 2025-01-21 00:27:43 +02:00
parent a7816937b0
commit 3a916c721d
2 changed files with 128 additions and 15 deletions

View File

@ -1,3 +1,8 @@
// MARK: Swiftgram
import SGInputToolbar
import SwiftUI
import SGSimpleSettings
import Foundation
import UIKit
import Display
@ -287,6 +292,10 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
private let hapticFeedback = HapticFeedback()
// MARK: Swiftgram
// private var toolbarHostingController: UIViewController? //Any? // UIHostingController<ChatToolbarView>?
private var toolbarNode: ASDisplayNode?
public var inputTextState: ChatTextInputState {
if let textInputNode = self.textInputNode {
let selectionRange: Range<Int> = textInputNode.selectedRange.location ..< (textInputNode.selectedRange.location + textInputNode.selectedRange.length)
@ -498,6 +507,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
self?.maxCaptionLength = maxCaptionLength
})
}
// MARK: Swiftgram
self.initToolbarIfNeeded()
}
public var sendPressed: ((NSAttributedString?) -> Void)?
@ -624,6 +636,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
textInputNode.view.addGestureRecognizer(recognizer)
textInputNode.textView.accessibilityHint = self.textPlaceholderNode.attributedText?.string
self.initToolbarIfNeeded()
}
private func textFieldMaxHeight(_ maxHeight: CGFloat, metrics: LayoutMetrics) -> CGFloat {
@ -927,7 +940,11 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
self.actionButtons.updateAccessibility()
return panelHeight
// MARK: Swiftgram
var toolbarOffset: CGFloat = 0.0
toolbarOffset = layoutToolbar(transition: transition, panelHeight: panelHeight, width: width, leftInset: leftInset, rightInset: rightInset)
return panelHeight + toolbarOffset
}
private func updateFieldAndButtonsLayout(inputHasText: Bool, panelHeight: CGFloat, transition: ContainedViewLayoutTransition) {
@ -1893,3 +1910,99 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
return nil
}
}
// MARK: Swiftgram
extension AttachmentTextInputPanelNode {
func initToolbarIfNeeded() {
guard #available(iOS 13.0, *) else { return }
guard SGSimpleSettings.shared.inputToolbar else { return }
guard SGSimpleSettings.shared.b else { return }
guard self.toolbarNode == nil else { return }
let toolbarView = ChatToolbarView(
onQuote: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesQuote(strongSelf)
},
onSpoiler: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesSpoiler(strongSelf)
},
onBold: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesBold(strongSelf)
},
onItalic: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesItalic(strongSelf)
},
onMonospace: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesMonospace(strongSelf)
},
onLink: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesLink(self!)
},
onStrikethrough: { [weak self]
in guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesStrikethrough(strongSelf)
},
onUnderline: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesUnderline(strongSelf)
},
onCode: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSelectLastWordIfIdle()
strongSelf.formatAttributesCodeBlock(strongSelf)
},
onNewLine: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.sgSetNewLine()
},
// TODO(swiftgram): Binding
showNewLine: .constant(true), //.constant(self.sendWithReturnKey)
onClearFormatting: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
return (chatTextInputAddFormattingAttribute(forceRemoveAll: true, current, attribute: ChatTextInputAttributes.allAttributes[0], value: nil), inputMode)
}
}
)
let toolbarHostingController = UIHostingController(rootView: toolbarView)
toolbarHostingController.view.backgroundColor = .clear
let toolbarNode = ASDisplayNode { toolbarHostingController.view }
self.toolbarNode = toolbarNode
// assigning toolbarHostingController bugs responsivness and overrides layout
// self.toolbarHostingController = toolbarHostingController
// Disable "Swipe to go back" gesture when touching scrollview
self.view.interactiveTransitionGestureRecognizerTest = { [weak self] point in
if let self, let _ = self.toolbarNode?.view.hitTest(point, with: nil) {
return false
}
return true
}
self.addSubnode(toolbarNode)
}
func layoutToolbar(transition: ContainedViewLayoutTransition, panelHeight: CGFloat, width: CGFloat, leftInset: CGFloat, rightInset: CGFloat) -> CGFloat {
var toolbarHeight: CGFloat = 0.0
var toolbarSpacing: CGFloat = 0.0
if let toolbarNode = self.toolbarNode {
toolbarHeight = 44.0
toolbarSpacing = 1.0
transition.updateFrame(node: toolbarNode, frame: CGRect(origin: CGPoint(x: leftInset, y: panelHeight + toolbarSpacing), size: CGSize(width: width - rightInset - leftInset, height: toolbarHeight)))
}
return toolbarHeight + toolbarSpacing
}
}

View File

@ -5148,21 +5148,21 @@ extension ChatTextInputPanelNode {
func layoutToolbar(transition: ContainedViewLayoutTransition, panelHeight: CGFloat, width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, displayBotStartButton: Bool) -> CGFloat {
var toolbarHeight: CGFloat = 0.0
var toolbarSpacing: CGFloat = 0.0
if let toolbarNode = self.toolbarNode {
if displayBotStartButton {
toolbarNode.view.isHidden = true
/*} else if !self.isFocused {
transition.updateAlpha(node: toolbarNode, alpha: 0.0, completion: { _ in
toolbarNode.isHidden = true
})*/
} else {
toolbarHeight = 44.0
toolbarSpacing = 1.0
// toolbarNode.isHidden = false
transition.updateFrame(node: toolbarNode, frame: CGRect(origin: CGPoint(x: leftInset, y: panelHeight + toolbarSpacing), size: CGSize(width: width - rightInset - leftInset, height: toolbarHeight)))
// transition.updateAlpha(node: toolbarNode, alpha: 1.0)
}
if let toolbarNode = self.toolbarNode {
if displayBotStartButton {
toolbarNode.view.isHidden = true
/*} else if !self.isFocused {
transition.updateAlpha(node: toolbarNode, alpha: 0.0, completion: { _ in
toolbarNode.isHidden = true
})*/
} else {
toolbarHeight = 44.0
toolbarSpacing = 1.0
// toolbarNode.isHidden = false
transition.updateFrame(node: toolbarNode, frame: CGRect(origin: CGPoint(x: leftInset, y: panelHeight + toolbarSpacing), size: CGSize(width: width - rightInset - leftInset, height: toolbarHeight)))
// transition.updateAlpha(node: toolbarNode, alpha: 1.0)
}
}
return toolbarHeight + toolbarSpacing
}
}