mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 21:16:35 +00:00
Text selection
This commit is contained in:
parent
bacd88a1ff
commit
9a1799d616
@ -584,7 +584,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
displayReactions: false,
|
||||
messageSelection: nil,
|
||||
layoutConstants: layoutConstants,
|
||||
constrainedSize: CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)
|
||||
constrainedSize: CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height),
|
||||
controllerInteraction: controllerInteraction
|
||||
))
|
||||
refineContentFileLayout = refineLayout
|
||||
}
|
||||
|
||||
@ -2697,6 +2697,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
|
||||
contentNode.updateIsTextSelectionActive = { [weak contextSourceNode] value in
|
||||
contextSourceNode?.updateDistractionFreeMode?(value)
|
||||
|
||||
}
|
||||
contentNode.updateIsExtractedToContextPreview(contextSourceNode.isExtractedToContextPreview)
|
||||
}
|
||||
@ -2829,8 +2830,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
animation.animator.updatePosition(layer: strongSelf.clippingNode.layer, position: backgroundFrame.center, completion: nil)
|
||||
strongSelf.clippingNode.clipsToBounds = true
|
||||
animation.animator.updateBounds(layer: strongSelf.clippingNode.layer, bounds: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size), completion: { [weak strongSelf] _ in
|
||||
let _ = strongSelf
|
||||
//strongSelf?.clippingNode.clipsToBounds = false
|
||||
strongSelf?.clippingNode.clipsToBounds = false
|
||||
})
|
||||
|
||||
strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: animation)
|
||||
|
||||
@ -72,6 +72,10 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
item.controllerInteraction.openMessageReactionContextMenu(item.topMessage, sourceNode, gesture, value)
|
||||
}
|
||||
|
||||
self.interactiveFileNode.updateIsTextSelectionActive = { [weak self] value in
|
||||
self?.updateIsTextSelectionActive?(value)
|
||||
}
|
||||
}
|
||||
|
||||
override func accessibilityActivate() -> Bool {
|
||||
@ -136,7 +140,8 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
displayReactions: true,
|
||||
messageSelection: item.message.groupingKey != nil ? selection : nil,
|
||||
layoutConstants: layoutConstants,
|
||||
constrainedSize: CGSize(width: constrainedSize.width - layoutConstants.file.bubbleInsets.left - layoutConstants.file.bubbleInsets.right, height: constrainedSize.height)
|
||||
constrainedSize: CGSize(width: constrainedSize.width - layoutConstants.file.bubbleInsets.left - layoutConstants.file.bubbleInsets.right, height: constrainedSize.height),
|
||||
controllerInteraction: item.controllerInteraction
|
||||
))
|
||||
|
||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||
@ -197,6 +202,14 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.interactiveFileNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
override func willUpdateIsExtractedToContextPreview(_ value: Bool) {
|
||||
self.interactiveFileNode.willUpdateIsExtractedToContextPreview(value)
|
||||
}
|
||||
|
||||
override func updateIsExtractedToContextPreview(_ value: Bool) {
|
||||
self.interactiveFileNode.updateIsExtractedToContextPreview(value)
|
||||
}
|
||||
|
||||
override func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
|
||||
if self.interactiveFileNode.dateAndStatusNode.supernode != nil, let _ = self.interactiveFileNode.dateAndStatusNode.hitTest(self.view.convert(point, to: self.interactiveFileNode.dateAndStatusNode.view), with: nil) {
|
||||
return .ignore
|
||||
|
||||
@ -24,6 +24,7 @@ import AudioWaveformComponent
|
||||
import ShimmerEffect
|
||||
import ConvertOpusToAAC
|
||||
import LocalAudioTranscription
|
||||
import TextSelectionNode
|
||||
|
||||
private struct FetchControls {
|
||||
let fetch: (Bool) -> Void
|
||||
@ -62,6 +63,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
let messageSelection: Bool?
|
||||
let layoutConstants: ChatMessageItemLayoutConstants
|
||||
let constrainedSize: CGSize
|
||||
let controllerInteraction: ChatControllerInteraction
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
@ -82,7 +84,8 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
displayReactions: Bool,
|
||||
messageSelection: Bool?,
|
||||
layoutConstants: ChatMessageItemLayoutConstants,
|
||||
constrainedSize: CGSize
|
||||
constrainedSize: CGSize,
|
||||
controllerInteraction: ChatControllerInteraction
|
||||
) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
@ -103,6 +106,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
self.messageSelection = messageSelection
|
||||
self.layoutConstants = layoutConstants
|
||||
self.constrainedSize = constrainedSize
|
||||
self.controllerInteraction = controllerInteraction
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,6 +128,10 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
|
||||
private var audioTranscriptionButton: ComponentHostView<Empty>?
|
||||
private let textNode: TextNode
|
||||
private var textSelectionNode: TextSelectionNode?
|
||||
|
||||
var updateIsTextSelectionActive: ((Bool) -> Void)?
|
||||
|
||||
let dateAndStatusNode: ChatMessageDateAndStatusNode
|
||||
private let consumableContentNode: ASImageNode
|
||||
|
||||
@ -179,6 +187,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
|
||||
private var context: AccountContext?
|
||||
private var message: Message?
|
||||
private var arguments: Arguments?
|
||||
private var presentationData: ChatPresentationData?
|
||||
private var file: TelegramMediaFile?
|
||||
private var progressFrame: CGRect?
|
||||
@ -805,6 +814,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
strongSelf.context = arguments.context
|
||||
strongSelf.presentationData = arguments.presentationData
|
||||
strongSelf.message = arguments.message
|
||||
strongSelf.arguments = arguments
|
||||
strongSelf.file = arguments.file
|
||||
|
||||
let _ = titleApply()
|
||||
@ -865,6 +875,15 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
if let textSelectionNode = strongSelf.textSelectionNode {
|
||||
let shouldUpdateLayout = textSelectionNode.frame.size != textFrame.size
|
||||
textSelectionNode.frame = textFrame
|
||||
textSelectionNode.highlightAreaNode.frame = textFrame
|
||||
if shouldUpdateLayout {
|
||||
textSelectionNode.updateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
if let statusSizeAndApply = statusSizeAndApply {
|
||||
let statusFrame: CGRect
|
||||
if textString != nil {
|
||||
@ -1545,6 +1564,61 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func willUpdateIsExtractedToContextPreview(_ value: Bool) {
|
||||
if !value {
|
||||
if let textSelectionNode = self.textSelectionNode {
|
||||
self.textSelectionNode = nil
|
||||
textSelectionNode.highlightAreaNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
textSelectionNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak textSelectionNode] _ in
|
||||
textSelectionNode?.highlightAreaNode.removeFromSupernode()
|
||||
textSelectionNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateIsExtractedToContextPreview(_ value: Bool) {
|
||||
if value {
|
||||
if self.textSelectionNode == nil, let item = self.arguments, /*!item.associatedData.isCopyProtectionEnabled && !item.message.isCopyProtected(),*/ let rootNode = item.controllerInteraction.chatControllerNode() {
|
||||
let selectionColor: UIColor
|
||||
let knobColor: UIColor
|
||||
if item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||
selectionColor = item.presentationData.theme.theme.chat.message.incoming.textSelectionColor
|
||||
knobColor = item.presentationData.theme.theme.chat.message.incoming.textSelectionKnobColor
|
||||
} else {
|
||||
selectionColor = item.presentationData.theme.theme.chat.message.outgoing.textSelectionColor
|
||||
knobColor = item.presentationData.theme.theme.chat.message.outgoing.textSelectionKnobColor
|
||||
}
|
||||
|
||||
let textSelectionNode = TextSelectionNode(theme: TextSelectionTheme(selection: selectionColor, knob: knobColor), strings: item.presentationData.strings, textNode: self.textNode, updateIsActive: { [weak self] value in
|
||||
self?.updateIsTextSelectionActive?(value)
|
||||
}, present: { [weak self] c, a in
|
||||
self?.arguments?.controllerInteraction.presentGlobalOverlayController(c, a)
|
||||
}, rootNode: rootNode, performAction: { [weak self] text, action in
|
||||
guard let strongSelf = self, let item = strongSelf.arguments else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.performTextSelectionAction(item.message.stableId, text, action)
|
||||
})
|
||||
self.textSelectionNode = textSelectionNode
|
||||
self.addSubnode(textSelectionNode)
|
||||
self.insertSubnode(textSelectionNode.highlightAreaNode, belowSubnode: self.textNode)
|
||||
textSelectionNode.frame = self.textNode.frame
|
||||
textSelectionNode.highlightAreaNode.frame = self.textNode.frame
|
||||
}
|
||||
} else {
|
||||
if let textSelectionNode = self.textSelectionNode {
|
||||
self.textSelectionNode = nil
|
||||
self.updateIsTextSelectionActive?(false)
|
||||
textSelectionNode.highlightAreaNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
textSelectionNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak textSelectionNode] _ in
|
||||
textSelectionNode?.highlightAreaNode.removeFromSupernode()
|
||||
textSelectionNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func transitionNode(media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
if let iconNode = self.iconNode, let file = self.file, file.isEqual(to: media) {
|
||||
return (iconNode, iconNode.bounds, { [weak iconNode] in
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user