Opening progress for giveaway and gift link messages

This commit is contained in:
Ilya Laktyushin 2023-11-02 20:29:24 +04:00
parent f5c53ba9a0
commit 2179c8318d
47 changed files with 284 additions and 128 deletions

View File

@ -893,7 +893,7 @@ public protocol SharedAccountContext: AnyObject {
func chatAvailableMessageActions(engine: TelegramEngine, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>, messages: [EngineMessage.Id: EngineMessage], peers: [EnginePeer.Id: EnginePeer]) -> Signal<ChatAvailableMessageActions, NoError> func chatAvailableMessageActions(engine: TelegramEngine, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>, messages: [EngineMessage.Id: EngineMessage], peers: [EnginePeer.Id: EnginePeer]) -> Signal<ChatAvailableMessageActions, NoError>
func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError> func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError>
func resolveUrlWithProgress(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolveUrlResult, NoError> func resolveUrlWithProgress(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolveUrlResult, NoError>
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?, progress: Promise<Bool>?)
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void) func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void) func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void) func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)

View File

@ -208,7 +208,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
present(c, a) present(c, a)
}, dismissInput: { }, dismissInput: {
self?.dismissInput() self?.dismissInput()
}, contentContext: nil) }, contentContext: nil, progress: nil)
}) })
}, clearRecentSearch: { [weak self] in }, clearRecentSearch: { [weak self] in
guard let strongSelf = self else { guard let strongSelf = self else {

View File

@ -264,7 +264,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
} else { } else {
UIPasteboard.general.setData(data, forPasteboardType: dataType) UIPasteboard.general.setData(data, forPasteboardType: dataType)
} }
context.sharedContext.openResolvedUrl(.importStickers, context: context, urlContext: .generic, navigationController: arguments.getNavigationController(), forceExternal: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { c, a in arguments.presentController(c, a as? ViewControllerPresentationArguments) }, dismissInput: {}, contentContext: nil) context.sharedContext.openResolvedUrl(.importStickers, context: context, urlContext: .generic, navigationController: arguments.getNavigationController(), forceExternal: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { c, a in arguments.presentController(c, a as? ViewControllerPresentationArguments) }, dismissInput: {}, contentContext: nil, progress: nil)
} }
}) })
case .sendLogs: case .sendLogs:

View File

@ -1369,7 +1369,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
self?.present(c, a) self?.present(c, a)
}, dismissInput: { }, dismissInput: {
self?.view.endEditing(true) self?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
} }
} }
})) }))

View File

@ -370,13 +370,13 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent {
component: AnyComponent( component: AnyComponent(
Button( Button(
content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: giftReason, font: tableFont, textColor: giftCode.messageId != nil ? tableLinkColor : tableTextColor)))), content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: giftReason, font: tableFont, textColor: giftCode.messageId != nil ? tableLinkColor : tableTextColor)))),
isEnabled: true, automaticHighlight: giftCode.messageId != nil,
action: { action: {
if let messageId = giftCode.messageId { if let messageId = giftCode.messageId {
component.openMessage(messageId) component.openMessage(messageId)
} Queue.mainQueue().after(1.0) {
Queue.mainQueue().after(1.0) { component.cancel(false)
component.cancel(false) }
} }
} }
) )
@ -391,13 +391,13 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent {
component: AnyComponent( component: AnyComponent(
Button( Button(
content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: giftReason, font: tableFont, textColor: boost.giveawayMessageId != nil ? tableLinkColor : tableTextColor)))), content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: giftReason, font: tableFont, textColor: boost.giveawayMessageId != nil ? tableLinkColor : tableTextColor)))),
isEnabled: true, automaticHighlight: boost.giveawayMessageId != nil,
action: { action: {
if let messageId = boost.giveawayMessageId { if let messageId = boost.giveawayMessageId {
component.openMessage(messageId) component.openMessage(messageId)
} Queue.mainQueue().after(1.0) {
Queue.mainQueue().after(1.0) { component.cancel(false)
component.cancel(false) }
} }
} }
) )

View File

@ -2043,7 +2043,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak controller] c, arguments in }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak controller] c, arguments in
controller?.push(c) controller?.push(c)
}, dismissInput: {}, contentContext: nil) }, dismissInput: {}, contentContext: nil, progress: nil)
}) })
} }
} }

View File

@ -916,7 +916,7 @@ private final class QrCodeScanScreenNode: ViewControllerTracingNode, UIScrollVie
self?.controller?.present(c, in: .window(.root), with: a) self?.controller?.present(c, in: .window(.root), with: a)
}, dismissInput: { [weak self] in }, dismissInput: { [weak self] in
self?.view.endEditing(true) self?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
return true return true
} }

View File

@ -318,7 +318,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
pushControllerImpl?(controller) pushControllerImpl?(controller)
}, dismissInput: {}, contentContext: nil) }, dismissInput: {}, contentContext: nil, progress: nil)
}) })
} }
@ -359,7 +359,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
pushControllerImpl?(controller) pushControllerImpl?(controller)
}, dismissInput: {}, contentContext: nil) }, dismissInput: {}, contentContext: nil, progress: nil)
}) })
} }

View File

@ -225,7 +225,7 @@ public func logoutOptionsController(context: AccountContext, navigationControlle
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
pushControllerImpl?(controller) pushControllerImpl?(controller)
}, dismissInput: {}, contentContext: nil) }, dismissInput: {}, contentContext: nil, progress: nil)
}) })
} }

View File

@ -1068,7 +1068,7 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
present(.push, controller) present(.push, controller)
}, dismissInput: {}, contentContext: nil) }, dismissInput: {}, contentContext: nil, progress: nil)
}) })
}) })
allItems.append(faq) allItems.append(faq)

View File

@ -2217,7 +2217,7 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
} }
} else if let emojiString = self.emojiString, emojiString.count == 1 { } else if let emojiString = self.emojiString, emojiString.count == 1 {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
if shouldPlay { if shouldPlay {
@ -2298,7 +2298,7 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}) })
} else { } else {
return .optionalAction({ return .optionalAction({
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
}) })
} }
} else if let dice = self.telegramDice { } else if let dice = self.telegramDice {

View File

@ -12,7 +12,7 @@ private let sharedBackgroundImage = generateStretchableFilledCircleImage(radius:
public final class ChatMessageAttachedContentButtonNode: HighlightTrackingButtonNode { public final class ChatMessageAttachedContentButtonNode: HighlightTrackingButtonNode {
private let textNode: TextNode private let textNode: TextNode
private var iconView: UIImageView? private var iconView: UIImageView?
private let shimmerEffectNode: ShimmerEffectForegroundNode private var shimmerEffectNode: ShimmerEffectForegroundNode?
private var backgroundView: UIImageView? private var backgroundView: UIImageView?
@ -26,12 +26,8 @@ public final class ChatMessageAttachedContentButtonNode: HighlightTrackingButton
self.textNode = TextNode() self.textNode = TextNode()
self.textNode.isUserInteractionEnabled = false self.textNode.isUserInteractionEnabled = false
self.shimmerEffectNode = ShimmerEffectForegroundNode()
self.shimmerEffectNode.cornerRadius = 5.0
super.init() super.init()
self.addSubnode(self.shimmerEffectNode)
self.addSubnode(self.textNode) self.addSubnode(self.textNode)
self.highligthedChanged = { [weak self] highlighted in self.highligthedChanged = { [weak self] highlighted in
@ -58,18 +54,32 @@ public final class ChatMessageAttachedContentButtonNode: HighlightTrackingButton
guard let titleColor = self.titleColor else { guard let titleColor = self.titleColor else {
return return
} }
self.shimmerEffectNode.isHidden = false
self.shimmerEffectNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) let shimmerEffectNode: ShimmerEffectForegroundNode
if let current = self.shimmerEffectNode {
shimmerEffectNode = current
} else {
shimmerEffectNode = ShimmerEffectForegroundNode()
shimmerEffectNode.cornerRadius = 5.0
self.insertSubnode(shimmerEffectNode, at: 0)
self.shimmerEffectNode = shimmerEffectNode
}
shimmerEffectNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
let backgroundFrame = self.bounds let backgroundFrame = self.bounds
self.shimmerEffectNode.frame = backgroundFrame shimmerEffectNode.frame = backgroundFrame
self.shimmerEffectNode.updateAbsoluteRect(CGRect(origin: .zero, size: backgroundFrame.size), within: backgroundFrame.size) shimmerEffectNode.updateAbsoluteRect(CGRect(origin: .zero, size: backgroundFrame.size), within: backgroundFrame.size)
self.shimmerEffectNode.update(backgroundColor: .clear, foregroundColor: titleColor.withAlphaComponent(0.3), horizontal: true, effectSize: nil, globalTimeOffset: false, duration: nil) shimmerEffectNode.update(backgroundColor: .clear, foregroundColor: titleColor.withAlphaComponent(0.3), horizontal: true, effectSize: nil, globalTimeOffset: false, duration: nil)
} }
public func stopShimmering() { public func stopShimmering() {
self.shimmerEffectNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in guard let shimmerEffectNode = self.shimmerEffectNode else {
self?.shimmerEffectNode.isHidden = true return
}
self.shimmerEffectNode = nil
shimmerEffectNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak shimmerEffectNode] _ in
shimmerEffectNode?.removeFromSupernode()
}) })
} }

View File

@ -4221,11 +4221,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
if let item = self.item { if let item = self.item {
if let type = self.backgroundNode.type, case .none = type { if let type = self.backgroundNode.type, case .none = type {
return .optionalAction({ return .optionalAction({
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
}) })
} else { } else {
return .action(InternalBubbleTapAction.Action { return .action(InternalBubbleTapAction.Action {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
}) })
} }
} }

View File

@ -23,6 +23,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentButtonNode", "//submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentButtonNode",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -13,6 +13,7 @@ import ChatMessageDateAndStatusNode
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatMessageAttachedContentButtonNode import ChatMessageAttachedContentButtonNode
import ChatControllerInteraction
private let avatarFont = avatarPlaceholderFont(size: 16.0) private let avatarFont = avatarPlaceholderFont(size: 16.0)
@ -390,14 +391,14 @@ public class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
@objc private func contactTap(_ recognizer: UITapGestureRecognizer) { @objc private func contactTap(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state { if case .ended = recognizer.state {
if let item = self.item { if let item = self.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
} }
} }
@objc private func buttonPressed() { @objc private func buttonPressed() {
if let item = self.item { if let item = self.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
} }

View File

@ -22,6 +22,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/Chat/ChatMessageInteractiveFileNode", "//submodules/TelegramUI/Components/Chat/ChatMessageInteractiveFileNode",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -12,6 +12,7 @@ import ChatMessageDateAndStatusNode
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatMessageInteractiveFileNode import ChatMessageInteractiveFileNode
import ChatControllerInteraction
public class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode { public class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
public let interactiveFileNode: ChatMessageInteractiveFileNode public let interactiveFileNode: ChatMessageInteractiveFileNode
@ -47,7 +48,7 @@ public class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
self.interactiveFileNode.activateLocalContent = { [weak self] in self.interactiveFileNode.activateLocalContent = { [weak self] in
if let strongSelf = self, let item = strongSelf.item { if let strongSelf = self, let item = strongSelf.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
} }
@ -86,7 +87,7 @@ public class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
override public func accessibilityActivate() -> Bool { override public func accessibilityActivate() -> Bool {
if let item = self.item { if let item = self.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
return true return true
} }

View File

@ -39,7 +39,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
private let placeholderNode: StickerShimmerEffectNode private let placeholderNode: StickerShimmerEffectNode
private let animationNode: AnimatedStickerNode private let animationNode: AnimatedStickerNode
private let shimmerEffectNode: ShimmerEffectForegroundNode private var shimmerEffectNode: ShimmerEffectForegroundNode?
private let buttonNode: HighlightTrackingButtonNode private let buttonNode: HighlightTrackingButtonNode
private let buttonStarsNode: PremiumStarsNode private let buttonStarsNode: PremiumStarsNode
private let buttonTitleNode: TextNode private let buttonTitleNode: TextNode
@ -49,6 +49,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
private var isPlaying: Bool = false private var isPlaying: Bool = false
private var currentProgressDisposable: Disposable?
override public var visibility: ListViewItemNodeVisibility { override public var visibility: ListViewItemNodeVisibility {
didSet { didSet {
let wasVisible = oldValue != .none let wasVisible = oldValue != .none
@ -94,10 +96,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
self.buttonNode = HighlightTrackingButtonNode() self.buttonNode = HighlightTrackingButtonNode()
self.buttonNode.clipsToBounds = true self.buttonNode.clipsToBounds = true
self.buttonNode.cornerRadius = 17.0 self.buttonNode.cornerRadius = 17.0
self.shimmerEffectNode = ShimmerEffectForegroundNode()
self.shimmerEffectNode.cornerRadius = 17.0
self.placeholderNode = StickerShimmerEffectNode() self.placeholderNode = StickerShimmerEffectNode()
self.placeholderNode.isUserInteractionEnabled = false self.placeholderNode.isUserInteractionEnabled = false
self.placeholderNode.alpha = 0.75 self.placeholderNode.alpha = 0.75
@ -120,7 +119,6 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
self.addSubnode(self.animationNode) self.addSubnode(self.animationNode)
self.addSubnode(self.buttonNode) self.addSubnode(self.buttonNode)
self.buttonNode.addSubnode(self.shimmerEffectNode)
self.buttonNode.addSubnode(self.buttonStarsNode) self.buttonNode.addSubnode(self.buttonStarsNode)
self.addSubnode(self.buttonTitleNode) self.addSubnode(self.buttonTitleNode)
@ -149,32 +147,68 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
deinit { deinit {
self.animationDisposable?.dispose() self.animationDisposable?.dispose()
self.currentProgressDisposable?.dispose()
} }
@objc private func buttonPressed() { @objc private func buttonPressed() {
guard let item = self.item else { guard let item = self.item else {
return return
} }
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default, progress: self.makeProgress()))
self.startShimmering() }
Queue.mainQueue().after(0.75) {
self.stopShimmering() private func makeProgress() -> Promise<Bool> {
let progress = Promise<Bool>()
self.currentProgressDisposable?.dispose()
self.currentProgressDisposable = (progress.get()
|> distinctUntilChanged
|> deliverOnMainQueue).start(next: { [weak self] hasProgress in
guard let self else {
return
}
self.displayProgress = hasProgress
})
return progress
}
private var displayProgress = false {
didSet {
if self.displayProgress != oldValue {
if self.displayProgress {
self.startShimmering()
} else {
self.stopShimmering()
}
}
} }
} }
func startShimmering() { private func startShimmering() {
self.shimmerEffectNode.isHidden = false let shimmerEffectNode: ShimmerEffectForegroundNode
self.shimmerEffectNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) if let current = self.shimmerEffectNode {
shimmerEffectNode = current
} else {
shimmerEffectNode = ShimmerEffectForegroundNode()
shimmerEffectNode.cornerRadius = 17.0
self.buttonNode.insertSubnode(shimmerEffectNode, at: 0)
self.shimmerEffectNode = shimmerEffectNode
}
shimmerEffectNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
let backgroundFrame = self.buttonNode.frame let backgroundFrame = self.buttonNode.frame
self.shimmerEffectNode.frame = CGRect(origin: .zero, size: backgroundFrame.size) shimmerEffectNode.frame = CGRect(origin: .zero, size: backgroundFrame.size)
self.shimmerEffectNode.updateAbsoluteRect(CGRect(origin: .zero, size: backgroundFrame.size), within: backgroundFrame.size) shimmerEffectNode.updateAbsoluteRect(CGRect(origin: .zero, size: backgroundFrame.size), within: backgroundFrame.size)
self.shimmerEffectNode.update(backgroundColor: .clear, foregroundColor: UIColor.white.withAlphaComponent(0.2), horizontal: true, effectSize: nil, globalTimeOffset: false, duration: nil) shimmerEffectNode.update(backgroundColor: .clear, foregroundColor: UIColor.white.withAlphaComponent(0.15), horizontal: true, effectSize: nil, globalTimeOffset: false, duration: nil)
} }
func stopShimmering() { private func stopShimmering() {
self.shimmerEffectNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in guard let shimmerEffectNode = self.shimmerEffectNode else {
self?.shimmerEffectNode.isHidden = true return
}
self.shimmerEffectNode = nil
shimmerEffectNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak shimmerEffectNode] _ in
shimmerEffectNode?.removeFromSupernode()
}) })
} }

View File

@ -28,6 +28,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentButtonNode", "//submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentButtonNode",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -18,7 +18,7 @@ import ChatMessageDateAndStatusNode
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatMessageAttachedContentButtonNode import ChatMessageAttachedContentButtonNode
import UndoUI import ChatControllerInteraction
private let titleFont = Font.medium(15.0) private let titleFont = Font.medium(15.0)
private let textFont = Font.regular(13.0) private let textFont = Font.regular(13.0)
@ -68,7 +68,7 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode
} }
} }
private var setupTimestamp: Double? private var currentProgressDisposable: Disposable?
required public init() { required public init() {
self.placeholderNode = StickerShimmerEffectNode() self.placeholderNode = StickerShimmerEffectNode()
@ -137,22 +137,26 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode
item.controllerInteraction.openPeer(peer, .chat(textInputState: nil, subject: nil, peekData: nil), nil, .default) item.controllerInteraction.openPeer(peer, .chat(textInputState: nil, subject: nil, peekData: nil), nil, .default)
} }
} }
override public func accessibilityActivate() -> Bool {
self.buttonPressed()
return true
}
required public init?(coder aDecoder: NSCoder) { required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
deinit {
self.currentProgressDisposable?.dispose()
}
override public func didLoad() { override public func didLoad() {
super.didLoad() super.didLoad()
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.bubbleTap(_:))) let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.bubbleTap(_:)))
self.view.addGestureRecognizer(tapRecognizer) self.view.addGestureRecognizer(tapRecognizer)
} }
override public func accessibilityActivate() -> Bool {
self.buttonPressed()
return true
}
@objc private func bubbleTap(_ gestureRecognizer: UITapGestureRecognizer) { @objc private func bubbleTap(_ gestureRecognizer: UITapGestureRecognizer) {
guard let item = self.item else { guard let item = self.item else {
@ -592,7 +596,33 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode
@objc private func buttonPressed() { @objc private func buttonPressed() {
if let item = self.item { if let item = self.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default, progress: self.makeProgress()))
}
}
private func makeProgress() -> Promise<Bool> {
let progress = Promise<Bool>()
self.currentProgressDisposable?.dispose()
self.currentProgressDisposable = (progress.get()
|> distinctUntilChanged
|> deliverOnMainQueue).start(next: { [weak self] hasProgress in
guard let self else {
return
}
self.displayProgress = hasProgress
})
return progress
}
private var displayProgress = false {
didSet {
if self.displayProgress != oldValue {
if self.displayProgress {
self.buttonNode.startShimmering()
} else {
self.buttonNode.stopShimmering()
}
}
} }
} }

View File

@ -23,6 +23,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/Chat/ChatMessageInteractiveInstantVideoNode", "//submodules/TelegramUI/Components/Chat/ChatMessageInteractiveInstantVideoNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageInteractiveFileNode", "//submodules/TelegramUI/Components/Chat/ChatMessageInteractiveFileNode",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -13,6 +13,7 @@ import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatMessageInteractiveInstantVideoNode import ChatMessageInteractiveInstantVideoNode
import ChatMessageInteractiveFileNode import ChatMessageInteractiveFileNode
import ChatControllerInteraction
extension ChatMessageInteractiveInstantVideoNode.AnimateFileNodeDescription { extension ChatMessageInteractiveInstantVideoNode.AnimateFileNodeDescription {
convenience init(_ node: ChatMessageInteractiveFileNode) { convenience init(_ node: ChatMessageInteractiveFileNode) {
@ -127,7 +128,7 @@ public class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentN
self.interactiveFileNode.activateLocalContent = { [weak self] in self.interactiveFileNode.activateLocalContent = { [weak self] in
if let strongSelf = self, let item = strongSelf.item { if let strongSelf = self, let item = strongSelf.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
} }
@ -166,7 +167,7 @@ public class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentN
override public func accessibilityActivate() -> Bool { override public func accessibilityActivate() -> Bool {
if let item = self.item { if let item = self.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
return true return true
} }

View File

@ -1419,7 +1419,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
item.context.sharedContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: .voice) item.context.sharedContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: .voice)
} }
} else { } else {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
} }
@ -1573,7 +1573,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
} }
} }
if canPlay { if canPlay {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
}) })
} }

View File

@ -23,6 +23,7 @@ swift_library(
"//submodules/TelegramPresentationData", "//submodules/TelegramPresentationData",
"//submodules/TelegramUIPreferences", "//submodules/TelegramUIPreferences",
"//submodules/TelegramStringFormatting", "//submodules/TelegramStringFormatting",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
"//submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode", "//submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",

View File

@ -13,6 +13,7 @@ import LiveLocationPositionNode
import ChatMessageDateAndStatusNode import ChatMessageDateAndStatusNode
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatControllerInteraction
private let titleFont = Font.medium(14.0) private let titleFont = Font.medium(14.0)
private let liveTitleFont = Font.medium(16.0) private let liveTitleFont = Font.medium(16.0)
@ -47,7 +48,7 @@ public class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
override public func accessibilityActivate() -> Bool { override public func accessibilityActivate() -> Bool {
if let item = self.item { if let item = self.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
return true return true
} }
@ -511,7 +512,7 @@ public class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
@objc private func imageTap(_ recognizer: UITapGestureRecognizer) { @objc private func imageTap(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state { if case .ended = recognizer.state {
if let item = self.item { if let item = self.item {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
} }
} }

View File

@ -14,6 +14,7 @@ import ChatMessageDateAndStatusNode
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatMessageInteractiveMediaNode import ChatMessageInteractiveMediaNode
import ChatControllerInteraction
public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
override public var supportsMosaic: Bool { override public var supportsMosaic: Bool {
@ -52,7 +53,7 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
case .automaticPlayback: case .automaticPlayback:
openChatMessageMode = .automaticPlayback openChatMessageMode = .automaticPlayback
} }
let _ = item.controllerInteraction.openMessage(item.message, openChatMessageMode) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: openChatMessageMode))
} }
} }
} }

View File

@ -30,6 +30,7 @@ swift_library(
"//submodules/Markdown", "//submodules/Markdown",
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -20,6 +20,7 @@ import GalleryUI
import Markdown import Markdown
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatControllerInteraction
public class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode { public class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode {
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode? private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
@ -142,7 +143,7 @@ public class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleCont
guard let item = self.item else { guard let item = self.item else {
return return
} }
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (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, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {

View File

@ -1416,7 +1416,7 @@ public class ChatMessageStickerItemNode: ChatMessageItemView {
if let item = self.item, self.imageNode.frame.contains(location) { if let item = self.item, self.imageNode.frame.contains(location) {
return .optionalAction({ return .optionalAction({
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
}) })
} }

View File

@ -33,6 +33,7 @@ swift_library(
"//submodules/AvatarNode", "//submodules/AvatarNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -23,6 +23,7 @@ import AvatarStoryIndicatorComponent
import AvatarNode import AvatarNode
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import ChatControllerInteraction
public class ChatMessageStoryMentionContentNode: ChatMessageBubbleContentNode { public class ChatMessageStoryMentionContentNode: ChatMessageBubbleContentNode {
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode? private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
@ -136,7 +137,7 @@ public class ChatMessageStoryMentionContentNode: ChatMessageBubbleContentNode {
guard let item = self.item else { guard let item = self.item else {
return return
} }
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (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, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {

View File

@ -31,6 +31,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/WallpaperPreviewMedia", "//submodules/TelegramUI/Components/WallpaperPreviewMedia",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -21,6 +21,7 @@ import AudioTranscriptionPendingIndicatorComponent
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import WallpaperPreviewMedia import WallpaperPreviewMedia
import ChatControllerInteraction
public class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode { public class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode? private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
@ -181,7 +182,7 @@ public class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode
guard let item = self.item else { guard let item = self.item else {
return return
} }
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
private func updateProgress(_ progress: Float?) { private func updateProgress(_ progress: Float?) {

View File

@ -91,7 +91,7 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
case .automaticPlayback: case .automaticPlayback:
openChatMessageMode = .automaticPlayback openChatMessageMode = .automaticPlayback
} }
if !item.controllerInteraction.openMessage(item.message, openChatMessageMode) { if !item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: openChatMessageMode)) {
if let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content { if let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content {
var isConcealed = true var isConcealed = true
if item.message.text.contains(content.url) { if item.message.text.contains(content.url) {
@ -123,7 +123,7 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
} }
if let webpage = webPageContent { if let webpage = webPageContent {
if webpage.story != nil { if webpage.story != nil {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} else if webpage.instantPage != nil { } else if webpage.instantPage != nil {
strongSelf.contentNode.openMedia?(.default) strongSelf.contentNode.openMedia?(.default)
} else { } else {

View File

@ -1068,7 +1068,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self?.presentController(c, .window(.root), a) self?.presentController(c, .window(.root), a)
}, dismissInput: { }, dismissInput: {
self?.view.endEditing(true) self?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
case .wallpaper: case .wallpaper:
break break
case .theme: case .theme:

View File

@ -85,6 +85,16 @@ public struct NavigateToMessageParams {
} }
} }
public struct OpenMessageParams {
public var mode: ChatControllerInteractionOpenMessageMode
public var progress: Promise<Bool>?
public init(mode: ChatControllerInteractionOpenMessageMode, progress: Promise<Bool>? = nil) {
self.mode = mode
self.progress = progress
}
}
public final class ChatControllerInteraction { public final class ChatControllerInteraction {
public enum OpenPeerSource { public enum OpenPeerSource {
case `default` case `default`
@ -110,7 +120,7 @@ public final class ChatControllerInteraction {
} }
} }
public let openMessage: (Message, ChatControllerInteractionOpenMessageMode) -> Bool public let openMessage: (Message, OpenMessageParams) -> Bool
public let openPeer: (EnginePeer, ChatControllerInteractionNavigateToPeer, MessageReference?, OpenPeerSource) -> Void public let openPeer: (EnginePeer, ChatControllerInteractionNavigateToPeer, MessageReference?, OpenPeerSource) -> Void
public let openPeerMention: (String, Promise<Bool>?) -> Void public let openPeerMention: (String, Promise<Bool>?) -> Void
public let openMessageContextMenu: (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?, CGPoint?) -> Void public let openMessageContextMenu: (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?, CGPoint?) -> Void
@ -228,7 +238,7 @@ public final class ChatControllerInteraction {
public var enableFullTranslucency: Bool = true public var enableFullTranslucency: Bool = true
public init( public init(
openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openMessage: @escaping (Message, OpenMessageParams) -> Bool,
openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer, MessageReference?, OpenPeerSource) -> Void, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer, MessageReference?, OpenPeerSource) -> Void,
openPeerMention: @escaping (String, Promise<Bool>?) -> Void, openPeerMention: @escaping (String, Promise<Bool>?) -> Void,
openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?, CGPoint?) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?, CGPoint?) -> Void,

View File

@ -26,6 +26,7 @@ import AppBundle
import ChatControllerInteraction import ChatControllerInteraction
import InvisibleInkDustNode import InvisibleInkDustNode
import MediaPickerUI import MediaPickerUI
import ChatControllerInteraction
public enum PeerInfoPaneKey: Int32 { public enum PeerInfoPaneKey: Int32 {
case members case members
@ -1384,7 +1385,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode,
let listItemInteraction = ListMessageItemInteraction( let listItemInteraction = ListMessageItemInteraction(
openMessage: { message, mode in openMessage: { message, mode in
return chatControllerInteraction.openMessage(message, mode) return chatControllerInteraction.openMessage(message, OpenMessageParams(mode: mode))
}, },
openMessageContextMenu: { message, bool, node, rect, gesture in openMessageContextMenu: { message, bool, node, rect, gesture in
chatControllerInteraction.openMessageContextMenu(message, bool, node, rect, gesture, nil) chatControllerInteraction.openMessageContextMenu(message, bool, node, rect, gesture, nil)
@ -1469,7 +1470,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode,
} }
strongSelf.chatControllerInteraction.toggleMessagesSelection([item.message.id], toggledValue) strongSelf.chatControllerInteraction.toggleMessagesSelection([item.message.id], toggledValue)
} else { } else {
let _ = strongSelf.chatControllerInteraction.openMessage(item.message, .default) let _ = strongSelf.chatControllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default))
} }
} }
@ -1561,7 +1562,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode,
self._itemInteraction = VisualMediaItemInteraction( self._itemInteraction = VisualMediaItemInteraction(
openMessage: { [weak self] message in openMessage: { [weak self] message in
let _ = self?.chatControllerInteraction.openMessage(message, .default) let _ = self?.chatControllerInteraction.openMessage(message, OpenMessageParams(mode: .default))
}, },
openMessageContextActions: { [weak self] message, sourceNode, sourceRect, gesture in openMessageContextActions: { [weak self] message, sourceNode, sourceRect, gesture in
self?.chatControllerInteraction.openMessageContextActions(message, sourceNode, sourceRect, gesture) self?.chatControllerInteraction.openMessageContextActions(message, sourceNode, sourceRect, gesture)

View File

@ -2709,7 +2709,8 @@ final class StoryItemSetContainerSendMessage {
} }
view.endEditing(true) view.endEditing(true)
}, },
contentContext: self.progressPauseContext contentContext: self.progressPauseContext,
progress: nil
) )
} }

View File

@ -677,16 +677,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return true return true
} }
let controllerInteraction = ChatControllerInteraction(openMessage: { [weak self] message, mode in let controllerInteraction = ChatControllerInteraction(openMessage: { [weak self] message, params in
guard let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) else { guard let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) else {
return false return false
} }
let mode = params.mode
let displayVoiceMessageDiscardAlert: () -> Bool = { let displayVoiceMessageDiscardAlert: () -> Bool = {
if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
Queue.mainQueue().after(0.1, { Queue.mainQueue().after(0.1, {
let _ = strongSelf.controllerInteraction?.openMessage(message, mode) let _ = strongSelf.controllerInteraction?.openMessage(message, params)
}) })
} }
}, performAction: false) { }, performAction: false) {
@ -736,6 +738,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
break break
} }
} else if let _ = media as? TelegramMediaGiveaway { } else if let _ = media as? TelegramMediaGiveaway {
let progress = params.progress
let presentationData = strongSelf.presentationData
var signal = strongSelf.context.engine.payments.premiumGiveawayInfo(peerId: message.id.peerId, messageId: message.id) var signal = strongSelf.context.engine.payments.premiumGiveawayInfo(peerId: message.id.peerId, messageId: message.id)
let disposable: MetaDisposable let disposable: MetaDisposable
if let current = strongSelf.giveawayStatusDisposable { if let current = strongSelf.giveawayStatusDisposable {
@ -745,11 +750,26 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.giveawayStatusDisposable = disposable strongSelf.giveawayStatusDisposable = disposable
} }
let progressSignal = Signal<Never, NoError> { subscriber in let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
return EmptyDisposable if let progress {
progress.set(.single(true))
return ActionDisposable {
Queue.mainQueue().async() {
progress.set(.single(false))
}
}
} else {
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
self?.present(controller, in: .window(.root))
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
}
} }
|> runOn(Queue.mainQueue()) |> runOn(Queue.mainQueue())
|> delay(0.15, queue: Queue.mainQueue()) |> delay(0.25, queue: Queue.mainQueue())
let progressDisposable = progressSignal.startStrict() let progressDisposable = progressSignal.startStrict()
signal = signal signal = signal
@ -950,7 +970,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.push(controller) strongSelf.push(controller)
return true return true
case let .giftCode(slug, _, _, _, _): case let .giftCode(slug, _, _, _, _):
strongSelf.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: message.id) strongSelf.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: message.id, progress: params.progress)
return true return true
case let .suggestedProfilePhoto(image): case let .suggestedProfilePhoto(image):
strongSelf.chatDisplayNode.dismissInput() strongSelf.chatDisplayNode.dismissInput()
@ -3684,7 +3704,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if case let .visible(fraction, _) = itemNode.visibility, fraction > 0.7 { if case let .visible(fraction, _) = itemNode.visibility, fraction > 0.7 {
action(Double(timestamp)) action(Double(timestamp))
} else { } else {
let _ = strongSelf.controllerInteraction?.openMessage(message, .timecode(Double(timestamp))) let _ = strongSelf.controllerInteraction?.openMessage(message, OpenMessageParams(mode: .timecode(Double(timestamp))))
} }
found = true found = true
} }
@ -3696,7 +3716,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
messageId = sourceMessageId messageId = sourceMessageId
} }
if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) { if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) {
let _ = strongSelf.controllerInteraction?.openMessage(message, .timecode(Double(timestamp))) let _ = strongSelf.controllerInteraction?.openMessage(message, OpenMessageParams(mode: .timecode(Double(timestamp))))
} else { } else {
strongSelf.navigateToMessage(messageLocation: .id(messageId, NavigateToMessageParams(timestamp: Double(timestamp), quote: nil)), animated: true, forceInCurrentChat: true) strongSelf.navigateToMessage(messageLocation: .id(messageId, NavigateToMessageParams(timestamp: Double(timestamp), quote: nil)), animated: true, forceInCurrentChat: true)
} }
@ -8077,12 +8097,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.scheduledScrollToMessageId = nil strongSelf.scheduledScrollToMessageId = nil
if let timecode = params.timestamp, message.id == messageId { if let timecode = params.timestamp, message.id == messageId {
Queue.mainQueue().after(0.2) { Queue.mainQueue().after(0.2) {
let _ = strongSelf.controllerInteraction?.openMessage(message, .timecode(timecode)) let _ = strongSelf.controllerInteraction?.openMessage(message, OpenMessageParams(mode: .timecode(timecode)))
} }
} }
} else if case let .message(_, _, maybeTimecode) = strongSelf.subject, let timecode = maybeTimecode, initial { } else if case let .message(_, _, maybeTimecode) = strongSelf.subject, let timecode = maybeTimecode, initial {
Queue.mainQueue().after(0.2) { Queue.mainQueue().after(0.2) {
let _ = strongSelf.controllerInteraction?.openMessage(message, .timecode(timecode)) let _ = strongSelf.controllerInteraction?.openMessage(message, OpenMessageParams(mode: .timecode(timecode)))
} }
} }
} }
@ -12057,7 +12077,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var completed = false var completed = false
self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in
if !completed, let itemNode = itemNode as? ChatMessageItemView, let message = itemNode.item?.message, let (_, soundEnabled, _, _, _) = itemNode.playMediaWithSound(), soundEnabled { if !completed, let itemNode = itemNode as? ChatMessageItemView, let message = itemNode.item?.message, let (_, soundEnabled, _, _, _) = itemNode.playMediaWithSound(), soundEnabled {
let _ = self.controllerInteraction?.openMessage(message, .landscape) let _ = self.controllerInteraction?.openMessage(message, OpenMessageParams(mode: .landscape))
completed = true completed = true
} }
} }
@ -14919,7 +14939,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let strongSelf = self, case let .result(info, _, _) = stickerPack { if let strongSelf = self, case let .result(info, _, _) = stickerPack {
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, loop: true, title: info.title, text: strongSelf.presentationData.strings.Stickers_PremiumPackInfoText, undoText: strongSelf.presentationData.strings.Stickers_PremiumPackView, customAction: nil), elevatedLayout: false, action: { [weak self] action in strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, loop: true, title: info.title, text: strongSelf.presentationData.strings.Stickers_PremiumPackInfoText, undoText: strongSelf.presentationData.strings.Stickers_PremiumPackView, customAction: nil), elevatedLayout: false, action: { [weak self] action in
if let strongSelf = self, action == .undo { if let strongSelf = self, action == .undo {
let _ = strongSelf.controllerInteraction?.openMessage(message, .default) let _ = strongSelf.controllerInteraction?.openMessage(message, OpenMessageParams(mode: .default))
} }
return false return false
}), in: .current) }), in: .current)
@ -15404,7 +15424,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.raiseToListenActivateRecordingTimer?.invalidate() self.raiseToListenActivateRecordingTimer?.invalidate()
self.raiseToListenActivateRecordingTimer = nil self.raiseToListenActivateRecordingTimer = nil
if let messageToListen = self.firstLoadedMessageToListen() { if let messageToListen = self.firstLoadedMessageToListen() {
let _ = self.controllerInteraction?.openMessage(messageToListen, .default) let _ = self.controllerInteraction?.openMessage(messageToListen, OpenMessageParams(mode: .default))
} else { } else {
let timeout = (self.voicePlaylistDidEndTimestamp + 1.0) - CACurrentMediaTime() let timeout = (self.voicePlaylistDidEndTimestamp + 1.0) - CACurrentMediaTime()
self.raiseToListenActivateRecordingTimer = SwiftSignalKit.Timer(timeout: max(0.0, timeout), repeat: false, completion: { [weak self] in self.raiseToListenActivateRecordingTimer = SwiftSignalKit.Timer(timeout: max(0.0, timeout), repeat: false, completion: { [weak self] in
@ -16421,7 +16441,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
if case let .id(_, params) = messageLocation, let timecode = params.timestamp { if case let .id(_, params) = messageLocation, let timecode = params.timestamp {
let _ = self.controllerInteraction?.openMessage(message, .timecode(timecode)) let _ = self.controllerInteraction?.openMessage(message, OpenMessageParams(mode: .timecode(timecode)))
} }
} else if case let .index(index) = messageLocation, index.id.id == 0, index.timestamp > 0, case .scheduledMessages = self.presentationInterfaceState.subject { } else if case let .index(index) = messageLocation, index.id.id == 0, index.timestamp > 0, case .scheduledMessages = self.presentationInterfaceState.subject {
self.chatDisplayNode.historyNode.scrollToMessage(from: scrollFromIndex, to: index, animated: animated, scrollPosition: scrollPosition) self.chatDisplayNode.historyNode.scrollToMessage(from: scrollFromIndex, to: index, animated: animated, scrollPosition: scrollPosition)
@ -17475,7 +17495,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})) }))
} }
func openResolved(result: ResolvedUrl, sourceMessageId: MessageId?, forceExternal: Bool = false, concealed: Bool = false, commit: @escaping () -> Void = {}) { func openResolved(result: ResolvedUrl, sourceMessageId: MessageId?, progress: Promise<Bool>? = nil, forceExternal: Bool = false, concealed: Bool = false, commit: @escaping () -> Void = {}) {
guard let peerId = self.chatLocation.peerId else { guard let peerId = self.chatLocation.peerId else {
return return
} }
@ -17485,13 +17505,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
let dismissWebAppContollers: () -> Void = { let dismissWebAppContollers: () -> Void = {
// if let currentWebAppController = strongSelf.currentWebAppController {
// strongSelf.currentWebAppController = nil
// currentWebAppController.dismiss(animated: true, completion: nil)
// } else if let currentWebAppController = strongSelf.currentMenuWebAppController {
// strongSelf.currentMenuWebAppController = nil
// currentWebAppController.dismiss(animated: true, completion: nil)
// }
} }
switch navigation { switch navigation {
@ -17568,7 +17581,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
}, dismissInput: { [weak self] in }, dismissInput: { [weak self] in
self?.chatDisplayNode.dismissInput() self?.chatDisplayNode.dismissInput()
}, contentContext: nil) }, contentContext: nil, progress: progress)
} }
func openUrl(_ url: String, concealed: Bool, forceExternal: Bool = false, skipUrlAuth: Bool = false, skipConcealedAlert: Bool = false, message: Message? = nil, allowInlineWebpageResolution: Bool = false, progress: Promise<Bool>? = nil, commit: @escaping () -> Void = {}) { func openUrl(_ url: String, concealed: Bool, forceExternal: Bool = false, skipUrlAuth: Bool = false, skipConcealedAlert: Bool = false, message: Message? = nil, allowInlineWebpageResolution: Bool = false, progress: Promise<Bool>? = nil, commit: @escaping () -> Void = {}) {
@ -17589,7 +17602,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} else if content.file == nil, (content.image == nil || content.isMediaLargeByDefault == true || content.isMediaLargeByDefault == nil), let embedUrl = content.embedUrl, !embedUrl.isEmpty { } else if content.file == nil, (content.image == nil || content.isMediaLargeByDefault == true || content.isMediaLargeByDefault == nil), let embedUrl = content.embedUrl, !embedUrl.isEmpty {
progress?.set(.single(false)) progress?.set(.single(false))
if let controllerInteraction = self.controllerInteraction { if let controllerInteraction = self.controllerInteraction {
if controllerInteraction.openMessage(message, .default) { if controllerInteraction.openMessage(message, OpenMessageParams(mode: .default)) {
return return
} }
} }

View File

@ -30,6 +30,7 @@ import ChatMessageItem
import ChatMessageItemImpl import ChatMessageItemImpl
import ChatMessageItemView import ChatMessageItemView
import ChatMessageTransitionNode import ChatMessageTransitionNode
import ChatControllerInteraction
struct ChatTopVisibleMessageRange: Equatable { struct ChatTopVisibleMessageRange: Equatable {
var lowerBound: MessageIndex var lowerBound: MessageIndex
@ -200,7 +201,7 @@ private func maxMessageIndexForEntries(_ view: ChatHistoryView, indexRange: (Int
extension ListMessageItemInteraction { extension ListMessageItemInteraction {
convenience init(controllerInteraction: ChatControllerInteraction) { convenience init(controllerInteraction: ChatControllerInteraction) {
self.init(openMessage: { message, mode -> Bool in self.init(openMessage: { message, mode -> Bool in
return controllerInteraction.openMessage(message, mode) return controllerInteraction.openMessage(message, OpenMessageParams(mode: mode))
}, openMessageContextMenu: { message, bool, node, rect, gesture in }, openMessageContextMenu: { message, bool, node, rect, gesture in
controllerInteraction.openMessageContextMenu(message, bool, node, rect, gesture, nil) controllerInteraction.openMessageContextMenu(message, bool, node, rect, gesture, nil)
}, toggleMessagesSelection: { messageId, selected in }, toggleMessagesSelection: { messageId, selected in

View File

@ -1501,7 +1501,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.StickerPack_ViewPack, icon: { theme in actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.StickerPack_ViewPack, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Sticker"), color: theme.actionSheet.primaryTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Sticker"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in }, action: { _, f in
let _ = controllerInteraction.openMessage(message, .default) let _ = controllerInteraction.openMessage(message, OpenMessageParams(mode: .default))
f(.dismissWithoutContent) f(.dismissWithoutContent)
}))) })))
} }

View File

@ -48,7 +48,22 @@ private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatContr
} }
} }
func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)? = nil, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) { func openResolvedUrlImpl(
_ resolvedUrl: ResolvedUrl,
context: AccountContext,
urlContext: OpenURLContext,
navigationController: NavigationController?,
forceExternal: Bool,
openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void,
sendFile: ((FileMediaReference) -> Void)?,
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?,
requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)? = nil,
joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?,
present: @escaping (ViewController, Any?) -> Void,
dismissInput: @escaping () -> Void,
contentContext: Any?,
progress: Promise<Bool>?
) {
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
if case let .chat(_, maybeUpdatedPresentationData) = urlContext { if case let .chat(_, maybeUpdatedPresentationData) = urlContext {
updatedPresentationData = maybeUpdatedPresentationData updatedPresentationData = maybeUpdatedPresentationData
@ -890,7 +905,32 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
if let updatedPresentationData, updatedPresentationData.initial.theme.overallDarkAppearance { if let updatedPresentationData, updatedPresentationData.initial.theme.overallDarkAppearance {
forceDark = true forceDark = true
} }
let _ = (context.engine.payments.checkPremiumGiftCode(slug: slug)
let progressSignal = Signal<Never, NoError> { subscriber in
if let progress {
progress.set(.single(true))
return ActionDisposable {
Queue.mainQueue().async() {
progress.set(.single(false))
}
}
} else {
return EmptyDisposable
}
}
|> runOn(Queue.mainQueue())
|> delay(0.25, queue: Queue.mainQueue())
let progressDisposable = progressSignal.startStrict()
var signal = context.engine.payments.checkPremiumGiftCode(slug: slug)
signal = signal
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
}
let _ = (signal
|> deliverOnMainQueue).startStandalone(next: { [weak navigationController] giftCode in |> deliverOnMainQueue).startStandalone(next: { [weak navigationController] giftCode in
if let giftCode { if let giftCode {
var dismissImpl: (() -> Void)? var dismissImpl: (() -> Void)?

View File

@ -240,7 +240,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
context.sharedContext.applicationBindings.getWindowHost()?.present(c, on: .root, blockInteraction: false, completion: {}) context.sharedContext.applicationBindings.getWindowHost()?.present(c, on: .root, blockInteraction: false, completion: {})
}, dismissInput: { }, dismissInput: {
dismissInput() dismissInput()
}, contentContext: nil) }, contentContext: nil, progress: nil)
} }
} }

View File

@ -2405,7 +2405,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
} }
) )
self._chatInterfaceInteraction = ChatControllerInteraction(openMessage: { [weak self] message, mode in self._chatInterfaceInteraction = ChatControllerInteraction(openMessage: { [weak self] message, _ in
guard let strongSelf = self else { guard let strongSelf = self else {
return false return false
} }
@ -4518,7 +4518,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
self?.controller?.present(c, in: .window(.root), with: a) self?.controller?.present(c, in: .window(.root), with: a)
}, dismissInput: { [weak self] in }, dismissInput: { [weak self] in
self?.view.endEditing(true) self?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
} }
private func openUrl(url: String, concealed: Bool, external: Bool, forceExternal: Bool = false, commit: @escaping () -> Void = {}) { private func openUrl(url: String, concealed: Bool, external: Bool, forceExternal: Bool = false, commit: @escaping () -> Void = {}) {
@ -4544,7 +4544,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
self?.controller?.present(c, in: .window(.root), with: a) self?.controller?.present(c, in: .window(.root), with: a)
}, dismissInput: { }, dismissInput: {
self?.view.endEditing(true) self?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
}) })
} }
@ -5466,7 +5466,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
return return
} }
self.controller?.view.endEditing(true) self.controller?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
}, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?))) }, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
c.pushItems(items: .single(ContextController.Items(content: .list(subItems)))) c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
@ -5655,7 +5655,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
return return
} }
self.controller?.view.endEditing(true) self.controller?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
}, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?))) }, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
c.pushItems(items: .single(ContextController.Items(content: .list(subItems)))) c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
@ -5783,7 +5783,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
return return
} }
self.controller?.view.endEditing(true) self.controller?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
}, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?))) }, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
c.pushItems(items: .single(ContextController.Items(content: .list(subItems)))) c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
@ -7056,7 +7056,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
controller?.present(c, in: .window(.root), with: a) controller?.present(c, in: .window(.root), with: a)
}, dismissInput: { [weak controller] in }, dismissInput: { [weak controller] in
controller?.view.endEditing(true) controller?.view.endEditing(true)
}, contentContext: nil) }, contentContext: nil, progress: nil)
} }
private func performBotCommand(command: PeerInfoBotCommand) { private func performBotCommand(command: PeerInfoBotCommand) {
@ -8689,7 +8689,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
strongSelf.context.sharedContext.openResolvedUrl(resolvedUrl, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, forceExternal: false, openPeer: { peer, navigation in strongSelf.context.sharedContext.openResolvedUrl(resolvedUrl, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, forceExternal: false, openPeer: { peer, navigation in
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak self] controller, arguments in }, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak self] controller, arguments in
self?.controller?.push(controller) self?.controller?.push(controller)
}, dismissInput: {}, contentContext: nil) }, dismissInput: {}, contentContext: nil, progress: nil)
} }
}) })
} }

View File

@ -834,7 +834,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
self._itemInteraction = VisualMediaItemInteraction( self._itemInteraction = VisualMediaItemInteraction(
openMessage: { [weak self] message in openMessage: { [weak self] message in
let _ = self?.chatControllerInteraction.openMessage(message, .default) let _ = self?.chatControllerInteraction.openMessage(message, OpenMessageParams(mode: .default))
}, },
openMessageContextActions: { [weak self] message, sourceNode, sourceRect, gesture in openMessageContextActions: { [weak self] message, sourceNode, sourceRect, gesture in
self?.chatControllerInteraction.openMessageContextActions(message, sourceNode, sourceRect, gesture) self?.chatControllerInteraction.openMessageContextActions(message, sourceNode, sourceRect, gesture)

View File

@ -1416,8 +1416,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return resolveUrlImpl(context: context, peerId: peerId, url: url, skipUrlAuth: skipUrlAuth) return resolveUrlImpl(context: context, peerId: peerId, url: url, skipUrlAuth: skipUrlAuth)
} }
public func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) { public func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?, progress: Promise<Bool>?) {
openResolvedUrlImpl(resolvedUrl, context: context, urlContext: urlContext, navigationController: navigationController, forceExternal: forceExternal, openPeer: openPeer, sendFile: sendFile, sendSticker: sendSticker, requestMessageActionUrlAuth: requestMessageActionUrlAuth, joinVoiceChat: joinVoiceChat, present: present, dismissInput: dismissInput, contentContext: contentContext) openResolvedUrlImpl(resolvedUrl, context: context, urlContext: urlContext, navigationController: navigationController, forceExternal: forceExternal, openPeer: openPeer, sendFile: sendFile, sendSticker: sendSticker, requestMessageActionUrlAuth: requestMessageActionUrlAuth, joinVoiceChat: joinVoiceChat, present: present, dismissInput: dismissInput, contentContext: contentContext, progress: progress)
} }
public func makeDeviceContactInfoController(context: AccountContext, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController { public func makeDeviceContactInfoController(context: AccountContext, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController {

View File

@ -54,7 +54,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n
sendSticker: nil, sendSticker: nil,
requestMessageActionUrlAuth: nil, requestMessageActionUrlAuth: nil,
joinVoiceChat: nil, joinVoiceChat: nil,
present: presentImpl, dismissInput: {}, contentContext: nil) present: presentImpl, dismissInput: {}, contentContext: nil, progress: nil)
} }
let openLinkImpl: (String) -> Void = { [weak controller] url in let openLinkImpl: (String) -> Void = { [weak controller] url in
@ -94,7 +94,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n
if let navigationController = controller.navigationController as? NavigationController { if let navigationController = controller.navigationController as? NavigationController {
openResolvedUrlImpl(result, context: context, urlContext: peerId.flatMap { .chat(peerId: $0, updatedPresentationData: nil) } ?? .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigateToPeer in openResolvedUrlImpl(result, context: context, urlContext: peerId.flatMap { .chat(peerId: $0, updatedPresentationData: nil) } ?? .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigateToPeer in
openResolvedPeerImpl(peer, navigateToPeer) openResolvedPeerImpl(peer, navigateToPeer)
}, sendFile: nil, sendSticker: nil, joinVoiceChat: nil, present: { c, a in }, dismissInput: {}, contentContext: nil) }, sendFile: nil, sendSticker: nil, joinVoiceChat: nil, present: { c, a in }, dismissInput: {}, contentContext: nil, progress: nil)
} }
default: default:
break break