Refactor toolbar to be a part of MessageInputPanel

This commit is contained in:
Kylmakalle
2025-01-26 14:41:10 +02:00
parent 7194cdc6d2
commit 9e1acf72dd
5 changed files with 166 additions and 126 deletions

View File

@@ -1,3 +1,8 @@
// MARK: Swiftgram
import class SwiftUI.UIHostingController
import SGSimpleSettings
import SGInputToolbar
import Foundation
import UIKit
import Display
@@ -467,6 +472,9 @@ public final class MessageInputPanelComponent: Component {
private let counter = ComponentView<Empty>()
private var header: ComponentView<Empty>?
// MARK: Swiftgram
private var toolbarView: UIView?
private var disabledPlaceholder: ComponentView<Empty>?
private var textClippingView = UIView()
private let textField = ComponentView<Empty>()
@@ -563,6 +571,9 @@ public final class MessageInputPanelComponent: Component {
self.state?.updated()
}
)
// MARK: Swiftgram
self.initToolbarIfNeeded()
}
required init?(coder: NSCoder) {
@@ -732,6 +743,11 @@ public final class MessageInputPanelComponent: Component {
if result == nil, let contextQueryResultPanel = self.contextQueryResultPanel?.view, let panelResult = contextQueryResultPanel.hitTest(self.convert(point, to: contextQueryResultPanel), with: event), panelResult !== contextQueryResultPanel {
return panelResult
}
// MARK: Swiftgram
if result == nil, let toolbarView = self.toolbarView, let toolbarResult = toolbarView.hitTest(self.convert(point, to: toolbarView), with: event) {
return toolbarResult
}
return result
}
@@ -2253,6 +2269,9 @@ public final class MessageInputPanelComponent: Component {
}
}
// MARK: Swiftgram
size = self.layoutToolbar(transition: transition, layoutFromTop: layoutFromTop, size: size, availableSize: availableSize, defaultInsets: defaultInsets, textFieldSize: textFieldSize, previousComponent: previousComponent)
return size
}
}
@@ -2306,3 +2325,110 @@ final class ViewForOverlayContent: UIView {
return nil
}
}
extension MessageInputPanelComponent.View {
func initToolbarIfNeeded() {
guard #available(iOS 13.0, *) else { return }
guard SGSimpleSettings.shared.inputToolbar else { return }
guard SGSimpleSettings.shared.b else { return }
guard self.toolbarView == nil else { return }
let notificationName = Notification.Name("sgToolbarAction")
let toolbar = ChatToolbarView(
onQuote: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "quote"])
},
onSpoiler: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "spoiler"])
},
onBold: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "bold"])
},
onItalic: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "italic"])
},
onMonospace: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "monospace"])
},
onLink: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "link"])
},
onStrikethrough: { [weak self]
in guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "strikethrough"])
},
onUnderline: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "underline"])
},
onCode: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "code"])
},
onNewLine: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "newline"])
},
// TODO(swiftgram): Binding
showNewLine: .constant(true), //.constant(self.sendWithReturnKey)
onClearFormatting: { [weak self] in
guard let _ = self else { return }
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["action": "clearFormatting"])
},
preferredColorScheme: .dark
)
let toolbarHostingController = UIHostingController(rootView: toolbar)
toolbarHostingController.view.backgroundColor = .clear
let toolbarView = toolbarHostingController.view
self.toolbarView = toolbarView
// assigning toolbarHostingController bugs responsivness and overrides layout
// self.toolbarHostingController = toolbarHostingController
// Disable "Swipe to go back" gesture when touching scrollview
self.interactiveTransitionGestureRecognizerTest = { [weak self] point in
if let self, let _ = self.toolbarView?.hitTest(point, with: nil) {
return false
}
return true
}
if let toolbarView = self.toolbarView {
self.addSubview(toolbarView)
}
}
func layoutToolbar(transition: ComponentTransition, layoutFromTop: Bool, size: CGSize, availableSize: CGSize, defaultInsets: UIEdgeInsets, textFieldSize: CGSize, previousComponent: MessageInputPanelComponent?) -> CGSize {
// TODO(swiftgram): Do not show if locked formatting
var transition = transition
if let previousComponent = previousComponent {
let previousLayoutFromTop = previousComponent.attachmentButtonMode == .captionDown
if previousLayoutFromTop != layoutFromTop {
// attachmentButtonMode changed
transition = .immediate
}
}
var size = size
if let toolbarView = self.toolbarView {
let toolbarHeight: CGFloat = 44.0
let toolbarSpacing: CGFloat = 1.0
let toolbarSize = CGSize(width: availableSize.width, height: toolbarHeight)
let hasFirstResponder = self.hasFirstResponder()
transition.setAlpha(view: toolbarView, alpha: hasFirstResponder ? 1.0 : 0.0)
if layoutFromTop {
transition.setFrame(view: toolbarView, frame: CGRect(origin: CGPoint(x: .zero, y: availableSize.height + toolbarSpacing), size: toolbarSize))
} else {
transition.setFrame(view: toolbarView, frame: CGRect(origin: CGPoint(x: .zero, y: textFieldSize.height + defaultInsets.top + toolbarSpacing), size: toolbarSize))
if hasFirstResponder {
size.height += toolbarHeight + toolbarSpacing
}
}
}
return size
}
}