Reaction improvements

This commit is contained in:
Ali 2021-12-22 20:35:45 +04:00
parent 216ddc4a6e
commit 4803a3c6cc
19 changed files with 215 additions and 75 deletions

View File

@ -487,6 +487,12 @@ private func compressFrame(width: Int, height: Int, rgbData: Data) -> Data? {
}
private final class AnimatedStickerDirectFrameSourceCache {
private enum FrameRangeResult {
case range(Range<Int>)
case notFound
case corruptedFile
}
private let queue: Queue
private let storeQueue: Queue
private let file: ManagedFileImpl
@ -548,27 +554,31 @@ private final class AnimatedStickerDirectFrameSourceCache {
}
}
private func readFrameRange(index: Int) -> Range<Int>? {
private func readFrameRange(index: Int) -> FrameRangeResult {
if index < 0 || index >= self.frameCount {
return nil
return .notFound
}
self.file.seek(position: Int64(index * 4 * 2))
var offset: Int32 = 0
var length: Int32 = 0
if self.file.read(&offset, 4) != 4 {
return nil
return .corruptedFile
}
if self.file.read(&length, 4) != 4 {
return nil
return .corruptedFile
}
if length == 0 {
return nil
return .notFound
}
if length < 0 || offset < 0 {
return nil
return .corruptedFile
}
return (Int(offset) ..< Int(offset + length))
if Int64(offset) + Int64(length) > 100 * 1024 * 1024 {
return .corruptedFile
}
return .range(Int(offset) ..< Int(offset + length))
}
func storeUncompressedRgbFrame(index: Int, rgbData: Data) {
@ -617,43 +627,52 @@ private final class AnimatedStickerDirectFrameSourceCache {
if index < 0 || index >= self.frameCount {
return nil
}
guard let range = self.readFrameRange(index: index) else {
return nil
}
self.file.seek(position: Int64(range.lowerBound))
let length = range.upperBound - range.lowerBound
let compressedData = self.file.readData(count: length)
if compressedData.count != length {
return nil
}
let rangeResult = self.readFrameRange(index: index)
var frameData: Data?
let decodeBufferLength = self.decodeBuffer.count
compressedData.withUnsafeBytes { buffer -> Void in
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
return
switch rangeResult {
case let .range(range):
self.file.seek(position: Int64(range.lowerBound))
let length = range.upperBound - range.lowerBound
let compressedData = self.file.readData(count: length)
if compressedData.count != length {
return nil
}
self.scratchBuffer.withUnsafeMutableBytes { scratchBuffer -> Void in
guard let scratchBytes = scratchBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
var frameData: Data?
let decodeBufferLength = self.decodeBuffer.count
compressedData.withUnsafeBytes { buffer -> Void in
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
return
}
self.decodeBuffer.withUnsafeMutableBytes { decodeBuffer -> Void in
guard let decodeBytes = decodeBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
self.scratchBuffer.withUnsafeMutableBytes { scratchBuffer -> Void in
guard let scratchBytes = scratchBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
return
}
let resultLength = compression_decode_buffer(decodeBytes, decodeBufferLength, bytes, length, UnsafeMutableRawPointer(scratchBytes), COMPRESSION_LZFSE)
frameData = Data(bytes: decodeBytes, count: resultLength)
self.decodeBuffer.withUnsafeMutableBytes { decodeBuffer -> Void in
guard let decodeBytes = decodeBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
return
}
let resultLength = compression_decode_buffer(decodeBytes, decodeBufferLength, bytes, length, UnsafeMutableRawPointer(scratchBytes), COMPRESSION_LZFSE)
frameData = Data(bytes: decodeBytes, count: resultLength)
}
}
}
return frameData
case .notFound:
return nil
case .corruptedFile:
self.file.truncate(count: 0)
self.initializeFrameTable()
return nil
}
return frameData
}
}

View File

@ -78,14 +78,14 @@ public final class JoinLinkPreviewController: ViewController {
if let strongSelf = self {
strongSelf.resolvedState = result
switch result {
case let .invite(flags, title, about, photoRepresentation, participantsCount, participants):
if flags.requestNeeded {
case let .invite(invite):
if invite.flags.requestNeeded {
strongSelf.isRequest = true
strongSelf.isGroup = !flags.isBroadcast
strongSelf.controllerNode.setRequestPeer(image: photoRepresentation, title: title, about: about, memberCount: participantsCount, isGroup: !flags.isBroadcast)
strongSelf.isGroup = !invite.flags.isBroadcast
strongSelf.controllerNode.setRequestPeer(image: invite.photoRepresentation, title: invite.title, about: invite.about, memberCount: invite.participantsCount, isGroup: !invite.flags.isBroadcast)
} else {
let data = JoinLinkPreviewData(isGroup: participants != nil, isJoined: false)
strongSelf.controllerNode.setInvitePeer(image: photoRepresentation, title: title, memberCount: participantsCount, members: participants?.map({ EnginePeer($0) }) ?? [], data: data)
let data = JoinLinkPreviewData(isGroup: invite.participants != nil, isJoined: false)
strongSelf.controllerNode.setInvitePeer(image: invite.photoRepresentation, title: invite.title, memberCount: invite.participantsCount, members: invite.participants?.map({ $0 }) ?? [], data: data)
}
case let .alreadyJoined(peerId):
strongSelf.navigateToPeer(peerId, nil)

View File

@ -185,11 +185,16 @@ final class ReactionContextBackgroundNode: ASDisplayNode {
self.backgroundLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
self.backgroundLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
self.backgroundShadowLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
self.backgroundShadowLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
}
func animateOut() {
self.backgroundLayer.animateAlpha(from: CGFloat(self.backgroundLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
self.backgroundShadowLayer.animateAlpha(from: CGFloat(self.backgroundShadowLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
self.largeCircleLayer.animateAlpha(from: CGFloat(self.largeCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
self.largeCircleShadowLayer.animateAlpha(from: CGFloat(self.largeCircleShadowLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
self.smallCircleLayer.animateAlpha(from: CGFloat(self.smallCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
self.smallCircleShadowLayer.animateAlpha(from: CGFloat(self.smallCircleShadowLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
}
}

View File

@ -17,17 +17,20 @@ public final class ReactionContextItem {
}
public let reaction: ReactionContextItem.Reaction
public let appearAnimation: TelegramMediaFile
public let stillAnimation: TelegramMediaFile
public let listAnimation: TelegramMediaFile
public let applicationAnimation: TelegramMediaFile
public init(
reaction: ReactionContextItem.Reaction,
appearAnimation: TelegramMediaFile,
stillAnimation: TelegramMediaFile,
listAnimation: TelegramMediaFile,
applicationAnimation: TelegramMediaFile
) {
self.reaction = reaction
self.appearAnimation = appearAnimation
self.stillAnimation = stillAnimation
self.listAnimation = listAnimation
self.applicationAnimation = applicationAnimation

View File

@ -148,6 +148,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
standaloneReactionAnimation.animateReactionSelection(
context: item.context, theme: item.theme, reaction: ReactionContextItem(
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
appearAnimation: reaction.appearAnimation,
stillAnimation: reaction.selectAnimation,
listAnimation: reaction.activateAnimation,
applicationAnimation: reaction.effectAnimation

View File

@ -2,14 +2,17 @@ import Foundation
import Postbox
public final class AdMessageAttribute: MessageAttribute {
public enum MessageTarget {
case peer(id: EnginePeer.Id, message: EngineMessage.Id?, startParam: String?)
case join(title: String, joinHash: String)
}
public let opaqueId: Data
public let startParam: String?
public let messageId: MessageId?
public let target: MessageTarget
public init(opaqueId: Data, startParam: String?, messageId: MessageId?) {
public init(opaqueId: Data, target: MessageTarget) {
self.opaqueId = opaqueId
self.startParam = startParam
self.messageId = messageId
self.target = target
}
public init(decoder: PostboxDecoder) {

View File

@ -234,6 +234,7 @@ func managedSynchronizeAvailableReactions(postbox: Postbox, network: Network) ->
for reaction in availableReactions.reactions {
resources.append(reaction.staticIcon.resource)
resources.append(reaction.appearAnimation.resource)
resources.append(reaction.selectAnimation.resource)
resources.append(reaction.activateAnimation.resource)
resources.append(reaction.effectAnimation.resource)

View File

@ -22,19 +22,39 @@ private class AdMessagesHistoryContextImpl {
enum CodingKeys: String, CodingKey {
case peer
case invite
}
struct Invite: Equatable, Codable {
var title: String
var joinHash: String
}
case peer(PeerId)
case invite(Invite)
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let peer = try container.decodeIfPresent(Int64.self, forKey: .peer) {
self = .peer(PeerId(peer))
} else if let invite = try container.decodeIfPresent(Invite.self, forKey: .invite) {
self = .invite(invite)
} else {
throw DecodingError.generic
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case let .peer(peerId):
try container.encode(peerId.toInt64(), forKey: .peer)
case let .invite(invite):
try container.encode(invite, forKey: .invite)
}
}
}
public let opaqueId: Data
@ -133,7 +153,14 @@ private class AdMessagesHistoryContextImpl {
func toMessage(peerId: PeerId, transaction: Transaction) -> Message? {
var attributes: [MessageAttribute] = []
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, startParam: self.startParam, messageId: self.messageId))
let target: AdMessageAttribute.MessageTarget
switch self.target {
case let .peer(peerId):
target = .peer(id: peerId, message: self.messageId, startParam: self.startParam)
case let .invite(invite):
target = .join(title: invite.title, joinHash: invite.joinHash)
}
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, target: target))
if !self.textEntities.isEmpty {
let attribute = TextEntitiesMessageAttribute(entities: self.textEntities)
attributes.append(attribute)
@ -153,6 +180,23 @@ private class AdMessagesHistoryContextImpl {
} else {
return nil
}
case let .invite(invite):
author = TelegramChannel(
id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(1)),
accessHash: nil,
title: invite.title,
username: nil,
photo: [],
creationDate: 0,
version: 0,
participationStatus: .left,
info: .broadcast(TelegramChannelBroadcastInfo(flags: [])),
flags: [],
restrictionInfo: nil,
adminRights: nil,
bannedRights: nil,
defaultBannedRights: nil
)
}
messagePeers[author.id] = author
@ -368,6 +412,36 @@ private class AdMessagesHistoryContextImpl {
var target: CachedMessage.Target?
if let fromId = fromId {
target = .peer(fromId.peerId)
} else if let chatInvite = chatInvite, let chatInviteHash = chatInviteHash {
switch chatInvite {
case let .chatInvite(flags, title, _, photo, participantsCount, participants):
let photo = telegramMediaImageFromApiPhoto(photo).flatMap({ smallestImageRepresentation($0.representations) })
let flags: ExternalJoiningChatState.Invite.Flags = .init(isChannel: (flags & (1 << 0)) != 0, isBroadcast: (flags & (1 << 1)) != 0, isPublic: (flags & (1 << 2)) != 0, isMegagroup: (flags & (1 << 3)) != 0, requestNeeded: (flags & (1 << 6)) != 0)
let _ = photo
let _ = flags
let _ = participantsCount
let _ = participants
target = .invite(CachedMessage.Target.Invite(
title: title,
joinHash: chatInviteHash
))
case let .chatInvitePeek(chat, _):
if let peer = parseTelegramGroupOrChannel(chat: chat) {
target = .invite(CachedMessage.Target.Invite(
title: peer.debugDisplayTitle,
joinHash: chatInviteHash
))
}
case let .chatInviteAlready(chat):
if let peer = parseTelegramGroupOrChannel(chat: chat) {
target = .invite(CachedMessage.Target.Invite(
title: peer.debugDisplayTitle,
joinHash: chatInviteHash
))
}
}
}
var messageId: MessageId?

View File

@ -29,21 +29,30 @@ func apiUpdatesGroups(_ updates: Api.Updates) -> [Api.Chat] {
}
public enum ExternalJoiningChatState {
public struct InviteFlags : Equatable {
public let isChannel: Bool
public let isBroadcast: Bool
public let isPublic: Bool
public let isMegagroup: Bool
public let requestNeeded: Bool
public struct Invite: Equatable {
public struct Flags: Equatable, Codable {
public let isChannel: Bool
public let isBroadcast: Bool
public let isPublic: Bool
public let isMegagroup: Bool
public let requestNeeded: Bool
}
public let flags: Flags
public let title: String
public let about: String?
public let photoRepresentation: TelegramMediaImageRepresentation?
public let participantsCount: Int32
public let participants: [EnginePeer]?
}
case invite(flags: InviteFlags, title: String, about: String?, photoRepresentation: TelegramMediaImageRepresentation?, participantsCount: Int32, participants: [Peer]?)
case invite(Invite)
case alreadyJoined(PeerId)
case invalidHash
case peek(PeerId, Int32)
}
func _internal_joinChatInteractively(with hash: String, account: Account) -> Signal <PeerId?, JoinLinkError> {
func _internal_joinChatInteractively(with hash: String, account: Account) -> Signal<PeerId?, JoinLinkError> {
return account.network.request(Api.functions.messages.importChatInvite(hash: hash), automaticFloodWait: false)
|> mapError { error -> JoinLinkError in
switch error.errorDescription {
@ -94,8 +103,8 @@ func _internal_joinLinkInformation(_ hash: String, account: Account) -> Signal<E
switch result {
case let .chatInvite(flags, title, about, invitePhoto, participantsCount, participants):
let photo = telegramMediaImageFromApiPhoto(invitePhoto).flatMap({ smallestImageRepresentation($0.representations) })
let flags:ExternalJoiningChatState.InviteFlags = .init(isChannel: (flags & (1 << 0)) != 0, isBroadcast: (flags & (1 << 1)) != 0, isPublic: (flags & (1 << 2)) != 0, isMegagroup: (flags & (1 << 3)) != 0, requestNeeded: (flags & (1 << 6)) != 0)
return .single(.invite(flags: flags, title: title, about: about, photoRepresentation: photo, participantsCount: participantsCount, participants: participants?.map({TelegramUser(user: $0)})))
let flags: ExternalJoiningChatState.Invite.Flags = .init(isChannel: (flags & (1 << 0)) != 0, isBroadcast: (flags & (1 << 1)) != 0, isPublic: (flags & (1 << 2)) != 0, isMegagroup: (flags & (1 << 3)) != 0, requestNeeded: (flags & (1 << 6)) != 0)
return .single(.invite(ExternalJoiningChatState.Invite(flags: flags, title: title, about: about, photoRepresentation: photo, participantsCount: participantsCount, participants: participants?.map({ EnginePeer(TelegramUser(user: $0)) }))))
case let .chatInviteAlready(chat):
if let peer = parseTelegramGroupOrChannel(chat: chat) {
return account.postbox.transaction({ (transaction) -> ExternalJoiningChatState in

View File

@ -1004,7 +1004,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
actions.context = strongSelf.context
if canAddMessageReactions(message: topMessage), let availableReactions = availableReactions, let allowedReactions = allowedReactions {
filterReactions: for reaction in availableReactions.reactions {
filterReactions: for reaction in availableReactions.reactions {
switch allowedReactions {
case let .set(set):
if !set.contains(reaction.value) {
@ -1015,6 +1015,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
actions.reactionItems.append(ReactionContextItem(
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
appearAnimation: reaction.appearAnimation,
stillAnimation: reaction.selectAnimation,
listAnimation: reaction.activateAnimation,
applicationAnimation: reaction.effectAnimation
@ -1249,6 +1250,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
theme: strongSelf.presentationData.theme,
reaction: ReactionContextItem(
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
appearAnimation: reaction.appearAnimation,
stillAnimation: reaction.selectAnimation,
listAnimation: reaction.activateAnimation,
applicationAnimation: reaction.effectAnimation
@ -3193,6 +3195,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
])])
strongSelf.chatDisplayNode.dismissInput()
strongSelf.present(actionSheet, in: .window(.root))
}, openJoinLink: { [weak self] joinHash in
guard let strongSelf = self else {
return
}
strongSelf.openResolved(result: .join(joinHash), sourceMessageId: nil)
}, requestMessageUpdate: { [weak self] id in
if let strongSelf = self {
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)

View File

@ -129,6 +129,7 @@ public final class ChatControllerInteraction {
let updateChoosingSticker: (Bool) -> Void
let commitEmojiInteraction: (MessageId, String, EmojiInteraction, TelegramMediaFile) -> Void
let openLargeEmojiInfo: (String, String?, TelegramMediaFile) -> Void
let openJoinLink: (String) -> Void
let requestMessageUpdate: (MessageId) -> Void
let cancelInteractiveKeyboardGestures: () -> Void
@ -227,6 +228,7 @@ public final class ChatControllerInteraction {
updateChoosingSticker: @escaping (Bool) -> Void,
commitEmojiInteraction: @escaping (MessageId, String, EmojiInteraction, TelegramMediaFile) -> Void,
openLargeEmojiInfo: @escaping (String, String?, TelegramMediaFile) -> Void,
openJoinLink: @escaping (String) -> Void,
requestMessageUpdate: @escaping (MessageId) -> Void,
cancelInteractiveKeyboardGestures: @escaping () -> Void,
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
@ -311,6 +313,7 @@ public final class ChatControllerInteraction {
self.updateChoosingSticker = updateChoosingSticker
self.commitEmojiInteraction = commitEmojiInteraction
self.openLargeEmojiInfo = openLargeEmojiInfo
self.openJoinLink = openJoinLink
self.requestMessageUpdate = requestMessageUpdate
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
@ -369,6 +372,7 @@ public final class ChatControllerInteraction {
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, openJoinLink: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -245,7 +245,9 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
} else {
if result.last?.1 == ChatMessageWebpageBubbleContentNode.self ||
result.last?.1 == ChatMessagePollBubbleContentNode.self ||
result.last?.1 == ChatMessageContactBubbleContentNode.self {
result.last?.1 == ChatMessageContactBubbleContentNode.self ||
result.last?.1 == ChatMessageGameBubbleContentNode.self ||
result.last?.1 == ChatMessageInvoiceBubbleContentNode.self {
result.append((firstMessage, ChatMessageReactionsFooterContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: true, neighborType: .freeform, neighborSpacing: .default)))
needReactions = false
} else if result.last?.1 == ChatMessageCommentFooterContentNode.self {
@ -254,11 +256,6 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
result[result.count - 2].1 == ChatMessageContactBubbleContentNode.self {
result.insert((firstMessage, ChatMessageReactionsFooterContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: true, neighborType: .freeform, neighborSpacing: .default)), at: result.count - 1)
}
/*if result[result.count - 2].1 == ChatMessageTextBubbleContentNode.self {
} else {
result.insert((firstMessage, ChatMessageReactionsFooterContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: true, neighborType: .freeform, neighborSpacing: .default)), at: result.count - 1)
needReactions = false
}*/
}
}
}

View File

@ -301,8 +301,15 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
isReplyThread = true
}
let trailingWidthToMeasure: CGFloat
if textLayout.hasRTL {
trailingWidthToMeasure = 10000.0
} else {
trailingWidthToMeasure = textLayout.trailingLineWidth
}
let dateLayoutInput: ChatMessageDateAndStatusNode.LayoutInput
dateLayoutInput = .trailingContent(contentWidth: textLayout.trailingLineWidth, reactionSettings: ChatMessageDateAndStatusNode.TrailingReactionSettings(displayInline: shouldDisplayInlineDateReactions(message: item.message), preferAdditionalInset: false))
dateLayoutInput = .trailingContent(contentWidth: trailingWidthToMeasure, reactionSettings: ChatMessageDateAndStatusNode.TrailingReactionSettings(displayInline: shouldDisplayInlineDateReactions(message: item.message), preferAdditionalInset: false))
statusSuggestedWidthAndContinue = statusLayout(ChatMessageDateAndStatusNode.Arguments(
context: item.context,

View File

@ -63,18 +63,23 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
}
self.contentNode.activateAction = { [weak self] in
if let strongSelf = self, let item = strongSelf.item {
if let adAttribute = item.message.adAttribute, let author = item.message.author {
let navigationData: ChatControllerInteractionNavigateToPeer
if let bot = author as? TelegramUser, bot.botInfo != nil, let startParam = adAttribute.startParam {
navigationData = .withBotStartPayload(ChatControllerInitialBotStart(payload: startParam, behavior: .interactive))
} else {
var subject: ChatControllerSubject?
if let messageId = adAttribute.messageId {
subject = .message(id: .id(messageId), highlight: true, timecode: nil)
if let adAttribute = item.message.adAttribute {
switch adAttribute.target {
case let .peer(id, messageId, startParam):
let navigationData: ChatControllerInteractionNavigateToPeer
if let bot = item.message.author as? TelegramUser, bot.botInfo != nil, let startParam = startParam {
navigationData = .withBotStartPayload(ChatControllerInitialBotStart(payload: startParam, behavior: .interactive))
} else {
var subject: ChatControllerSubject?
if let messageId = messageId {
subject = .message(id: .id(messageId), highlight: true, timecode: nil)
}
navigationData = .chat(textInputState: nil, subject: subject, peekData: nil)
}
navigationData = .chat(textInputState: nil, subject: subject, peekData: nil)
item.controllerInteraction.openPeer(id, navigationData, nil)
case let .join(_, joinHash):
item.controllerInteraction.openJoinLink(joinHash)
}
item.controllerInteraction.openPeer(author.id, navigationData, nil)
} else {
var webPageContent: TelegramMediaWebpageLoadedContent?
for media in item.message.media {
@ -342,13 +347,13 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
if let author = item.message.author as? TelegramUser, author.botInfo != nil {
actionTitle = item.presentationData.strings.Conversation_ViewBot
} else if let author = item.message.author as? TelegramChannel, case .group = author.info {
if adAttribute.messageId != nil {
if case let .peer(_, messageId, _) = adAttribute.target, messageId != nil {
actionTitle = item.presentationData.strings.Conversation_ViewPost
} else {
actionTitle = item.presentationData.strings.Conversation_ViewGroup
}
} else {
if adAttribute.messageId != nil {
if case let .peer(_, messageId, _) = adAttribute.target, messageId != nil {
actionTitle = item.presentationData.strings.Conversation_ViewMessage
} else {
actionTitle = item.presentationData.strings.Conversation_ViewChannel

View File

@ -531,6 +531,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, openJoinLink: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,

View File

@ -157,6 +157,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, openJoinLink: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -149,6 +149,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, openJoinLink: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: nil))

View File

@ -2241,6 +2241,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, openJoinLink: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -1294,6 +1294,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, openJoinLink: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,