Link preview update

This commit is contained in:
Ali 2020-06-05 21:50:50 +04:00
parent db5ba5b97c
commit f529ec0793
37 changed files with 2500 additions and 2372 deletions

View File

@ -3,7 +3,7 @@
@implementation Serialization @implementation Serialization
- (NSUInteger)currentLayer { - (NSUInteger)currentLayer {
return 114; return 115;
} }
- (id _Nullable)parseMessage:(NSData * _Nullable)data { - (id _Nullable)parseMessage:(NSData * _Nullable)data {

View File

@ -5534,3 +5534,7 @@ Any member of this group will be able to see messages in the channel.";
"ChatList.MessagePhotos_any" = "%@ Photos"; "ChatList.MessagePhotos_any" = "%@ Photos";
"ChatList.MessageVideos_1" = "1 Videos"; "ChatList.MessageVideos_1" = "1 Videos";
"ChatList.MessageVideos_any" = "%@ Videos"; "ChatList.MessageVideos_any" = "%@ Videos";
"Conversation.PrivateChannelTimeLimitedAlertTitle" = "Join Channel";
"Conversation.PrivateChannelTimeLimitedAlertText" = "This channel is private. Please join it to continue viewing its content.";
"Conversation.PrivateChannelTimeLimitedAlertJoin" = "Join";

View File

@ -192,6 +192,16 @@ public enum NavigateToChatKeepStack {
case never case never
} }
public final class ChatPeekTimeout {
public let deadline: Int32
public let linkData: String
public init(deadline: Int32, linkData: String) {
self.deadline = deadline
self.linkData = linkData
}
}
public final class NavigateToChatControllerParams { public final class NavigateToChatControllerParams {
public let navigationController: NavigationController public let navigationController: NavigationController
public let chatController: ChatController? public let chatController: ChatController?
@ -206,12 +216,13 @@ public final class NavigateToChatControllerParams {
public let purposefulAction: (() -> Void)? public let purposefulAction: (() -> Void)?
public let scrollToEndIfExists: Bool public let scrollToEndIfExists: Bool
public let activateMessageSearch: Bool public let activateMessageSearch: Bool
public let peekData: ChatPeekTimeout?
public let animated: Bool public let animated: Bool
public let options: NavigationAnimationOptions public let options: NavigationAnimationOptions
public let parentGroupId: PeerGroupId? public let parentGroupId: PeerGroupId?
public let completion: (ChatController) -> Void public let completion: (ChatController) -> Void
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: Bool = false, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, completion: @escaping (ChatController) -> Void = { _ in }) { public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: Bool = false, peekData: ChatPeekTimeout? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, completion: @escaping (ChatController) -> Void = { _ in }) {
self.navigationController = navigationController self.navigationController = navigationController
self.chatController = chatController self.chatController = chatController
self.context = context self.context = context
@ -225,6 +236,7 @@ public final class NavigateToChatControllerParams {
self.purposefulAction = purposefulAction self.purposefulAction = purposefulAction
self.scrollToEndIfExists = scrollToEndIfExists self.scrollToEndIfExists = scrollToEndIfExists
self.activateMessageSearch = activateMessageSearch self.activateMessageSearch = activateMessageSearch
self.peekData = peekData
self.animated = animated self.animated = animated
self.options = options self.options = options
self.parentGroupId = parentGroupId self.parentGroupId = parentGroupId

View File

@ -27,7 +27,7 @@ public struct ChatControllerInitialBotStart {
public enum ChatControllerInteractionNavigateToPeer { public enum ChatControllerInteractionNavigateToPeer {
case `default` case `default`
case chat(textInputState: ChatTextInputState?, subject: ChatControllerSubject?) case chat(textInputState: ChatTextInputState?, subject: ChatControllerSubject?, peekData: ChatPeekTimeout?)
case info case info
case withBotStartPayload(ChatControllerInitialBotStart) case withBotStartPayload(ChatControllerInitialBotStart)
} }

View File

@ -13,8 +13,8 @@ public final class AlertControllerContext {
} }
} }
public func textAlertController(alertContext: AlertControllerContext, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true) -> AlertController { public func textAlertController(alertContext: AlertControllerContext, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissOnOutsideTap: Bool = true) -> AlertController {
let controller = standardTextAlertController(theme: alertContext.theme, title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset) let controller = standardTextAlertController(theme: alertContext.theme, title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, dismissOnOutsideTap: dismissOnOutsideTap)
let presentationDataDisposable = alertContext.themeSignal.start(next: { [weak controller] theme in let presentationDataDisposable = alertContext.themeSignal.start(next: { [weak controller] theme in
controller?.theme = theme controller?.theme = theme
}) })
@ -36,7 +36,7 @@ public func richTextAlertController(alertContext: AlertControllerContext, title:
} }
action.action() action.action()
}) })
}, actionLayout: actionLayout), allowInputInset: allowInputInset) }, actionLayout: actionLayout, dismissOnOutsideTap: true), allowInputInset: allowInputInset)
dismissImpl = { [weak controller] in dismissImpl = { [weak controller] in
controller?.dismissAnimated() controller?.dismissAnimated()
} }

View File

@ -21,7 +21,7 @@ func contactContextMenuItems(context: AccountContext, peerId: PeerId, contactsCo
items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_SendMessage, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.contextMenu.primaryColor) }, action: { _, f in items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_SendMessage, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.contextMenu.primaryColor) }, action: { _, f in
if let contactsController = contactsController, let navigationController = contactsController.navigationController as? NavigationController { if let contactsController = contactsController, let navigationController = contactsController.navigationController as? NavigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId))) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), peekData: nil))
} }
f(.default) f(.default)
}))) })))
@ -58,7 +58,7 @@ func contactContextMenuItems(context: AccountContext, peerId: PeerId, contactsCo
|> deliverOnMainQueue).start(next: { currentPeerId in |> deliverOnMainQueue).start(next: { currentPeerId in
if let currentPeerId = currentPeerId { if let currentPeerId = currentPeerId {
if let contactsController = contactsController, let navigationController = (contactsController.navigationController as? NavigationController) { if let contactsController = contactsController, let navigationController = (contactsController.navigationController as? NavigationController) {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(currentPeerId))) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(currentPeerId), peekData: nil))
} }
} else { } else {
var createSignal = createSecretChat(account: context.account, peerId: peerId) var createSignal = createSecretChat(account: context.account, peerId: peerId)
@ -93,7 +93,7 @@ func contactContextMenuItems(context: AccountContext, peerId: PeerId, contactsCo
createSecretChatDisposable.set((createSignal createSecretChatDisposable.set((createSignal
|> deliverOnMainQueue).start(next: { peerId in |> deliverOnMainQueue).start(next: { peerId in
if let navigationController = (contactsController?.navigationController as? NavigationController) { if let navigationController = (contactsController?.navigationController as? NavigationController) {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId))) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), peekData: nil))
} }
}, error: { _ in }, error: { _ in
if let contactsController = contactsController { if let contactsController = contactsController {

View File

@ -137,6 +137,11 @@ public final class TextAlertContentNode: AlertContentNode {
private var validLayout: CGSize? private var validLayout: CGSize?
private let _dismissOnOutsideTap: Bool
override public var dismissOnOutsideTap: Bool {
return self._dismissOnOutsideTap
}
public var textAttributeAction: (NSAttributedString.Key, (Any) -> Void)? { public var textAttributeAction: (NSAttributedString.Key, (Any) -> Void)? {
didSet { didSet {
if let (attribute, textAttributeAction) = self.textAttributeAction { if let (attribute, textAttributeAction) = self.textAttributeAction {
@ -160,9 +165,10 @@ public final class TextAlertContentNode: AlertContentNode {
} }
} }
public init(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout) { public init(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout, dismissOnOutsideTap: Bool) {
self.theme = theme self.theme = theme
self.actionLayout = actionLayout self.actionLayout = actionLayout
self._dismissOnOutsideTap = dismissOnOutsideTap
if let title = title { if let title = title {
let titleNode = ImmediateTextNode() let titleNode = ImmediateTextNode()
titleNode.attributedText = title titleNode.attributedText = title
@ -364,11 +370,11 @@ public final class TextAlertContentNode: AlertContentNode {
} }
} }
public func textAlertController(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal) -> AlertController { public func textAlertController(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, dismissOnOutsideTap: Bool = true) -> AlertController {
return AlertController(theme: theme, contentNode: TextAlertContentNode(theme: theme, title: title, text: text, actions: actions, actionLayout: actionLayout)) return AlertController(theme: theme, contentNode: TextAlertContentNode(theme: theme, title: title, text: text, actions: actions, actionLayout: actionLayout, dismissOnOutsideTap: dismissOnOutsideTap))
} }
public func standardTextAlertController(theme: AlertControllerTheme, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, parseMarkdown: Bool = false) -> AlertController { public func standardTextAlertController(theme: AlertControllerTheme, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, parseMarkdown: Bool = false, dismissOnOutsideTap: Bool = true) -> AlertController {
var dismissImpl: (() -> Void)? var dismissImpl: (() -> Void)?
let attributedText: NSAttributedString let attributedText: NSAttributedString
if parseMarkdown { if parseMarkdown {
@ -385,7 +391,7 @@ public func standardTextAlertController(theme: AlertControllerTheme, title: Stri
dismissImpl?() dismissImpl?()
action.action() action.action()
}) })
}, actionLayout: actionLayout), allowInputInset: allowInputInset) }, actionLayout: actionLayout, dismissOnOutsideTap: dismissOnOutsideTap), allowInputInset: allowInputInset)
dismissImpl = { [weak controller] in dismissImpl = { [weak controller] in
controller?.dismissAnimated() controller?.dismissAnimated()
} }

View File

@ -1168,9 +1168,9 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
strongSelf.loadProgress.set(1.0) strongSelf.loadProgress.set(1.0)
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), openPeer: { peerId, navigation in strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), openPeer: { peerId, navigation in
switch navigation { switch navigation {
case let .chat(_, subject): case let .chat(_, subject, peekData):
if let navigationController = strongSelf.getNavigationController() { if let navigationController = strongSelf.getNavigationController() {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, peekData: peekData))
} }
case let .withBotStartPayload(botStart): case let .withBotStartPayload(botStart):
if let navigationController = strongSelf.getNavigationController() { if let navigationController = strongSelf.getNavigationController() {

View File

@ -21,14 +21,14 @@ public final class JoinLinkPreviewController: ViewController {
private let context: AccountContext private let context: AccountContext
private let link: String private let link: String
private let navigateToPeer: (PeerId) -> Void private let navigateToPeer: (PeerId, ChatPeekTimeout?) -> Void
private let parentNavigationController: NavigationController? private let parentNavigationController: NavigationController?
private var resolvedState: ExternalJoiningChatState? private var resolvedState: ExternalJoiningChatState?
private var presentationData: PresentationData private var presentationData: PresentationData
private let disposable = MetaDisposable() private let disposable = MetaDisposable()
public init(context: AccountContext, link: String, navigateToPeer: @escaping (PeerId) -> Void, parentNavigationController: NavigationController?, resolvedState: ExternalJoiningChatState? = nil) { public init(context: AccountContext, link: String, navigateToPeer: @escaping (PeerId, ChatPeekTimeout?) -> Void, parentNavigationController: NavigationController?, resolvedState: ExternalJoiningChatState? = nil) {
self.context = context self.context = context
self.link = link self.link = link
self.navigateToPeer = navigateToPeer self.navigateToPeer = navigateToPeer
@ -81,7 +81,10 @@ public final class JoinLinkPreviewController: ViewController {
let data = JoinLinkPreviewData(isGroup: participants != nil, isJoined: false) let data = JoinLinkPreviewData(isGroup: participants != nil, isJoined: false)
strongSelf.controllerNode.setPeer(image: photoRepresentation, title: title, memberCount: participantsCount, members: participants ?? [], data: data) strongSelf.controllerNode.setPeer(image: photoRepresentation, title: title, memberCount: participantsCount, members: participants ?? [], data: data)
case let .alreadyJoined(peerId): case let .alreadyJoined(peerId):
strongSelf.navigateToPeer(peerId) strongSelf.navigateToPeer(peerId, nil)
strongSelf.dismiss()
case let .peek(peerId, deadline):
strongSelf.navigateToPeer(peerId, ChatPeekTimeout(deadline: deadline, linkData: strongSelf.link))
strongSelf.dismiss() strongSelf.dismiss()
case .invalidHash: case .invalidHash:
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.GroupInfo_InvitationLinkDoesNotExist, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.GroupInfo_InvitationLinkDoesNotExist, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
@ -119,7 +122,7 @@ public final class JoinLinkPreviewController: ViewController {
self.disposable.set((joinChatInteractively(with: self.link, account: self.context.account) |> deliverOnMainQueue).start(next: { [weak self] peerId in self.disposable.set((joinChatInteractively(with: self.link, account: self.context.account) |> deliverOnMainQueue).start(next: { [weak self] peerId in
if let strongSelf = self { if let strongSelf = self {
if let peerId = peerId { if let peerId = peerId {
strongSelf.navigateToPeer(peerId) strongSelf.navigateToPeer(peerId, nil)
strongSelf.dismiss() strongSelf.dismiss()
} }
} }

View File

@ -661,7 +661,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController {
} }
navigateToChatImpl = { [weak controller] peer in navigateToChatImpl = { [weak controller] peer in
if let navigationController = controller?.navigationController as? NavigationController { if let navigationController = controller?.navigationController as? NavigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer.id), keepStack: .always, purposefulAction: {})) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer.id), keepStack: .always, purposefulAction: {}, peekData: nil))
} }
} }
pushControllerImpl = { [weak controller] c in pushControllerImpl = { [weak controller] c in

View File

@ -4,8 +4,8 @@ import AlertUI
import AccountContext import AccountContext
import SwiftSignalKit import SwiftSignalKit
public func textAlertController(context: AccountContext, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true) -> AlertController { public func textAlertController(context: AccountContext, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissOnOutsideTap: Bool = true) -> AlertController {
return textAlertController(alertContext: AlertControllerContext(theme: AlertControllerTheme(presentationData: context.sharedContext.currentPresentationData.with { $0 }), themeSignal: context.sharedContext.presentationData |> map { presentationData in AlertControllerTheme(presentationData: presentationData) }), title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset) return textAlertController(alertContext: AlertControllerContext(theme: AlertControllerTheme(presentationData: context.sharedContext.currentPresentationData.with { $0 }), themeSignal: context.sharedContext.presentationData |> map { presentationData in AlertControllerTheme(presentationData: presentationData) }), title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, dismissOnOutsideTap: dismissOnOutsideTap)
} }
public func richTextAlertController(context: AccountContext, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController { public func richTextAlertController(context: AccountContext, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController {

View File

@ -512,7 +512,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
}) })
}) })
case let .photoPreview(theme, value): case let .photoPreview(theme, value):
return ItemListSwitchItem(presentationData: presentationData, title: "Photo Preview", value: value, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: "Media Preview (Updated)", value: value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings

View File

@ -514,7 +514,7 @@ public func channelStatsController(context: AccountContext, peerId: PeerId, cach
} }
navigateToMessageImpl = { [weak controller] messageId in navigateToMessageImpl = { [weak controller] messageId in
if let navigationController = controller?.navigationController as? NavigationController { if let navigationController = controller?.navigationController as? NavigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(messageId), keepStack: .always, useExisting: false, purposefulAction: {})) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(messageId), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil))
} }
} }
return controller return controller

View File

@ -71,6 +71,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1202287072] = { return Api.StatsURL.parse_statsURL($0) } dict[1202287072] = { return Api.StatsURL.parse_statsURL($0) }
dict[1516793212] = { return Api.ChatInvite.parse_chatInviteAlready($0) } dict[1516793212] = { return Api.ChatInvite.parse_chatInviteAlready($0) }
dict[-540871282] = { return Api.ChatInvite.parse_chatInvite($0) } dict[-540871282] = { return Api.ChatInvite.parse_chatInvite($0) }
dict[1634294960] = { return Api.ChatInvite.parse_chatInvitePeek($0) }
dict[-532532493] = { return Api.AutoDownloadSettings.parse_autoDownloadSettings($0) } dict[-532532493] = { return Api.AutoDownloadSettings.parse_autoDownloadSettings($0) }
dict[1678812626] = { return Api.StickerSetCovered.parse_stickerSetCovered($0) } dict[1678812626] = { return Api.StickerSetCovered.parse_stickerSetCovered($0) }
dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) } dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) }

View File

@ -3624,6 +3624,7 @@ public extension Api {
public enum ChatInvite: TypeConstructorDescription { public enum ChatInvite: TypeConstructorDescription {
case chatInviteAlready(chat: Api.Chat) case chatInviteAlready(chat: Api.Chat)
case chatInvite(flags: Int32, title: String, photo: Api.Photo, participantsCount: Int32, participants: [Api.User]?) case chatInvite(flags: Int32, title: String, photo: Api.Photo, participantsCount: Int32, participants: [Api.User]?)
case chatInvitePeek(chat: Api.Chat, expires: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -3647,6 +3648,13 @@ public extension Api {
item.serialize(buffer, true) item.serialize(buffer, true)
}} }}
break break
case .chatInvitePeek(let chat, let expires):
if boxed {
buffer.appendInt32(1634294960)
}
chat.serialize(buffer, true)
serializeInt32(expires, buffer: buffer, boxed: false)
break
} }
} }
@ -3656,6 +3664,8 @@ public extension Api {
return ("chatInviteAlready", [("chat", chat)]) return ("chatInviteAlready", [("chat", chat)])
case .chatInvite(let flags, let title, let photo, let participantsCount, let participants): case .chatInvite(let flags, let title, let photo, let participantsCount, let participants):
return ("chatInvite", [("flags", flags), ("title", title), ("photo", photo), ("participantsCount", participantsCount), ("participants", participants)]) return ("chatInvite", [("flags", flags), ("title", title), ("photo", photo), ("participantsCount", participantsCount), ("participants", participants)])
case .chatInvitePeek(let chat, let expires):
return ("chatInvitePeek", [("chat", chat), ("expires", expires)])
} }
} }
@ -3699,6 +3709,22 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_chatInvitePeek(_ reader: BufferReader) -> ChatInvite? {
var _1: Api.Chat?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Chat
}
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.ChatInvite.chatInvitePeek(chat: _1!, expires: _2!)
}
else {
return nil
}
}
} }
public enum AutoDownloadSettings: TypeConstructorDescription { public enum AutoDownloadSettings: TypeConstructorDescription {

View File

@ -25,6 +25,7 @@ public enum ExternalJoiningChatState {
case invite(title: String, photoRepresentation: TelegramMediaImageRepresentation?, participantsCount: Int32, participants: [Peer]?) case invite(title: String, photoRepresentation: TelegramMediaImageRepresentation?, participantsCount: Int32, participants: [Peer]?)
case alreadyJoined(PeerId) case alreadyJoined(PeerId)
case invalidHash case invalidHash
case peek(PeerId, Int32)
} }
public func joinChatInteractively(with hash: String, account: Account) -> Signal <PeerId?, JoinLinkError> { public func joinChatInteractively(with hash: String, account: Account) -> Signal <PeerId?, JoinLinkError> {
@ -66,7 +67,7 @@ public func joinLinkInformation(_ hash: String, account: Account) -> Signal<Exte
case let .chatInvite(invite): case let .chatInvite(invite):
let photo = telegramMediaImageFromApiPhoto(invite.photo).flatMap({ smallestImageRepresentation($0.representations) }) let photo = telegramMediaImageFromApiPhoto(invite.photo).flatMap({ smallestImageRepresentation($0.representations) })
return .single(.invite(title: invite.title, photoRepresentation: photo, participantsCount: invite.participantsCount, participants: invite.participants?.map({TelegramUser(user: $0)}))) return .single(.invite(title: invite.title, photoRepresentation: photo, participantsCount: invite.participantsCount, participants: invite.participants?.map({TelegramUser(user: $0)})))
case let .chatInviteAlready(chat: chat): case let .chatInviteAlready(chat):
if let peer = parseTelegramGroupOrChannel(chat: chat) { if let peer = parseTelegramGroupOrChannel(chat: chat) {
return account.postbox.transaction({ (transaction) -> ExternalJoiningChatState in return account.postbox.transaction({ (transaction) -> ExternalJoiningChatState in
updatePeers(transaction: transaction, peers: [peer], update: { (previous, updated) -> Peer? in updatePeers(transaction: transaction, peers: [peer], update: { (previous, updated) -> Peer? in
@ -77,6 +78,17 @@ public func joinLinkInformation(_ hash: String, account: Account) -> Signal<Exte
}) })
} }
return .single(.invalidHash) return .single(.invalidHash)
case let .chatInvitePeek(chat, expires):
if let peer = parseTelegramGroupOrChannel(chat: chat) {
return account.postbox.transaction({ (transaction) -> ExternalJoiningChatState in
updatePeers(transaction: transaction, peers: [peer], update: { (previous, updated) -> Peer? in
return updated
})
return .peek(peer.id, expires)
})
}
return .single(.invalidHash)
} }
} else { } else {
return .single(.invalidHash) return .single(.invalidHash)

View File

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization { public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt { public func currentLayer() -> UInt {
return 114 return 115
} }
public func parseMessage(_ data: Data!) -> Any! { public func parseMessage(_ data: Data!) -> Any! {

View File

@ -324,7 +324,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
}).start() }).start()
})]), on: .root, blockInteraction: false, completion: {}) })]), on: .root, blockInteraction: false, completion: {})
}) })
], actionLayout: .vertical) ], actionLayout: .vertical, dismissOnOutsideTap: true)
contentNode.textAttributeAction = (NSAttributedString.Key(rawValue: TelegramTextAttributes.URL), { value in contentNode.textAttributeAction = (NSAttributedString.Key(rawValue: TelegramTextAttributes.URL), { value in
if let value = value as? String { if let value = value as? String {
strongSelf.openUrl(value) strongSelf.openUrl(value)

View File

@ -302,7 +302,7 @@ final class ChatBotInfoItemNode: ListViewItemNode {
case let .url(url, concealed): case let .url(url, concealed):
self.item?.controllerInteraction.openUrl(url, concealed, nil, nil) self.item?.controllerInteraction.openUrl(url, concealed, nil, nil)
case let .peerMention(peerId, _): case let .peerMention(peerId, _):
self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil), nil) self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil, peekData: nil), nil)
case let .textMention(name): case let .textMention(name):
self.item?.controllerInteraction.openPeerMention(name) self.item?.controllerInteraction.openPeerMention(name)
case let .botCommand(command): case let .botCommand(command):

View File

@ -202,7 +202,7 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
peerId = message.id.peerId peerId = message.id.peerId
} }
if let botPeer = botPeer, let addressName = botPeer.addressName { if let botPeer = botPeer, let addressName = botPeer.addressName {
self.controllerInteraction.openPeer(peerId, .chat(textInputState: ChatTextInputState(inputText: NSAttributedString(string: "@\(addressName) \(query)")), subject: nil), nil) self.controllerInteraction.openPeer(peerId, .chat(textInputState: ChatTextInputState(inputText: NSAttributedString(string: "@\(addressName) \(query)")), subject: nil, peekData: nil), nil)
} }
} }
case .payment: case .payment:

View File

@ -317,6 +317,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
private var focusOnSearchAfterAppearance: Bool = false private var focusOnSearchAfterAppearance: Bool = false
private let keepPeerInfoScreenDataHotDisposable = MetaDisposable() private let keepPeerInfoScreenDataHotDisposable = MetaDisposable()
private let peekData: ChatPeekTimeout?
private let peekTimerDisposable = MetaDisposable()
public override var customData: Any? { public override var customData: Any? {
return self.chatLocation return self.chatLocation
@ -324,7 +327,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var purposefulAction: (() -> Void)? var purposefulAction: (() -> Void)?
public init(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false)) { public init(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil) {
let _ = ChatControllerCount.modify { value in let _ = ChatControllerCount.modify { value in
return value + 1 return value + 1
} }
@ -333,6 +336,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.chatLocation = chatLocation self.chatLocation = chatLocation
self.subject = subject self.subject = subject
self.botStart = botStart self.botStart = botStart
self.peekData = peekData
var locationBroadcastPanelSource: LocationBroadcastPanelSource var locationBroadcastPanelSource: LocationBroadcastPanelSource
@ -982,9 +986,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return return
} }
if let botStart = strongSelf.botStart, case let .automatic(returnToPeerId, scheduled) = botStart.behavior { if let botStart = strongSelf.botStart, case let .automatic(returnToPeerId, scheduled) = botStart.behavior {
strongSelf.openPeer(peerId: returnToPeerId, navigation: .chat(textInputState: ChatTextInputState(inputText: NSAttributedString(string: inputString)), subject: scheduled ? .scheduledMessages : nil), fromMessage: nil) strongSelf.openPeer(peerId: returnToPeerId, navigation: .chat(textInputState: ChatTextInputState(inputText: NSAttributedString(string: inputString)), subject: scheduled ? .scheduledMessages : nil, peekData: nil), fromMessage: nil)
} else { } else {
strongSelf.openPeer(peerId: peerId, navigation: .chat(textInputState: ChatTextInputState(inputText: NSAttributedString(string: inputString)), subject: nil), fromMessage: nil) strongSelf.openPeer(peerId: peerId, navigation: .chat(textInputState: ChatTextInputState(inputText: NSAttributedString(string: inputString)), subject: nil, peekData: nil), fromMessage: nil)
} }
}, openUrl: { [weak self] url, concealed, _, message in }, openUrl: { [weak self] url, concealed, _, message in
if let strongSelf = self { if let strongSelf = self {
@ -1288,7 +1292,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
if let strongSelf = self { if let strongSelf = self {
strongSelf.openPeer(peerId: peerId, navigation: .chat(textInputState: nil, subject: nil), fromMessage: nil) strongSelf.openPeer(peerId: peerId, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil)
} }
})) }))
if !mention.isEmpty { if !mention.isEmpty {
@ -2741,6 +2745,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.reminderActivity?.invalidate() self.reminderActivity?.invalidate()
self.updateSlowmodeStatusDisposable.dispose() self.updateSlowmodeStatusDisposable.dispose()
self.keepPeerInfoScreenDataHotDisposable.dispose() self.keepPeerInfoScreenDataHotDisposable.dispose()
self.peekTimerDisposable.dispose()
} }
public func updatePresentationMode(_ mode: ChatControllerPresentationMode) { public func updatePresentationMode(_ mode: ChatControllerPresentationMode) {
@ -4711,7 +4716,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let actions: [TextAlertAction] let actions: [TextAlertAction]
if moreInfo { if moreInfo {
actions = [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Generic_ErrorMoreInfo, action: { actions = [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Generic_ErrorMoreInfo, action: {
self?.openPeerMention("spambot", navigation: .chat(textInputState: nil, subject: nil)) self?.openPeerMention("spambot", navigation: .chat(textInputState: nil, subject: nil, peekData: nil))
}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {})] }), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]
} else { } else {
actions = [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})] actions = [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]
@ -4998,6 +5003,58 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
searchNode.activate() searchNode.activate()
} }
} }
if let peekData = self.peekData {
let timestamp = Int32(Date().timeIntervalSince1970)
let remainingTime = max(1, peekData.deadline - timestamp)
self.peekTimerDisposable.set((
(
Signal<Bool, NoError>.single(true)
|> suspendAwareDelay(Double(remainingTime), granularity: 2.0, queue: .mainQueue())
)
|> deliverOnMainQueue
).start(next: { [weak self] _ in
guard let strongSelf = self else {
return
}
strongSelf.present(textAlertController(
context: strongSelf.context,
title: strongSelf.presentationData.strings.Conversation_PrivateChannelTimeLimitedAlertTitle,
text: strongSelf.presentationData.strings.Conversation_PrivateChannelTimeLimitedAlertText,
actions: [
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Conversation_PrivateChannelTimeLimitedAlertJoin, action: {
guard let strongSelf = self else {
return
}
strongSelf.peekTimerDisposable.set(
(joinChatInteractively(with: peekData.linkData, account: strongSelf.context.account)
|> deliverOnMainQueue).start(next: { peerId in
guard let strongSelf = self else {
return
}
if peerId == nil {
strongSelf.dismiss()
}
}, error: { _ in
guard let strongSelf = self else {
return
}
strongSelf.dismiss()
})
)
}),
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
guard let strongSelf = self else {
return
}
strongSelf.dismiss()
})
],
actionLayout: .vertical,
dismissOnOutsideTap: false
), in: .window(.root))
}))
}
} }
override public func viewWillDisappear(_ animated: Bool) { override public func viewWillDisappear(_ animated: Bool) {
@ -5021,6 +5078,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}) })
self.sendMessageActionsController?.dismiss() self.sendMessageActionsController?.dismiss()
if let _ = self.peekData {
self.peekTimerDisposable.set(nil)
}
} }
private func saveInterfaceState(includeScrollState: Bool = true) { private func saveInterfaceState(includeScrollState: Bool = true) {
@ -7799,7 +7860,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
switch navigation { switch navigation {
case .info: case .info:
self.navigationButtonAction(.openChatInfo(expandAvatar: expandAvatar)) self.navigationButtonAction(.openChatInfo(expandAvatar: expandAvatar))
case let .chat(textInputState, _): case let .chat(textInputState, _, _):
if let textInputState = textInputState { if let textInputState = textInputState {
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { self.updateChatPresentationInterfaceState(animated: true, interactive: true, {
return ($0.updatedInterfaceState { return ($0.updatedInterfaceState {
@ -7846,7 +7907,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
})) }))
case let .chat(textInputState, subject): case let .chat(textInputState, subject, peekData):
if let textInputState = textInputState { if let textInputState = textInputState {
let _ = (self.context.account.postbox.transaction({ transaction -> Void in let _ = (self.context.account.postbox.transaction({ transaction -> Void in
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
@ -7859,7 +7920,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}) })
|> deliverOnMainQueue).start(completed: { [weak self] in |> deliverOnMainQueue).start(completed: { [weak self] in
if let strongSelf = self, let navigationController = strongSelf.effectiveNavigationController { if let strongSelf = self, let navigationController = strongSelf.effectiveNavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, updateTextInputState: textInputState)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, updateTextInputState: textInputState, peekData: peekData))
} }
}) })
} else { } else {
@ -7877,7 +7938,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
switch navigation { switch navigation {
case .info: case .info:
break break
case let .chat(textInputState, _): case let .chat(textInputState, _, _):
if let textInputState = textInputState { if let textInputState = textInputState {
let controller = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context)) let controller = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context))
controller.peerSelected = { [weak self, weak controller] peerId in controller.peerSelected = { [weak self, weak controller] peerId in
@ -7982,7 +8043,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var navigation = navigation var navigation = navigation
if case .default = navigation { if case .default = navigation {
if let peer = peer as? TelegramUser, peer.botInfo != nil { if let peer = peer as? TelegramUser, peer.botInfo != nil {
navigation = .chat(textInputState: nil, subject: nil) navigation = .chat(textInputState: nil, subject: nil, peekData: nil)
} }
} }
strongSelf.openResolved(.peer(peer.id, navigation)) strongSelf.openResolved(.peer(peer.id, navigation))
@ -8245,13 +8306,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return return
} }
switch navigation { switch navigation {
case let .chat(_, subject): case let .chat(_, subject, peekData):
if case .peer(peerId) = strongSelf.chatLocation { if case .peer(peerId) = strongSelf.chatLocation {
if let subject = subject, case let .message(messageId) = subject { if let subject = subject, case let .message(messageId) = subject {
strongSelf.navigateToMessage(from: nil, to: .id(messageId)) strongSelf.navigateToMessage(from: nil, to: .id(messageId))
} }
} else if let navigationController = strongSelf.effectiveNavigationController { } else if let navigationController = strongSelf.effectiveNavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always, peekData: peekData))
} }
case .info: case .info:
strongSelf.navigationActionDisposable.set((strongSelf.context.account.postbox.loadedPeerWithId(peerId) strongSelf.navigationActionDisposable.set((strongSelf.context.account.postbox.loadedPeerWithId(peerId)

View File

@ -962,7 +962,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
var navigate: ChatControllerInteractionNavigateToPeer var navigate: ChatControllerInteractionNavigateToPeer
if item.content.firstMessage.id.peerId == item.context.account.peerId { if item.content.firstMessage.id.peerId == item.context.account.peerId {
navigate = .chat(textInputState: nil, subject: nil) navigate = .chat(textInputState: nil, subject: nil, peekData: nil)
} else { } else {
navigate = .info navigate = .info
} }
@ -970,7 +970,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
for attribute in item.content.firstMessage.attributes { for attribute in item.content.firstMessage.attributes {
if let attribute = attribute as? SourceReferenceMessageAttribute { if let attribute = attribute as? SourceReferenceMessageAttribute {
openPeerId = attribute.messageId.peerId openPeerId = attribute.messageId.peerId
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId)) navigate = .chat(textInputState: nil, subject: .message(attribute.messageId), peekData: nil)
} }
} }

View File

@ -2398,7 +2398,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
var navigate: ChatControllerInteractionNavigateToPeer var navigate: ChatControllerInteractionNavigateToPeer
if item.content.firstMessage.id.peerId == item.context.account.peerId { if item.content.firstMessage.id.peerId == item.context.account.peerId {
navigate = .chat(textInputState: nil, subject: nil) navigate = .chat(textInputState: nil, subject: nil, peekData: nil)
} else { } else {
navigate = .info navigate = .info
} }
@ -2406,7 +2406,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
for attribute in item.content.firstMessage.attributes { for attribute in item.content.firstMessage.attributes {
if let attribute = attribute as? SourceReferenceMessageAttribute { if let attribute = attribute as? SourceReferenceMessageAttribute {
openPeerId = attribute.messageId.peerId openPeerId = attribute.messageId.peerId
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId)) navigate = .chat(textInputState: nil, subject: .message(attribute.messageId), peekData: nil)
} }
} }
@ -2513,7 +2513,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
}) })
case let .peerMention(peerId, _): case let .peerMention(peerId, _):
return .action({ return .action({
self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil), nil) self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil, peekData: nil), nil)
}) })
case let .textMention(name): case let .textMention(name):
return .action({ return .action({

View File

@ -671,7 +671,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
var navigate: ChatControllerInteractionNavigateToPeer var navigate: ChatControllerInteractionNavigateToPeer
if item.content.firstMessage.id.peerId == item.context.account.peerId { if item.content.firstMessage.id.peerId == item.context.account.peerId {
navigate = .chat(textInputState: nil, subject: nil) navigate = .chat(textInputState: nil, subject: nil, peekData: nil)
} else { } else {
navigate = .info navigate = .info
} }
@ -679,7 +679,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
for attribute in item.content.firstMessage.attributes { for attribute in item.content.firstMessage.attributes {
if let attribute = attribute as? SourceReferenceMessageAttribute { if let attribute = attribute as? SourceReferenceMessageAttribute {
openPeerId = attribute.messageId.peerId openPeerId = attribute.messageId.peerId
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId)) navigate = .chat(textInputState: nil, subject: .message(attribute.messageId), peekData: nil)
} }
} }

View File

@ -690,7 +690,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
var navigate: ChatControllerInteractionNavigateToPeer var navigate: ChatControllerInteractionNavigateToPeer
if item.content.firstMessage.id.peerId == item.context.account.peerId { if item.content.firstMessage.id.peerId == item.context.account.peerId {
navigate = .chat(textInputState: nil, subject: nil) navigate = .chat(textInputState: nil, subject: nil, peekData: nil)
} else { } else {
navigate = .info navigate = .info
} }
@ -698,7 +698,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
for attribute in item.content.firstMessage.attributes { for attribute in item.content.firstMessage.attributes {
if let attribute = attribute as? SourceReferenceMessageAttribute { if let attribute = attribute as? SourceReferenceMessageAttribute {
openPeerId = attribute.messageId.peerId openPeerId = attribute.messageId.peerId
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId)) navigate = .chat(textInputState: nil, subject: .message(attribute.messageId), peekData: nil)
} }
} }

View File

@ -653,7 +653,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self.eventLogContext.setFilter(self.filter) self.eventLogContext.setFilter(self.filter)
} }
private func openPeer(peerId: PeerId, peer: Peer?) { private func openPeer(peerId: PeerId, peer: Peer?, peekData: ChatPeekTimeout? = nil) {
let peerSignal: Signal<Peer?, NoError> let peerSignal: Signal<Peer?, NoError>
if let peer = peer { if let peer = peer {
peerSignal = .single(peer) peerSignal = .single(peer)
@ -663,7 +663,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self.navigationActionDisposable.set((peerSignal |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in self.navigationActionDisposable.set((peerSignal |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in
if let strongSelf = self, let peer = peer { if let strongSelf = self, let peer = peer {
if peer is TelegramChannel, let navigationController = strongSelf.getNavigationController() { if peer is TelegramChannel, let navigationController = strongSelf.getNavigationController() {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), animated: true)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), peekData: peekData, animated: true))
} else { } else {
if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) {
strongSelf.pushController(infoController) strongSelf.pushController(infoController)
@ -796,9 +796,9 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
case let .instantView(webpage, anchor): case let .instantView(webpage, anchor):
strongSelf.pushController(InstantPageController(context: strongSelf.context, webPage: webpage, sourcePeerType: .channel, anchor: anchor)) strongSelf.pushController(InstantPageController(context: strongSelf.context, webPage: webpage, sourcePeerType: .channel, anchor: anchor))
case let .join(link): case let .join(link):
strongSelf.presentController(JoinLinkPreviewController(context: strongSelf.context, link: link, navigateToPeer: { peerId in strongSelf.presentController(JoinLinkPreviewController(context: strongSelf.context, link: link, navigateToPeer: { peerId, peekData in
if let strongSelf = self { if let strongSelf = self {
strongSelf.openPeer(peerId: peerId, peer: nil) strongSelf.openPeer(peerId: peerId, peer: nil, peekData: peekData)
} }
}, parentNavigationController: strongSelf.getNavigationController()), nil) }, parentNavigationController: strongSelf.getNavigationController()), nil)
case let .localization(identifier): case let .localization(identifier):

View File

@ -67,7 +67,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
}) })
} }
} else { } else {
controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation, subject: params.subject, botStart: params.botStart) controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation, subject: params.subject, botStart: params.botStart, peekData: params.peekData)
} }
controller.purposefulAction = params.purposefulAction controller.purposefulAction = params.purposefulAction
if params.activateMessageSearch { if params.activateMessageSearch {

View File

@ -25,9 +25,9 @@ private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatContr
if case .default = navigation { if case .default = navigation {
if let peerId = peerId { if let peerId = peerId {
if peerId.namespace == Namespaces.Peer.CloudUser { if peerId.namespace == Namespaces.Peer.CloudUser {
return .chat(textInputState: nil, subject: nil) return .chat(textInputState: nil, subject: nil, peekData: nil)
} else { } else {
return .chat(textInputState: nil, subject: nil) return .chat(textInputState: nil, subject: nil, peekData: nil)
} }
} else { } else {
return .info return .info
@ -88,7 +88,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
dismissInput() dismissInput()
navigationController?.pushViewController(controller) navigationController?.pushViewController(controller)
case let .channelMessage(peerId, messageId): case let .channelMessage(peerId, messageId):
openPeer(peerId, .chat(textInputState: nil, subject: .message(messageId))) openPeer(peerId, .chat(textInputState: nil, subject: .message(messageId), peekData: nil))
case let .stickerPack(name): case let .stickerPack(name):
dismissInput() dismissInput()
if false { if false {
@ -133,8 +133,8 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
navigationController?.pushViewController(InstantPageController(context: context, webPage: webpage, sourcePeerType: .channel, anchor: anchor)) navigationController?.pushViewController(InstantPageController(context: context, webPage: webpage, sourcePeerType: .channel, anchor: anchor))
case let .join(link): case let .join(link):
dismissInput() dismissInput()
present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peerId in present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peerId, peekData in
openPeer(peerId, .chat(textInputState: nil, subject: nil)) openPeer(peerId, .chat(textInputState: nil, subject: nil, peekData: peekData))
}, parentNavigationController: navigationController), nil) }, parentNavigationController: navigationController), nil)
case let .localization(identifier): case let .localization(identifier):
dismissInput() dismissInput()

View File

@ -214,10 +214,10 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
navigationController?.pushViewController(infoController) navigationController?.pushViewController(infoController)
} }
}) })
case let .chat(_, subject): case let .chat(_, subject, peekData):
context.sharedContext.applicationBindings.dismissNativeController() context.sharedContext.applicationBindings.dismissNativeController()
if let navigationController = navigationController { if let navigationController = navigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: subject)) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: subject, peekData: peekData))
} }
case let .withBotStartPayload(payload): case let .withBotStartPayload(payload):
context.sharedContext.applicationBindings.dismissNativeController() context.sharedContext.applicationBindings.dismissNativeController()

View File

@ -2176,9 +2176,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
if let navigationController = self.controller?.navigationController as? NavigationController { if let navigationController = self.controller?.navigationController as? NavigationController {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peerId), keepStack: .always)) self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peerId), keepStack: .always))
} }
case let .chat(_, subject): case let .chat(_, subject, peekData):
if let navigationController = self.controller?.navigationController as? NavigationController { if let navigationController = self.controller?.navigationController as? NavigationController {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always)) self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always, peekData: peekData))
} }
case .info: case .info:
self.resolveUrlDisposable.set((self.context.account.postbox.loadedPeerWithId(peerId) self.resolveUrlDisposable.set((self.context.account.postbox.loadedPeerWithId(peerId)

View File

@ -757,9 +757,9 @@ public class PeerMediaCollectionController: TelegramBaseController {
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.navigationController as? NavigationController, openPeer: { peerId, navigation in strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.navigationController as? NavigationController, openPeer: { peerId, navigation in
if let strongSelf = self { if let strongSelf = self {
switch navigation { switch navigation {
case let .chat(_, subject): case let .chat(_, subject, peekData):
if let navigationController = strongSelf.navigationController as? NavigationController { if let navigationController = strongSelf.navigationController as? NavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always, peekData: peekData))
} }
case .info: case .info:
strongSelf.navigationActionDisposable.set((strongSelf.context.account.postbox.loadedPeerWithId(peerId) strongSelf.navigationActionDisposable.set((strongSelf.context.account.postbox.loadedPeerWithId(peerId)

View File

@ -24,9 +24,9 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate
let openResolvedPeerImpl: (PeerId?, ChatControllerInteractionNavigateToPeer) -> Void = { [weak controller] peerId, navigation in let openResolvedPeerImpl: (PeerId?, ChatControllerInteractionNavigateToPeer) -> Void = { [weak controller] peerId, navigation in
context.sharedContext.openResolvedUrl(.peer(peerId, navigation), context: context, urlContext: .generic, navigationController: (controller?.navigationController as? NavigationController), openPeer: { (peerId, navigation) in context.sharedContext.openResolvedUrl(.peer(peerId, navigation), context: context, urlContext: .generic, navigationController: (controller?.navigationController as? NavigationController), openPeer: { (peerId, navigation) in
switch navigation { switch navigation {
case let .chat(_, subject): case let .chat(_, subject, peekData):
if let navigationController = controller?.navigationController as? NavigationController { if let navigationController = controller?.navigationController as? NavigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: subject, keepStack: .always)) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: subject, keepStack: .always, peekData: peekData))
} }
case .info: case .info:
let peerSignal: Signal<Peer?, NoError> let peerSignal: Signal<Peer?, NoError>
@ -64,8 +64,8 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate
case let .instantView(webpage, anchor): case let .instantView(webpage, anchor):
(controller.navigationController as? NavigationController)?.pushViewController(InstantPageController(context: context, webPage: webpage, sourcePeerType: .group, anchor: anchor)) (controller.navigationController as? NavigationController)?.pushViewController(InstantPageController(context: context, webPage: webpage, sourcePeerType: .group, anchor: anchor))
case let .join(link): case let .join(link):
controller.present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peerId in controller.present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peerId, peekData in
openResolvedPeerImpl(peerId, .chat(textInputState: nil, subject: nil)) openResolvedPeerImpl(peerId, .chat(textInputState: nil, subject: nil, peekData: peekData))
}, parentNavigationController: controller.navigationController as? NavigationController), in: .window(.root)) }, parentNavigationController: controller.navigationController as? NavigationController), in: .window(.root))
#if ENABLE_WALLET #if ENABLE_WALLET
case let .wallet(address, amount, comment): case let .wallet(address, amount, comment):

View File

@ -282,9 +282,9 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig
} }
} else { } else {
if let peer = peer as? TelegramUser, peer.botInfo == nil { if let peer = peer as? TelegramUser, peer.botInfo == nil {
return .peer(peer.id, .chat(textInputState: nil, subject: nil)) return .peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil))
} else { } else {
return .peer(peer.id, .chat(textInputState: nil, subject: nil)) return .peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil))
} }
} }
} else { } else {
@ -297,7 +297,7 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig
} }
|> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in |> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in
if let peer = peer { if let peer = peer {
return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil))) return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil)))
} else { } else {
return .single(.inaccessiblePeer) return .single(.inaccessiblePeer)
} }
@ -308,12 +308,12 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig
} }
|> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in |> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in
if let peer = peer { if let peer = peer {
return .single(.peer(peer.id, .chat(textInputState: nil, subject: .message(messageId)))) return .single(.peer(peer.id, .chat(textInputState: nil, subject: .message(messageId), peekData: nil)))
} else { } else {
return findChannelById(postbox: account.postbox, network: account.network, channelId: messageId.peerId.id) return findChannelById(postbox: account.postbox, network: account.network, channelId: messageId.peerId.id)
|> map { foundPeer -> ResolvedUrl? in |> map { foundPeer -> ResolvedUrl? in
if let foundPeer = foundPeer { if let foundPeer = foundPeer {
return .peer(foundPeer.id, .chat(textInputState: nil, subject: .message(messageId))) return .peer(foundPeer.id, .chat(textInputState: nil, subject: .message(messageId), peekData: nil))
} else { } else {
return .inaccessiblePeer return .inaccessiblePeer
} }

View File

@ -449,12 +449,12 @@ public final class WalletStrings: Equatable {
public var Wallet_SecureStorageReset_Title: String { return self._s[219]! } public var Wallet_SecureStorageReset_Title: String { return self._s[219]! }
public var Wallet_Receive_CommentHeader: String { return self._s[220]! } public var Wallet_Receive_CommentHeader: String { return self._s[220]! }
public var Wallet_Info_ReceiveGrams: String { return self._s[221]! } public var Wallet_Info_ReceiveGrams: String { return self._s[221]! }
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
let form = getPluralizationForm(self.lc, value) let form = getPluralizationForm(self.lc, value)
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator) let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
} }
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
let form = getPluralizationForm(self.lc, value) let form = getPluralizationForm(self.lc, value)
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator) let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)