[WIP] Quotes

This commit is contained in:
Ali 2023-10-09 20:46:17 +04:00
parent 7ea8742d33
commit b17138d501
10 changed files with 131 additions and 30 deletions

View File

@ -359,6 +359,8 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatChannelSubscriberInputPanelNode",
"//submodules/TelegramUI/Components/Chat/ChatContextResultPeekContent",
"//submodules/TelegramUI/Components/Chat/ChatInputContextPanelNode",
"//submodules/TelegramUI/Components/Chat/ReplyAccessoryPanelNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageCallBubbleContentNode",
] + select({
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
"//build-system:ios_sim_arm64": [],

View File

@ -0,0 +1,26 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ChatMessageCallBubbleContentNode",
module_name = "ChatMessageCallBubbleContentNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/Display",
"//submodules/TelegramCore",
"//submodules/Postbox",
"//submodules/TelegramPresentationData",
"//submodules/AppBundle",
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode",
],
visibility = [
"//visibility:public",
],
)

View File

@ -19,13 +19,13 @@ private let incomingRedIcon = generateTintedImage(image: UIImage(bundleImageName
private let outgoingGreenIcon = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/CallOutgoingArrow"), color: UIColor(rgb: 0x36c033))
private let outgoingRedIcon = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/CallOutgoingArrow"), color: UIColor(rgb: 0xff4747))
class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
public class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
private let titleNode: TextNode
private let labelNode: TextNode
private let iconNode: ASImageNode
private let buttonNode: HighlightableButtonNode
required init() {
required public init() {
self.titleNode = TextNode()
self.labelNode = TextNode()
@ -57,22 +57,22 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
self.buttonNode.addTarget(self, action: #selector(self.callButtonPressed), forControlEvents: .touchUpInside)
}
override func accessibilityActivate() -> Bool {
override public func accessibilityActivate() -> Bool {
self.callButtonPressed()
return true
}
override func didLoad() {
override public func didLoad() {
super.didLoad()
self.view.accessibilityElementsHidden = true
}
required init?(coder aDecoder: NSCoder) {
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
@ -236,19 +236,19 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
}
}
override func animateInsertion(_ currentTimestamp: Double, duration: Double) {
override public func animateInsertion(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
override func animateAdded(_ currentTimestamp: Double, duration: Double) {
override public func animateAdded(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
@objc func callButtonPressed() {
@objc private func callButtonPressed() {
if let item = self.item {
var isVideo = false
for media in item.message.media {
@ -260,7 +260,7 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
}
}
override func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
override public func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
if self.buttonNode.frame.contains(point) {
return .ignore
} else if self.bounds.contains(point), let item = self.item {

View File

@ -0,0 +1,36 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ReplyAccessoryPanelNode",
module_name = "ReplyAccessoryPanelNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/TelegramCore",
"//submodules/Postbox",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/Display",
"//submodules/TelegramPresentationData",
"//submodules/TelegramUIPreferences",
"//submodules/AccountContext",
"//submodules/LocalizedPeerData",
"//submodules/PhotoResources",
"//submodules/TelegramStringFormatting",
"//submodules/TextFormat",
"//submodules/ChatPresentationInterfaceState",
"//submodules/TelegramUI/Components/TextNodeWithEntities",
"//submodules/TelegramUI/Components/AnimationCache",
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
"//submodules/TelegramUI/Components/Chat/AccessoryPanelNode",
"//submodules/TelegramNotices",
],
visibility = [
"//visibility:public",
],
)

View File

@ -19,29 +19,29 @@ import MultiAnimationRenderer
import AccessoryPanelNode
import TelegramNotices
final class ReplyAccessoryPanelNode: AccessoryPanelNode {
public final class ReplyAccessoryPanelNode: AccessoryPanelNode {
private let messageDisposable = MetaDisposable()
let messageId: MessageId
let quote: EngineMessageReplyQuote?
public let messageId: MessageId
public let quote: EngineMessageReplyQuote?
private var previousMediaReference: AnyMediaReference?
let closeButton: HighlightableButtonNode
let lineNode: ASImageNode
let iconNode: ASImageNode
let titleNode: ImmediateTextNode
let textNode: ImmediateTextNodeWithEntities
let imageNode: TransformImageNode
public let closeButton: HighlightableButtonNode
public let lineNode: ASImageNode
public let iconNode: ASImageNode
public let titleNode: ImmediateTextNode
public let textNode: ImmediateTextNodeWithEntities
public let imageNode: TransformImageNode
private let actionArea: AccessibilityAreaNode
private let context: AccountContext
var theme: PresentationTheme
var strings: PresentationStrings
public var theme: PresentationTheme
public var strings: PresentationStrings
private var validLayout: (size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState)?
init(context: AccountContext, messageId: MessageId, quote: EngineMessageReplyQuote?, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, animationCache: AnimationCache?, animationRenderer: MultiAnimationRenderer?) {
public init(context: AccountContext, messageId: MessageId, quote: EngineMessageReplyQuote?, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, animationCache: AnimationCache?, animationRenderer: MultiAnimationRenderer?) {
self.messageId = messageId
self.quote = quote
@ -264,6 +264,38 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
if let (size, inset, interfaceState) = strongSelf.validLayout {
strongSelf.updateState(size: size, inset: inset, interfaceState: interfaceState)
}
let _ = (ApplicationSpecificNotice.getChatReplyOptionsTip(accountManager: strongSelf.context.sharedContext.accountManager)
|> deliverOnMainQueue).start(next: { [weak self] count in
if let strongSelf = self, count < 3 {
Queue.mainQueue().after(3.0) {
if let snapshotView = strongSelf.textNode.view.snapshotContentTree() {
let text: String
//TODO:localize
if let (size, _, _) = strongSelf.validLayout, size.width > 320.0 {
text = "Tap here for options"
} else {
text = "Tap here for forwarding options"
}
strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor)
strongSelf.view.addSubview(snapshotView)
if let (size, inset, interfaceState) = strongSelf.validLayout {
strongSelf.updateState(size: size, inset: inset, interfaceState: interfaceState)
}
strongSelf.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
}
let _ = ApplicationSpecificNotice.incrementChatReplyOptionsTip(accountManager: strongSelf.context.sharedContext.accountManager).start()
}
}
})
}
}))
}
@ -272,21 +304,21 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
self.messageDisposable.dispose()
}
override func didLoad() {
override public func didLoad() {
super.didLoad()
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
}
override func animateIn() {
override public func animateIn() {
self.iconNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
}
override func animateOut() {
override public func animateOut() {
self.iconNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false)
}
override func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
override public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
self.updateThemeAndStrings(theme: theme, strings: strings, force: false)
}
@ -314,11 +346,11 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
}
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 45.0)
}
override func updateState(size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState) {
override public func updateState(size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState) {
self.validLayout = (size, inset, interfaceState)
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: 45.0))
@ -361,7 +393,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
}
}
@objc func closePressed() {
@objc private func closePressed() {
if let dismiss = self.dismiss {
dismiss()
}

View File

@ -104,6 +104,7 @@ import PeerReportScreen
import PeerSelectionController
import SaveToCameraRoll
import ChatMessageDateAndStatusNode
import ReplyAccessoryPanelNode
public enum ChatControllerPeekActions {
case standard

View File

@ -31,6 +31,7 @@ import ChatOverscrollControl
import ChatInputPanelNode
import ChatInputContextPanelNode
import TextSelectionNode
import ReplyAccessoryPanelNode
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
let itemNode: OverlayMediaItemNode

View File

@ -7,6 +7,7 @@ import ChatPresentationInterfaceState
import ChatControllerInteraction
import AccessoryPanelNode
import ForwardAccessoryPanelNode
import ReplyAccessoryPanelNode
func accessoryPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: AccessoryPanelNode?, chatControllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?) -> AccessoryPanelNode? {
if let _ = chatPresentationInterfaceState.interfaceState.selectionState {

View File

@ -36,6 +36,7 @@ import ChatHistoryEntry
import ChatMessageTextBubbleContentNode
import ChatMessageItemCommon
import ChatMessageReplyInfoNode
import ChatMessageCallBubbleContentNode
enum InternalBubbleTapAction {
case action(() -> Void)

View File

@ -12,6 +12,7 @@ import ReactionSelectionNode
import ChatControllerInteraction
import FeaturedStickersScreen
import ChatTextInputMediaRecordingButton
import ReplyAccessoryPanelNode
private func convertAnimatingSourceRect(_ rect: CGRect, fromView: UIView, toView: UIView?) -> CGRect {
if let presentationLayer = fromView.layer.presentation() {