mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
2d02870d59
@ -5481,3 +5481,6 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"ForwardedDices_any" = "%@ forwarded dices";
|
||||
"ForwardedDices_many" = "%@ forwarded dices";
|
||||
"ForwardedDices_0" = "%@ forwarded dices";
|
||||
|
||||
"Conversation.ContextMenuDiscuss" = "Discuss";
|
||||
|
||||
|
@ -157,7 +157,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
}
|
||||
})
|
||||
|
||||
self.contextContainer.activated = { [weak self] gesture in
|
||||
self.contextContainer.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
|
@ -366,7 +366,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
}
|
||||
})
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let item = strongSelf.item, let contextAction = item.contextAction else {
|
||||
gesture.cancel()
|
||||
return
|
||||
|
@ -9,10 +9,11 @@ public final class ContextControllerSourceNode: ASDisplayNode {
|
||||
self.contextGesture?.isEnabled = self.isGestureEnabled
|
||||
}
|
||||
}
|
||||
public var activated: ((ContextGesture) -> Void)?
|
||||
public var activated: ((ContextGesture, CGPoint) -> Void)?
|
||||
public var shouldBegin: ((CGPoint) -> Bool)?
|
||||
public var customActivationProgress: ((CGFloat, ContextGestureTransition) -> Void)?
|
||||
public var targetNodeForActivationProgress: ASDisplayNode?
|
||||
public var targetNodeForActivationProgressContentRect: CGRect?
|
||||
|
||||
public func cancelGesture() {
|
||||
self.contextGesture?.cancel()
|
||||
@ -41,25 +42,54 @@ public final class ContextControllerSourceNode: ASDisplayNode {
|
||||
if let customActivationProgress = strongSelf.customActivationProgress {
|
||||
customActivationProgress(progress, update)
|
||||
} else {
|
||||
let targetNode = strongSelf.targetNodeForActivationProgress ?? strongSelf
|
||||
let targetNode: ASDisplayNode
|
||||
let targetContentRect: CGRect
|
||||
if let targetNodeForActivationProgress = strongSelf.targetNodeForActivationProgress {
|
||||
targetNode = targetNodeForActivationProgress
|
||||
if let targetNodeForActivationProgressContentRect = strongSelf.targetNodeForActivationProgressContentRect {
|
||||
targetContentRect = targetNodeForActivationProgressContentRect
|
||||
} else {
|
||||
targetContentRect = CGRect(origin: CGPoint(), size: targetNode.bounds.size)
|
||||
}
|
||||
} else {
|
||||
targetNode = strongSelf
|
||||
targetContentRect = CGRect(origin: CGPoint(), size: targetNode.bounds.size)
|
||||
}
|
||||
|
||||
let minScale: CGFloat = (strongSelf.bounds.width - 10.0) / strongSelf.bounds.width
|
||||
let scaleSide = max(targetContentRect.width, targetContentRect.height)
|
||||
let minScale: CGFloat = (scaleSide - 10.0) / scaleSide
|
||||
let currentScale = 1.0 * (1.0 - progress) + minScale * progress
|
||||
|
||||
let originalCenterOffsetX: CGFloat = targetNode.bounds.width / 2.0 - targetContentRect.midX
|
||||
let scaledCaneterOffsetX: CGFloat = originalCenterOffsetX * currentScale
|
||||
|
||||
let originalCenterOffsetY: CGFloat = targetNode.bounds.height / 2.0 - targetContentRect.midY
|
||||
let scaledCaneterOffsetY: CGFloat = originalCenterOffsetY * currentScale
|
||||
|
||||
let scaleMidX: CGFloat = scaledCaneterOffsetX - originalCenterOffsetX
|
||||
let scaleMidY: CGFloat = scaledCaneterOffsetY - originalCenterOffsetY
|
||||
|
||||
switch update {
|
||||
case .update:
|
||||
targetNode.layer.sublayerTransform = CATransform3DMakeScale(currentScale, currentScale, 1.0)
|
||||
let sublayerTransform = CATransform3DTranslate(CATransform3DScale(CATransform3DIdentity, currentScale, currentScale, 1.0), scaleMidX, scaleMidY, 0.0)
|
||||
targetNode.layer.sublayerTransform = sublayerTransform
|
||||
case .begin:
|
||||
targetNode.layer.sublayerTransform = CATransform3DMakeScale(currentScale, currentScale, 1.0)
|
||||
case let .ended(previousProgress):
|
||||
let previousScale = 1.0 * (1.0 - previousProgress) + minScale * previousProgress
|
||||
targetNode.layer.sublayerTransform = CATransform3DMakeScale(currentScale, currentScale, 1.0)
|
||||
targetNode.layer.animateSpring(from: previousScale as NSNumber, to: currentScale as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.5, delay: 0.0, initialVelocity: 0.0, damping: 90.0)
|
||||
let sublayerTransform = CATransform3DTranslate(CATransform3DScale(CATransform3DIdentity, currentScale, currentScale, 1.0), scaleMidX, scaleMidY, 0.0)
|
||||
targetNode.layer.sublayerTransform = sublayerTransform
|
||||
case .ended:
|
||||
let sublayerTransform = CATransform3DTranslate(CATransform3DScale(CATransform3DIdentity, currentScale, currentScale, 1.0), scaleMidX, scaleMidY, 0.0)
|
||||
let previousTransform = targetNode.layer.sublayerTransform
|
||||
targetNode.layer.sublayerTransform = sublayerTransform
|
||||
|
||||
targetNode.layer.animate(from: NSValue(caTransform3D: previousTransform), to: NSValue(caTransform3D: sublayerTransform), keyPath: "sublayerTransform", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 0.2)
|
||||
|
||||
//targetNode.layer.animateSpring(from: previousScale as NSNumber, to: currentScale as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.5, delay: 0.0, initialVelocity: 0.0, damping: 90.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
contextGesture.activated = { [weak self] gesture in
|
||||
contextGesture.activated = { [weak self] gesture, location in
|
||||
if let activated = self?.activated {
|
||||
activated(gesture)
|
||||
activated(gesture, location)
|
||||
} else {
|
||||
gesture.cancel()
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
|
||||
|
||||
public var shouldBegin: ((CGPoint) -> Bool)?
|
||||
public var activationProgress: ((CGFloat, ContextGestureTransition) -> Void)?
|
||||
public var activated: ((ContextGesture) -> Void)?
|
||||
public var activated: ((ContextGesture, CGPoint) -> Void)?
|
||||
public var externalUpdated: ((UIView?, CGPoint) -> Void)?
|
||||
public var externalEnded: (((UIView?, CGPoint)?) -> Void)?
|
||||
|
||||
@ -95,9 +95,10 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
|
||||
guard let touch = touches.first else {
|
||||
return
|
||||
}
|
||||
let location = touch.location(in: self.view)
|
||||
|
||||
if let shouldBegin = self.shouldBegin {
|
||||
if !shouldBegin(touch.location(in: self.view)) {
|
||||
if !shouldBegin(location) {
|
||||
self.state = .failed
|
||||
return
|
||||
}
|
||||
@ -132,7 +133,7 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
|
||||
case .possible:
|
||||
strongSelf.delayTimer?.invalidate()
|
||||
strongSelf.animator?.invalidate()
|
||||
strongSelf.activated?(strongSelf)
|
||||
strongSelf.activated?(strongSelf, location)
|
||||
if let view = strongSelf.view?.superview {
|
||||
if let window = view.window {
|
||||
cancelOtherGestures(gesture: strongSelf, view: window)
|
||||
@ -167,7 +168,7 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
|
||||
case .possible:
|
||||
self.delayTimer?.invalidate()
|
||||
self.animator?.invalidate()
|
||||
self.activated?(self)
|
||||
self.activated?(self, touch.location(in: self.view))
|
||||
if let view = self.view?.superview {
|
||||
if let window = view.window {
|
||||
cancelOtherGestures(gesture: self, view: window)
|
||||
|
@ -248,7 +248,7 @@ private final class TabBarNodeContainer {
|
||||
updateSelectedImage(value)
|
||||
}
|
||||
|
||||
imageNode.containerNode.activated = { [weak self] gesture in
|
||||
imageNode.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ public class BaseLinesChartController: BaseChartController {
|
||||
}
|
||||
|
||||
public override func didTapZoomIn(date: Date, pointIndex: Int) {
|
||||
guard isZoomed == false else { return }
|
||||
guard !isZoomed, isZoomable else { return }
|
||||
|
||||
setDetailsViewModel?(chartDetailsViewModel(closestDate: date, pointIndex: pointIndex, loading: true), false, false)
|
||||
|
||||
|
@ -245,7 +245,7 @@ public class PercentPieChartController: BaseChartController {
|
||||
}
|
||||
|
||||
func didTapZoomIn(date: Date, animated: Bool) {
|
||||
guard isZoomed == false else { return }
|
||||
guard !isZoomed, isZoomable else { return }
|
||||
cancelChartInteraction()
|
||||
let currentCollection = percentController.chartsCollection
|
||||
let range: Int = Constants.zoomedRange
|
||||
|
@ -206,7 +206,7 @@ public class DailyBarsChartController: BaseChartController {
|
||||
}
|
||||
|
||||
public override func didTapZoomIn(date: Date, pointIndex: Int) {
|
||||
guard isZoomed == false else { return }
|
||||
guard !isZoomed, isZoomable else { return }
|
||||
if isZoomed {
|
||||
return linesController.hideDetailsView(animated: true)
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ public class StackedBarsChartController: BaseChartController {
|
||||
}
|
||||
|
||||
public override func didTapZoomIn(date: Date, pointIndex: Int) {
|
||||
guard isZoomed == false else { return }
|
||||
guard !isZoomed, isZoomable else { return }
|
||||
if isZoomed {
|
||||
return zoomedBarsController.hideDetailsView(animated: true)
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ public class StepBarsChartController: BaseChartController {
|
||||
}
|
||||
|
||||
public override func didTapZoomIn(date: Date, pointIndex: Int) {
|
||||
guard isZoomed == false else { return }
|
||||
guard !isZoomed, isZoomable else { return }
|
||||
if isZoomed {
|
||||
return zoomedBarsController.hideDetailsView(animated: true)
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
}
|
||||
})
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let item = strongSelf.layoutParams?.0, let contextAction = item.contextAction else {
|
||||
gesture.cancel()
|
||||
return
|
||||
|
@ -215,7 +215,7 @@ private final class ChatListViewSpaceState {
|
||||
if let lastMessage = lowerOrAtAnchorMessages.min(by: { $0.entryIndex < $1.entryIndex }) {
|
||||
nextLowerIndex = lastMessage.entryIndex
|
||||
} else {
|
||||
nextLowerIndex = resolvedAnchorIndex.predecessor
|
||||
nextLowerIndex = resolvedAnchorIndex
|
||||
}
|
||||
let loadedLowerMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextLowerIndex.index, nextLowerIndex.isMessage), to: (lowerBound.index, lowerBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - lowerOrAtAnchorMessages.count, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry)
|
||||
lowerOrAtAnchorMessages.append(contentsOf: loadedLowerMessages)
|
||||
|
@ -127,7 +127,7 @@ public final class SelectablePeerNode: ASDisplayNode {
|
||||
self.contextContainer.addSubnode(self.textNode)
|
||||
self.contextContainer.addSubnode(self.onlineNode)
|
||||
|
||||
self.contextContainer.activated = { [weak self] gesture in
|
||||
self.contextContainer.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let contextAction = strongSelf.contextAction else {
|
||||
gesture.cancel()
|
||||
return
|
||||
|
@ -313,7 +313,7 @@ private final class ThemeSettingsAccentColorIconItemNode : ListViewItemNode {
|
||||
self.containerNode.addSubnode(self.dotsNode)
|
||||
self.containerNode.addSubnode(self.centerNode)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
gesture.cancel()
|
||||
return
|
||||
|
@ -224,7 +224,7 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
|
||||
self.containerNode.addSubnode(self.overlayNode)
|
||||
self.containerNode.addSubnode(self.titleNode)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
gesture.cancel()
|
||||
return
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -63,7 +63,7 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
|
||||
self.containerNode.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.containerNode)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -545,13 +545,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self?.openPeer(peerId: id, navigation: navigation, fromMessage: fromMessage)
|
||||
}, openPeerMention: { [weak self] name in
|
||||
self?.openPeerMention(name)
|
||||
}, openMessageContextMenu: { [weak self] message, selectAll, node, frame, recognizer in
|
||||
}, openMessageContextMenu: { [weak self] message, selectAll, node, frame, anyRecognizer in
|
||||
guard let strongSelf = self, strongSelf.isNodeLoaded else {
|
||||
return
|
||||
}
|
||||
if strongSelf.presentationInterfaceState.interfaceState.selectionState != nil {
|
||||
return
|
||||
}
|
||||
let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
|
||||
let gesture: ContextGesture? = anyRecognizer as? ContextGesture
|
||||
if let messages = strongSelf.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) {
|
||||
(strongSelf.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures()
|
||||
strongSelf.chatDisplayNode.cancelInteractiveKeyboardGestures()
|
||||
@ -600,7 +602,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let _ = ApplicationSpecificNotice.incrementChatTextSelectionTips(accountManager: strongSelf.context.sharedContext.accountManager).start()
|
||||
}
|
||||
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: message)), items: .single(actions), reactionItems: reactionItems, recognizer: recognizer, displayTextSelectionTip: displayTextSelectionTip)
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: message)), items: .single(actions), reactionItems: reactionItems, recognizer: recognizer, gesture: gesture, displayTextSelectionTip: displayTextSelectionTip)
|
||||
strongSelf.currentContextController = controller
|
||||
controller.reactionSelected = { [weak controller] value in
|
||||
guard let strongSelf = self, let message = updatedMessages.first else {
|
||||
|
@ -53,7 +53,7 @@ public final class ChatControllerInteraction {
|
||||
let openMessage: (Message, ChatControllerInteractionOpenMessageMode) -> Bool
|
||||
let openPeer: (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void
|
||||
let openPeerMention: (String) -> Void
|
||||
let openMessageContextMenu: (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void
|
||||
let openMessageContextMenu: (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void
|
||||
let openMessageContextActions: (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void
|
||||
let navigateToMessage: (MessageId, MessageId) -> Void
|
||||
let tapMessage: ((Message) -> Void)?
|
||||
@ -121,7 +121,7 @@ public final class ChatControllerInteraction {
|
||||
var searchTextHighightState: (String, [MessageIndex])?
|
||||
var seenOneTimeAnimatedMedia = Set<MessageId>()
|
||||
|
||||
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, tapMessage: ((Message) -> Void)?, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?, Message?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOptions: @escaping (MessageId, [Data]) -> Void, requestOpenMessagePollResults: @escaping (MessageId, MediaId) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String?) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, openMessagePollResults: @escaping (MessageId, Data) -> Void, openPollCreation: @escaping (Bool?) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
|
||||
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, tapMessage: ((Message) -> Void)?, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?, Message?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOptions: @escaping (MessageId, [Data]) -> Void, requestOpenMessagePollResults: @escaping (MessageId, MediaId) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String?) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, openMessagePollResults: @escaping (MessageId, Data) -> Void, openPollCreation: @escaping (Bool?) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
|
||||
self.openMessage = openMessage
|
||||
self.openPeer = openPeer
|
||||
self.openPeerMention = openPeerMention
|
||||
|
@ -257,6 +257,7 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
||||
var loadCopyMediaResource: MediaResource?
|
||||
var isAction = false
|
||||
var isDice = false
|
||||
var canDiscuss = false
|
||||
if messages.count == 1 {
|
||||
for media in messages[0].media {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
@ -292,6 +293,17 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
||||
if let channel = messages[0].peers[messages[0].id.peerId] as? TelegramChannel {
|
||||
if !isAction {
|
||||
canPin = channel.hasPermission(.pinMessages)
|
||||
|
||||
if messages[0].id.namespace == Namespaces.Message.Cloud {
|
||||
switch channel.info {
|
||||
case let .broadcast(info):
|
||||
if info.flags.contains(.hasDiscussionGroup) {
|
||||
canDiscuss = true
|
||||
}
|
||||
case .group:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let group = messages[0].peers[messages[0].id.peerId] as? TelegramGroup {
|
||||
if !isAction {
|
||||
@ -693,6 +705,94 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
||||
})))
|
||||
}
|
||||
|
||||
if canDiscuss {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuDiscuss, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { c, _ in
|
||||
let timestamp = messages[0].timestamp
|
||||
let channelMessageId = messages[0].id
|
||||
|
||||
enum DiscussMessageResult {
|
||||
case message(MessageId)
|
||||
case peer(PeerId)
|
||||
}
|
||||
|
||||
let signal = context.account.postbox.transaction { transaction -> PeerId? in
|
||||
if let cachedData = transaction.getPeerCachedData(peerId: messages[0].id.peerId) as? CachedChannelData {
|
||||
return cachedData.linkedDiscussionPeerId
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|> mapToSignal { peerId -> Signal<DiscussMessageResult?, NoError> in
|
||||
guard let peerId = peerId else {
|
||||
return .single(nil)
|
||||
}
|
||||
let historyView = preloadedChatHistoryViewForLocation(ChatHistoryLocationInput(content: .InitialSearch(location: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp)), count: 30), id: 0), account: context.account, chatLocation: .peer(peerId), fixedCombinedReadStates: nil, tagMask: nil, additionalData: [])
|
||||
return historyView
|
||||
|> mapToSignal { historyView -> Signal<(MessageIndex?, Bool), NoError> in
|
||||
switch historyView {
|
||||
case .Loading:
|
||||
return .single((nil, true))
|
||||
case let .HistoryView(view, _, _, _, _, _, _):
|
||||
for entry in view.entries {
|
||||
for attribute in entry.message.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
if attribute.messageId == channelMessageId {
|
||||
return .single((entry.message.index, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return .single((nil, false))
|
||||
}
|
||||
}
|
||||
|> take(until: { index in
|
||||
return SignalTakeAction(passthrough: true, complete: !index.1)
|
||||
})
|
||||
|> last
|
||||
|> map { result -> DiscussMessageResult? in
|
||||
if let index = result?.0 {
|
||||
return .message(index.id)
|
||||
} else {
|
||||
return .peer(peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let foundIndex = Promise<DiscussMessageResult?>()
|
||||
foundIndex.set(signal)
|
||||
|
||||
c.dismiss(completion: { [weak interfaceInteraction] in
|
||||
var cancelImpl: (() -> Void)?
|
||||
let statusController = OverlayStatusController(theme: chatPresentationInterfaceState.theme, type: .loading(cancelled: {
|
||||
cancelImpl?()
|
||||
}))
|
||||
controllerInteraction.presentController(statusController, nil)
|
||||
|
||||
let disposable = (foundIndex.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak statusController] result in
|
||||
statusController?.dismiss()
|
||||
|
||||
if let result = result {
|
||||
switch result {
|
||||
case let .message(id):
|
||||
interfaceInteraction?.navigateToMessage(id)
|
||||
case let .peer(peerId):
|
||||
interfaceInteraction?.navigateToChat(peerId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
cancelImpl = { [weak statusController] in
|
||||
disposable.dispose()
|
||||
statusController?.dismiss()
|
||||
}
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
if data.messageActions.options.contains(.report) {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuReport, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Report"), color: theme.actionSheet.primaryTextColor)
|
||||
|
@ -23,6 +23,12 @@ import GridMessageSelectionNode
|
||||
import AppBundle
|
||||
import Markdown
|
||||
|
||||
private enum InternalBubbleTapAction {
|
||||
case action(() -> Void)
|
||||
case optionalAction(() -> Void)
|
||||
case openContextMenu(tapMessage: Message, selectAll: Bool, subFrame: CGRect)
|
||||
}
|
||||
|
||||
private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(Message, AnyClass, ChatMessageEntryAttributes)] {
|
||||
var result: [(Message, AnyClass, ChatMessageEntryAttributes)] = []
|
||||
var skipText = false
|
||||
@ -145,6 +151,7 @@ private enum ContentNodeOperation {
|
||||
|
||||
class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode {
|
||||
private let contextSourceNode: ContextExtractedContentContainingNode
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
private let backgroundWallpaperNode: ChatMessageBubbleBackdrop
|
||||
private let backgroundNode: ChatMessageBackground
|
||||
private let shadowNode: ChatMessageShadowNode
|
||||
@ -201,6 +208,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
|
||||
required init() {
|
||||
self.contextSourceNode = ContextExtractedContentContainingNode()
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
self.backgroundWallpaperNode = ChatMessageBubbleBackdrop()
|
||||
|
||||
self.backgroundNode = ChatMessageBackground()
|
||||
@ -209,7 +217,48 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
|
||||
super.init(layerBacked: false)
|
||||
|
||||
self.addSubnode(self.contextSourceNode)
|
||||
self.containerNode.shouldBegin = { [weak self] location in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
if !strongSelf.backgroundNode.frame.contains(location) {
|
||||
return false
|
||||
}
|
||||
if let action = strongSelf.gestureRecognized(gesture: .tap, location: location, recognizer: nil) {
|
||||
if case .action = action {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case .action, .optionalAction:
|
||||
return false
|
||||
case .openContextMenu:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture, location in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case .action, .optionalAction:
|
||||
break
|
||||
case let .openContextMenu(tapMessage, selectAll, subFrame):
|
||||
item.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, strongSelf, subFrame, gesture)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.containerNode.addSubnode(self.contextSourceNode)
|
||||
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
||||
self.addSubnode(self.containerNode)
|
||||
|
||||
self.contextSourceNode.contentNode.addSubnode(self.backgroundWallpaperNode)
|
||||
self.contextSourceNode.contentNode.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.messageAccessibilityArea)
|
||||
@ -385,8 +434,18 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
return
|
||||
}
|
||||
strongSelf.reactionRecognizer?.cancel()
|
||||
if strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) {
|
||||
recognizer.cancel()
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) {
|
||||
switch action {
|
||||
case let .action(f):
|
||||
f()
|
||||
recognizer.cancel()
|
||||
case let .optionalAction(f):
|
||||
f()
|
||||
recognizer.cancel()
|
||||
case .openContextMenu:
|
||||
//recognizer.cancel()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
recognizer.highlight = { [weak self] point in
|
||||
@ -1688,7 +1747,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
guard let strongSelf = selfReference.value else {
|
||||
return
|
||||
}
|
||||
let previousContextFrame = strongSelf.contextSourceNode.frame
|
||||
let previousContextFrame = strongSelf.containerNode.frame
|
||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
|
||||
@ -2052,6 +2112,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
|
||||
let previousContextContentFrame = strongSelf.contextSourceNode.contentRect
|
||||
strongSelf.contextSourceNode.contentRect = backgroundFrame.offsetBy(dx: incomingOffset, dy: 0.0)
|
||||
strongSelf.containerNode.targetNodeForActivationProgressContentRect = strongSelf.contextSourceNode.contentRect
|
||||
|
||||
if previousContextFrame.size != strongSelf.contextSourceNode.bounds.size || previousContextContentFrame != strongSelf.contextSourceNode.contentRect {
|
||||
strongSelf.contextSourceNode.layoutUpdated?(strongSelf.contextSourceNode.bounds.size)
|
||||
@ -2212,6 +2273,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
break
|
||||
}
|
||||
self.contextSourceNode.contentRect = backgroundFrame.offsetBy(dx: incomingOffset, dy: 0.0)
|
||||
self.containerNode.targetNodeForActivationProgressContentRect = self.contextSourceNode.contentRect
|
||||
if !self.contextSourceNode.isExtractedToContextPreview {
|
||||
if let (rect, size) = self.absoluteRect {
|
||||
self.updateAbsoluteRect(rect, within: size)
|
||||
@ -2246,14 +2308,25 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
let _ = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil)
|
||||
if let action = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case let .action(f):
|
||||
f()
|
||||
case let .optionalAction(f):
|
||||
f()
|
||||
case let .openContextMenu(tapMessage, selectAll, subFrame):
|
||||
self.item?.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, self, subFrame, nil)
|
||||
}
|
||||
} else if case .tap = gesture {
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> Bool {
|
||||
private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> InternalBubbleTapAction? {
|
||||
var mediaMessage: Message?
|
||||
var forceOpen = false
|
||||
if let item = self.item {
|
||||
@ -2290,38 +2363,39 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
switch gesture {
|
||||
case .tap:
|
||||
if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) {
|
||||
if let item = self.item, let author = item.content.firstMessage.author {
|
||||
var openPeerId = item.effectiveAuthorId ?? author.id
|
||||
var navigate: ChatControllerInteractionNavigateToPeer
|
||||
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
navigate = .chat(textInputState: nil, subject: nil)
|
||||
} else {
|
||||
navigate = .info
|
||||
}
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId))
|
||||
return .action({
|
||||
if let item = self.item, let author = item.content.firstMessage.author {
|
||||
var openPeerId = item.effectiveAuthorId ?? author.id
|
||||
var navigate: ChatControllerInteractionNavigateToPeer
|
||||
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
navigate = .chat(textInputState: nil, subject: nil)
|
||||
} else {
|
||||
navigate = .info
|
||||
}
|
||||
}
|
||||
|
||||
if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
|
||||
} else {
|
||||
if item.message.id.peerId == item.context.account.peerId, let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
|
||||
if case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
|
||||
} else if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
return true
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId))
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
|
||||
if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
|
||||
} else {
|
||||
if item.message.id.peerId == item.context.account.peerId, let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
|
||||
if case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
|
||||
} else if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
return
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
if let nameNode = self.nameNode, nameNode.frame.contains(location) {
|
||||
@ -2335,15 +2409,16 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
botAddressName = attribute.title
|
||||
}
|
||||
|
||||
if let botAddressName = botAddressName {
|
||||
item.controllerInteraction.updateInputState { textInputState in
|
||||
return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " "))
|
||||
return .optionalAction({
|
||||
if let botAddressName = botAddressName {
|
||||
item.controllerInteraction.updateInputState { textInputState in
|
||||
return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " "))
|
||||
}
|
||||
item.controllerInteraction.updateInputMode { _ in
|
||||
return .text
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.updateInputMode { _ in
|
||||
return .text
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2351,119 +2426,133 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
if let item = self.item {
|
||||
for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? ReplyMessageAttribute {
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
|
||||
return true
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let forwardInfoNode = self.forwardInfoNode, forwardInfoNode.frame.contains(location) {
|
||||
if let item = self.item, let forwardInfo = item.message.forwardInfo {
|
||||
if let sourceMessageId = forwardInfo.sourceMessageId {
|
||||
if let channel = forwardInfo.author as? TelegramChannel, channel.username == nil {
|
||||
if case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
|
||||
} else if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, forwardInfoNode, nil)
|
||||
return true
|
||||
return .optionalAction({
|
||||
if let sourceMessageId = forwardInfo.sourceMessageId {
|
||||
if let channel = forwardInfo.author as? TelegramChannel, channel.username == nil {
|
||||
if case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
|
||||
} else if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, forwardInfoNode, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
|
||||
} else if let id = forwardInfo.source?.id ?? forwardInfo.author?.id {
|
||||
item.controllerInteraction.openPeer(id, .info, nil)
|
||||
} else if let _ = forwardInfo.authorSignature {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
|
||||
}
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
|
||||
} else if let id = forwardInfo.source?.id ?? forwardInfo.author?.id {
|
||||
item.controllerInteraction.openPeer(id, .info, nil)
|
||||
} else if let _ = forwardInfo.authorSignature {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
var foundTapAction = false
|
||||
loop: for contentNode in self.contentNodes {
|
||||
let tapAction = contentNode.tapActionAtPoint(CGPoint(x: location.x - contentNode.frame.minX, y: location.y - contentNode.frame.minY), gesture: gesture, isEstimating: false)
|
||||
switch tapAction {
|
||||
case .none, .ignore:
|
||||
if let item = self.item, self.backgroundNode.frame.contains(CGPoint(x: self.frame.width - location.x, y: location.y)), let tapMessage = self.item?.controllerInteraction.tapMessage {
|
||||
foundTapAction = true
|
||||
case .none:
|
||||
if let item = self.item, self.backgroundNode.frame.contains(CGPoint(x: self.frame.width - location.x, y: location.y)), let tapMessage = self.item?.controllerInteraction.tapMessage {
|
||||
return .action({
|
||||
tapMessage(item.message)
|
||||
}
|
||||
break
|
||||
case let .url(url, concealed):
|
||||
foundTapAction = true
|
||||
})
|
||||
}
|
||||
case .ignore:
|
||||
if let item = self.item, self.backgroundNode.frame.contains(CGPoint(x: self.frame.width - location.x, y: location.y)), let tapMessage = self.item?.controllerInteraction.tapMessage {
|
||||
return .action({
|
||||
tapMessage(item.message)
|
||||
})
|
||||
} else {
|
||||
return .action({
|
||||
})
|
||||
}
|
||||
case let .url(url, concealed):
|
||||
return .action({
|
||||
self.item?.controllerInteraction.openUrl(url, concealed, nil, self.item?.content.firstMessage)
|
||||
break loop
|
||||
case let .peerMention(peerId, _):
|
||||
foundTapAction = true
|
||||
})
|
||||
case let .peerMention(peerId, _):
|
||||
return .action({
|
||||
self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil), nil)
|
||||
break loop
|
||||
case let .textMention(name):
|
||||
foundTapAction = true
|
||||
})
|
||||
case let .textMention(name):
|
||||
return .action({
|
||||
self.item?.controllerInteraction.openPeerMention(name)
|
||||
break loop
|
||||
case let .botCommand(command):
|
||||
foundTapAction = true
|
||||
if let item = self.item {
|
||||
})
|
||||
case let .botCommand(command):
|
||||
if let item = self.item {
|
||||
return .action({
|
||||
item.controllerInteraction.sendBotCommand(item.message.id, command)
|
||||
}
|
||||
break loop
|
||||
case let .hashtag(peerName, hashtag):
|
||||
foundTapAction = true
|
||||
})
|
||||
}
|
||||
case let .hashtag(peerName, hashtag):
|
||||
return .action({
|
||||
self.item?.controllerInteraction.openHashtag(peerName, hashtag)
|
||||
break loop
|
||||
case .instantPage:
|
||||
foundTapAction = true
|
||||
if let item = self.item {
|
||||
})
|
||||
case .instantPage:
|
||||
if let item = self.item {
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.openInstantPage(item.message, item.associatedData)
|
||||
}
|
||||
break loop
|
||||
case .wallpaper:
|
||||
foundTapAction = true
|
||||
if let item = self.item {
|
||||
})
|
||||
}
|
||||
case .wallpaper:
|
||||
if let item = self.item {
|
||||
return .action({
|
||||
item.controllerInteraction.openWallpaper(item.message)
|
||||
}
|
||||
break loop
|
||||
case .theme:
|
||||
foundTapAction = true
|
||||
if let item = self.item {
|
||||
})
|
||||
}
|
||||
case .theme:
|
||||
if let item = self.item {
|
||||
return .action({
|
||||
item.controllerInteraction.openTheme(item.message)
|
||||
}
|
||||
break loop
|
||||
case let .call(peerId):
|
||||
foundTapAction = true
|
||||
})
|
||||
}
|
||||
case let .call(peerId):
|
||||
return .optionalAction({
|
||||
self.item?.controllerInteraction.callPeer(peerId)
|
||||
break loop
|
||||
case .openMessage:
|
||||
foundTapAction = true
|
||||
if let item = self.item {
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
})
|
||||
case .openMessage:
|
||||
if let item = self.item {
|
||||
if let type = self.backgroundNode.type, case .none = type {
|
||||
return .optionalAction({
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
})
|
||||
} else {
|
||||
return .action({
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
})
|
||||
}
|
||||
break loop
|
||||
case let .timecode(timecode, _):
|
||||
foundTapAction = true
|
||||
if let item = self.item, let mediaMessage = mediaMessage {
|
||||
}
|
||||
case let .timecode(timecode, _):
|
||||
if let item = self.item, let mediaMessage = mediaMessage {
|
||||
return .action({
|
||||
item.controllerInteraction.seekToTimecode(mediaMessage, timecode, forceOpen)
|
||||
}
|
||||
break loop
|
||||
case let .bankCard(number):
|
||||
foundTapAction = true
|
||||
if let item = self.item {
|
||||
})
|
||||
}
|
||||
case let .bankCard(number):
|
||||
if let item = self.item {
|
||||
return .action({
|
||||
item.controllerInteraction.longTap(.bankCard(number), item.message)
|
||||
}
|
||||
case let .tooltip(text, node, rect):
|
||||
foundTapAction = true
|
||||
if let item = self.item {
|
||||
})
|
||||
}
|
||||
case let .tooltip(text, node, rect):
|
||||
if let item = self.item {
|
||||
return .action({
|
||||
let _ = item.controllerInteraction.displayMessageTooltip(item.message.id, text, node, rect)
|
||||
}
|
||||
break loop
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if !foundTapAction {
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
}
|
||||
return nil
|
||||
case .longTap, .doubleTap:
|
||||
if let item = self.item, self.backgroundNode.frame.contains(location) {
|
||||
let message = item.message
|
||||
|
||||
var foundTapAction = false
|
||||
var tapMessage: Message? = item.content.firstMessage
|
||||
var selectAll = true
|
||||
loop: for contentNode in self.contentNodes {
|
||||
@ -2475,53 +2564,53 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
tapMessage = contentNode.item?.message
|
||||
let tapAction = contentNode.tapActionAtPoint(CGPoint(x: location.x - contentNode.frame.minX, y: location.y - contentNode.frame.minY), gesture: gesture, isEstimating: false)
|
||||
switch tapAction {
|
||||
case .none, .ignore:
|
||||
break
|
||||
case let .url(url, _):
|
||||
foundTapAction = true
|
||||
case .none, .ignore:
|
||||
break
|
||||
case let .url(url, _):
|
||||
return .action({
|
||||
item.controllerInteraction.longTap(.url(url), message)
|
||||
break loop
|
||||
case let .peerMention(peerId, mention):
|
||||
foundTapAction = true
|
||||
})
|
||||
case let .peerMention(peerId, mention):
|
||||
return .action({
|
||||
item.controllerInteraction.longTap(.peerMention(peerId, mention), message)
|
||||
break loop
|
||||
case let .textMention(name):
|
||||
foundTapAction = true
|
||||
})
|
||||
case let .textMention(name):
|
||||
return .action({
|
||||
item.controllerInteraction.longTap(.mention(name), message)
|
||||
break loop
|
||||
case let .botCommand(command):
|
||||
foundTapAction = true
|
||||
})
|
||||
case let .botCommand(command):
|
||||
return .action({
|
||||
item.controllerInteraction.longTap(.command(command), message)
|
||||
break loop
|
||||
case let .hashtag(_, hashtag):
|
||||
foundTapAction = true
|
||||
})
|
||||
case let .hashtag(_, hashtag):
|
||||
return .action({
|
||||
item.controllerInteraction.longTap(.hashtag(hashtag), message)
|
||||
break loop
|
||||
case .instantPage:
|
||||
break
|
||||
case .wallpaper:
|
||||
break
|
||||
case .theme:
|
||||
break
|
||||
case .call:
|
||||
break
|
||||
case .openMessage:
|
||||
foundTapAction = false
|
||||
break
|
||||
case let .timecode(timecode, text):
|
||||
foundTapAction = true
|
||||
if let mediaMessage = mediaMessage {
|
||||
})
|
||||
case .instantPage:
|
||||
break
|
||||
case .wallpaper:
|
||||
break
|
||||
case .theme:
|
||||
break
|
||||
case .call:
|
||||
break
|
||||
case .openMessage:
|
||||
break
|
||||
case let .timecode(timecode, text):
|
||||
if let mediaMessage = mediaMessage {
|
||||
return .action({
|
||||
item.controllerInteraction.longTap(.timecode(timecode, text), mediaMessage)
|
||||
}
|
||||
break loop
|
||||
case let .bankCard(number):
|
||||
foundTapAction = true
|
||||
})
|
||||
}
|
||||
case let .bankCard(number):
|
||||
return .action({
|
||||
item.controllerInteraction.longTap(.bankCard(number), message)
|
||||
case .tooltip:
|
||||
break
|
||||
})
|
||||
case .tooltip:
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundTapAction, let tapMessage = tapMessage {
|
||||
if let tapMessage = tapMessage {
|
||||
var subFrame = self.backgroundNode.frame
|
||||
if case .group = item.content {
|
||||
for contentNode in self.contentNodes {
|
||||
@ -2531,14 +2620,13 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
}
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, self, subFrame, recognizer)
|
||||
return false
|
||||
return .openContextMenu(tapMessage: tapMessage, selectAll: selectAll, subFrame: subFrame)
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
private func traceSelectionNodes(parent: ASDisplayNode, point: CGPoint) -> ASDisplayNode? {
|
||||
|
@ -118,7 +118,7 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode {
|
||||
let gestureRecognizer = ContextGesture(target: nil, action: nil)
|
||||
self.sendButton.view.addGestureRecognizer(gestureRecognizer)
|
||||
self.gestureRecognizer = gestureRecognizer
|
||||
gestureRecognizer.activated = { [weak self] gesture in
|
||||
gestureRecognizer.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
let gestureRecognizer = ContextGesture(target: nil, action: nil)
|
||||
self.gestureRecognizer = gestureRecognizer
|
||||
self.sendButton.view.addGestureRecognizer(gestureRecognizer)
|
||||
gestureRecognizer.activated = { [weak self] recognizer in
|
||||
gestureRecognizer.activated = { [weak self] recognizer, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ final class GridMessageItemNode: GridItemNode {
|
||||
self.containerNode.addSubnode(self.imageNode)
|
||||
self.containerNode.addSubnode(self.mediaBadgeNode)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let item = strongSelf.item, let controllerInteraction = strongSelf.controllerInteraction else {
|
||||
gesture.cancel()
|
||||
return
|
||||
@ -458,8 +458,7 @@ final class GridMessageItemNode: GridItemNode {
|
||||
let _ = controllerInteraction.openMessage(message, .default)
|
||||
}
|
||||
case .longTap:
|
||||
break
|
||||
//controllerInteraction.openMessageContextMenu(message, false, self, self.bounds, nil)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ final class MultiplexedVideoNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
return strongSelf.fileAt(point: point) != nil
|
||||
}
|
||||
|
||||
self.contextContainerNode.activated = { [weak self] gesture in
|
||||
self.contextContainerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let gestureLocation = gestureLocation else {
|
||||
return
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
self.containerNode.addSubnode(self.imageNode)
|
||||
self.containerNode.addSubnode(self.mediaBadgeNode)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
self.containerNode.activated = { [weak self] gesture, _ in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ public class PeerMediaCollectionController: TelegramBaseController {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let items = (chatAvailableMessageActionsImpl(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id])
|
||||
(chatAvailableMessageActionsImpl(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id])
|
||||
|> deliverOnMainQueue).start(next: { actions in
|
||||
var messageIds = Set<MessageId>()
|
||||
messageIds.insert(message.id)
|
||||
|
Binary file not shown.
@ -130,7 +130,12 @@ public final class WalletInfoScreen: ViewController {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.push(WalletTransactionInfoScreen(context: strongSelf.context, walletInfo: strongSelf.walletInfo, walletTransaction: transaction, walletState: (strongSelf.displayNode as! WalletInfoScreenNode).statePromise.get(), enableDebugActions: strongSelf.enableDebugActions))
|
||||
strongSelf.push(WalletTransactionInfoScreen(context: strongSelf.context, walletInfo: strongSelf.walletInfo, walletTransaction: transaction, walletState: (strongSelf.displayNode as! WalletInfoScreenNode).statePromise.get(), enableDebugActions: strongSelf.enableDebugActions, decryptionKeyUpdated: { key in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
(strongSelf.displayNode as! WalletInfoScreenNode).updateTransactionDecryptionKey(key)
|
||||
}))
|
||||
}, present: { [weak self] c, a in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -653,10 +658,11 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self, let (_, _) = strongSelf.validLayout else {
|
||||
return
|
||||
}
|
||||
let topInset = strongSelf.listNode.insets.top - strongSelf.listNode.headerInsets.top
|
||||
switch strongSelf.listNode.visibleContentOffset() {
|
||||
case let .known(offset):
|
||||
if offset < strongSelf.listNode.insets.top {
|
||||
if offset > strongSelf.listNode.insets.top / 2.0 {
|
||||
if offset < topInset {
|
||||
if offset > topInset / 2.0 {
|
||||
strongSelf.scrollToHideHeader()
|
||||
} else {
|
||||
strongSelf.scrollToTop()
|
||||
@ -844,6 +850,10 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
self.transactionDecryptionKeyDisposable?.dispose()
|
||||
}
|
||||
|
||||
func updateTransactionDecryptionKey(_ key: WalletTransactionDecryptionKey) {
|
||||
self.transactionDecryptionKey.set(.single(key))
|
||||
}
|
||||
|
||||
func scrollToHideHeader() {
|
||||
guard let (_, navigationHeight) = self.validLayout else {
|
||||
return
|
||||
|
@ -449,12 +449,12 @@ public final class WalletStrings: Equatable {
|
||||
public var Wallet_SecureStorageReset_Title: String { return self._s[219]! }
|
||||
public var Wallet_Receive_CommentHeader: String { return self._s[220]! }
|
||||
public var Wallet_Info_ReceiveGrams: String { return self._s[221]! }
|
||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
|
||||
}
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)
|
||||
|
@ -191,17 +191,19 @@ final class WalletTransactionInfoScreen: ViewController {
|
||||
private let walletInfo: WalletInfo?
|
||||
private var walletTransaction: WalletInfoTransaction
|
||||
private let walletState: Signal<(CombinedWalletState, Bool), NoError>
|
||||
private let decryptionKeyUpdated: (WalletTransactionDecryptionKey) -> Void
|
||||
private var presentationData: WalletPresentationData
|
||||
|
||||
private var walletStateDisposable: Disposable?
|
||||
private var combinedState: CombinedWalletState?
|
||||
private var reloadingState = false
|
||||
|
||||
public init(context: WalletContext, walletInfo: WalletInfo?, walletTransaction: WalletInfoTransaction, walletState: Signal<(CombinedWalletState, Bool), NoError>, enableDebugActions: Bool) {
|
||||
public init(context: WalletContext, walletInfo: WalletInfo?, walletTransaction: WalletInfoTransaction, walletState: Signal<(CombinedWalletState, Bool), NoError>, enableDebugActions: Bool, decryptionKeyUpdated: @escaping (WalletTransactionDecryptionKey) -> Void) {
|
||||
self.context = context
|
||||
self.walletInfo = walletInfo
|
||||
self.walletTransaction = walletTransaction
|
||||
self.walletState = walletState
|
||||
self.decryptionKeyUpdated = decryptionKeyUpdated
|
||||
|
||||
self.presentationData = context.presentationData
|
||||
|
||||
@ -238,7 +240,7 @@ final class WalletTransactionInfoScreen: ViewController {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = WalletTransactionInfoScreenNode(context: self.context, presentationData: self.presentationData, walletTransaction: self.walletTransaction)
|
||||
self.displayNode = WalletTransactionInfoScreenNode(context: self.context, presentationData: self.presentationData, walletTransaction: self.walletTransaction, decryptionKeyUpdated: self.decryptionKeyUpdated)
|
||||
(self.displayNode as! WalletTransactionInfoScreenNode).send = { [weak self] address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -284,6 +286,7 @@ final class WalletTransactionInfoScreen: ViewController {
|
||||
return
|
||||
}
|
||||
if let decryptionKey = decryptionKey {
|
||||
strongSelf.decryptionKeyUpdated(decryptionKey)
|
||||
let _ = (decryptWalletTransactions(decryptionKey: decryptionKey, transactions: [walletTransaction], tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self, let updatedTransaction = result.first else {
|
||||
@ -400,6 +403,7 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
|
||||
private var presentationData: WalletPresentationData
|
||||
private var walletTransaction: WalletInfoTransaction
|
||||
private let incoming: Bool
|
||||
private let decryptionKeyUpdated: (WalletTransactionDecryptionKey) -> Void
|
||||
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let timeNode: ImmediateTextNode
|
||||
@ -426,18 +430,21 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
|
||||
var displayFeesTooltip: ((ASDisplayNode, CGRect) -> Void)?
|
||||
var displayCopyContextMenu: ((ASDisplayNode, CGRect, String) -> Void)?
|
||||
|
||||
init(context: WalletContext, presentationData: WalletPresentationData, walletTransaction: WalletInfoTransaction) {
|
||||
init(context: WalletContext, presentationData: WalletPresentationData, walletTransaction: WalletInfoTransaction, decryptionKeyUpdated: @escaping (WalletTransactionDecryptionKey) -> Void) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.walletTransaction = walletTransaction
|
||||
self.decryptionKeyUpdated = decryptionKeyUpdated
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
self.titleNode.textAlignment = .center
|
||||
self.titleNode.maximumNumberOfLines = 1
|
||||
self.titleNode.displaysAsynchronously = false
|
||||
|
||||
self.timeNode = ImmediateTextNode()
|
||||
self.timeNode.textAlignment = .center
|
||||
self.timeNode.maximumNumberOfLines = 1
|
||||
self.timeNode.displaysAsynchronously = false
|
||||
|
||||
self.navigationBackgroundNode = ASDisplayNode()
|
||||
self.navigationBackgroundNode.backgroundColor = self.presentationData.theme.navigationBar.backgroundColor
|
||||
@ -453,6 +460,7 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
|
||||
self.feesNode.textAlignment = .center
|
||||
self.feesNode.maximumNumberOfLines = 2
|
||||
self.feesNode.lineSpacing = 0.35
|
||||
self.feesNode.displaysAsynchronously = false
|
||||
|
||||
self.feesInfoIconNode = ASImageNode()
|
||||
self.feesInfoIconNode.displaysAsynchronously = false
|
||||
@ -469,6 +477,7 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
|
||||
self.commentTextNode.textAlignment = .natural
|
||||
self.commentTextNode.maximumNumberOfLines = 0
|
||||
self.commentTextNode.isUserInteractionEnabled = false
|
||||
self.commentTextNode.displaysAsynchronously = false
|
||||
|
||||
self.commentSeparatorNode = ASDisplayNode()
|
||||
self.commentSeparatorNode.backgroundColor = self.presentationData.theme.list.itemPlainSeparatorColor
|
||||
@ -478,6 +487,7 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
|
||||
self.commentDecryptButtonTitle.textAlignment = .natural
|
||||
self.commentDecryptButtonTitle.maximumNumberOfLines = 0
|
||||
self.commentDecryptButtonTitle.isUserInteractionEnabled = false
|
||||
self.commentDecryptButtonTitle.displaysAsynchronously = false
|
||||
|
||||
self.commentDecryptButton = HighlightableButtonNode()
|
||||
self.commentDecryptButton.hitTestSlop = UIEdgeInsets(top: -10.0, left: -10.0, bottom: -10.0, right: -10.0)
|
||||
@ -486,6 +496,7 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
|
||||
self.addressTextNode.maximumNumberOfLines = 4
|
||||
self.addressTextNode.textAlignment = .justified
|
||||
self.addressTextNode.lineSpacing = 0.35
|
||||
self.addressTextNode.displaysAsynchronously = false
|
||||
|
||||
self.buttonNode = SolidRoundedButtonNode(title: "", icon: nil, theme: SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.setup.buttonFillColor, foregroundColor: self.presentationData.theme.setup.buttonForegroundColor), height: 50.0, cornerRadius: 10.0, gloss: false)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user