From f259829c8ade81326e0a1bd4fc84f6ebcb6e4473 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 20 Feb 2024 14:45:25 +0400 Subject: [PATCH] [WIP] Business --- .../Sources/AccountContext.swift | 12 +- .../Sources/ChatController.swift | 21 +- .../Sources/AttachmentPanel.swift | 2 + .../Sources/ChatListControllerNode.swift | 1 + .../Sources/Node/ChatListItem.swift | 55 ++- .../ChatPanelInterfaceInteraction.swift | 8 + .../Sources/ContactsControllerNode.swift | 1 + .../Sources/ItemListAddressItem.swift | 2 +- .../Sources/ItemListStickerPackItem.swift | 2 +- .../ItemListSelectableControlNode.swift | 35 +- .../Items/ItemListTextWithLabelItem.swift | 2 +- .../Sources/ListMessageFileItemNode.swift | 2 +- .../Sources/ListMessageSnippetItemNode.swift | 2 +- submodules/Postbox/Sources/Message.swift | 8 + .../PremiumUI/Sources/GiftOptionItem.swift | 2 +- submodules/TelegramApi/Sources/Api0.swift | 46 ++- submodules/TelegramApi/Sources/Api12.swift | 18 +- submodules/TelegramApi/Sources/Api2.swift | 132 +++++++ submodules/TelegramApi/Sources/Api21.swift | 44 +++ submodules/TelegramApi/Sources/Api22.swift | 184 +++++++++ submodules/TelegramApi/Sources/Api23.swift | 136 ++++--- submodules/TelegramApi/Sources/Api27.swift | 58 +++ submodules/TelegramApi/Sources/Api28.swift | 284 +++++++------- submodules/TelegramApi/Sources/Api29.swift | 244 +++++++----- submodules/TelegramApi/Sources/Api30.swift | 364 ++++++++++-------- submodules/TelegramApi/Sources/Api31.swift | 168 ++++++++ submodules/TelegramApi/Sources/Api32.swift | 320 ++++++++++++++- .../ApiUtils/StoreMessage_Telegram.swift | 8 +- .../PendingMessages/RequestEditMessage.swift | 4 +- .../StandaloneSendMessage.swift | 12 +- .../Sources/State/AccountViewTracker.swift | 2 +- .../Sources/State/ApplyUpdateMessage.swift | 2 +- .../Sources/State/PendingMessageManager.swift | 12 +- .../Sources/State/Serialization.swift | 2 +- .../Sources/State/UpdateMessageService.swift | 4 +- .../Sources/State/UpdatesApiUtils.swift | 12 +- .../SyncCore/SyncCore_CachedUserData.swift | 257 +++++++++++-- .../SyncCore/SyncCore_Namespaces.swift | 7 + .../TelegramEngineAccountData.swift | 60 +++ .../TelegramEngine/Data/PeersData.swift | 56 +++ .../TelegramEngine/Messages/ForwardGame.swift | 2 +- .../TelegramEngine/Messages/Polls.swift | 2 +- .../Messages/QuickReplyMessages.swift | 157 ++++++++ .../Peers/UpdateCachedPeerData.swift | 16 +- submodules/TelegramUI/BUILD | 2 +- .../Sources/ChatRecentActionsController.swift | 2 + .../Sources/ChatListNavigationBar.swift | 10 + .../ListMultilineTextFieldItemComponent.swift | 7 + .../Sources/PeerInfoScreen.swift | 101 ++++- .../Sources/PeerSelectionControllerNode.swift | 2 + .../BUILD | 5 +- ...ticBusinessMessageListItemComponent.swift} | 1 + ...ticBusinessMessageSetupChatContents.swift} | 2 +- ...AutomaticBusinessMessageSetupScreen.swift} | 38 +- .../QuickReplyEmptyStateComponent.swift | 0 .../Sources/QuickReplySetupScreen.swift | 310 ++++++++++++--- .../Sources/BusinessDaySetupScreen.swift | 58 ++- .../Sources/BusinessHoursSetupScreen.swift | 170 ++++++-- .../Sources/BusinessLocationSetupScreen.swift | 51 ++- .../Sources/BusinessSetupScreen.swift | 41 +- .../Sources/TextFieldComponent.swift | 17 + .../TelegramUI/Sources/ChatController.swift | 50 +++ .../ChatInterfaceInputContextPanels.swift | 8 +- .../ChatInterfaceStateContextQueries.swift | 52 ++- .../CommandChatInputContextPanelNode.swift | 336 ++++++++++++++-- .../Sources/SharedAccountContext.swift | 22 +- ...textResultsChatInputContextPanelNode.swift | 2 +- ...ntextResultsChatInputPanelButtonItem.swift | 38 +- 68 files changed, 3331 insertions(+), 762 deletions(-) create mode 100644 submodules/TelegramCore/Sources/TelegramEngine/Messages/QuickReplyMessages.swift rename submodules/TelegramUI/Components/Settings/{GreetingMessageSetupScreen => AutomaticBusinessMessageSetupScreen}/BUILD (92%) rename submodules/TelegramUI/Components/Settings/{GreetingMessageSetupScreen/Sources/GreetingMessageListItemComponent.swift => AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageListItemComponent.swift} (99%) rename submodules/TelegramUI/Components/Settings/{GreetingMessageSetupScreen/Sources/GreetingMessageSetupChatContents.swift => AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageSetupChatContents.swift} (99%) rename submodules/TelegramUI/Components/Settings/{GreetingMessageSetupScreen/Sources/GreetingMessageSetupScreen.swift => AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageSetupScreen.swift} (97%) rename submodules/TelegramUI/Components/Settings/{GreetingMessageSetupScreen => AutomaticBusinessMessageSetupScreen}/Sources/QuickReplyEmptyStateComponent.swift (100%) rename submodules/TelegramUI/Components/Settings/{GreetingMessageSetupScreen => AutomaticBusinessMessageSetupScreen}/Sources/QuickReplySetupScreen.swift (63%) diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index c1a7ae3a31..53072625e6 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -847,6 +847,9 @@ public protocol TelegramRootControllerInterface: NavigationController { func openSettings() } +public protocol QuickReplySetupScreenInitialData: AnyObject { +} + public protocol SharedAccountContext: AnyObject { var sharedContainerPath: String { get } var basePath: String { get } @@ -934,10 +937,11 @@ public protocol SharedAccountContext: AnyObject { func makeArchiveSettingsController(context: AccountContext) -> ViewController func makeBusinessSetupScreen(context: AccountContext) -> ViewController func makeChatbotSetupScreen(context: AccountContext) -> ViewController - func makeBusinessLocationSetupScreen(context: AccountContext) -> ViewController - func makeBusinessHoursSetupScreen(context: AccountContext) -> ViewController - func makeGreetingMessageSetupScreen(context: AccountContext, isAwayMode: Bool) -> ViewController - func makeQuickReplySetupScreen(context: AccountContext) -> ViewController + func makeBusinessLocationSetupScreen(context: AccountContext, initialValue: TelegramBusinessLocation?, completion: @escaping (TelegramBusinessLocation?) -> Void) -> ViewController + func makeBusinessHoursSetupScreen(context: AccountContext, initialValue: TelegramBusinessHours?, completion: @escaping (TelegramBusinessHours?) -> Void) -> ViewController + func makeAutomaticBusinessMessageSetupScreen(context: AccountContext, isAwayMode: Bool) -> ViewController + func makeQuickReplySetupScreen(context: AccountContext, initialData: QuickReplySetupScreenInitialData) -> ViewController + func makeQuickReplySetupScreenInitialData(context: AccountContext) -> Signal func navigateToChatController(_ params: NavigateToChatControllerParams) func navigateToForumChannel(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController) func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?, keepStack: NavigateToChatKeepStack) -> Signal diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index 947b186ec8..f423a580d6 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -803,11 +803,30 @@ public enum ChatControllerPresentationMode: Equatable { case inline(NavigationController?) } +public enum ChatInputTextCommand: Equatable { + case command(PeerCommand) + case shortcut(QuickReplyMessageShortcut) +} + +public struct ChatInputQueryCommandsResult: Equatable { + public var commands: [ChatInputTextCommand] + public var accountPeer: EnginePeer? + public var hasShortcuts: Bool + public var query: String + + public init(commands: [ChatInputTextCommand], accountPeer: EnginePeer?, hasShortcuts: Bool, query: String) { + self.commands = commands + self.accountPeer = accountPeer + self.hasShortcuts = hasShortcuts + self.query = query + } +} + public enum ChatPresentationInputQueryResult: Equatable { case stickers([FoundStickerItem]) case hashtags([String]) case mentions([EnginePeer]) - case commands([PeerCommand]) + case commands(ChatInputQueryCommandsResult) case emojis([(String, TelegramMediaFile?, String)], NSRange) case contextRequestResult(EnginePeer?, ChatContextResultCollection?) diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index 77938c59f7..39ebcc7c5e 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -821,6 +821,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { }, sendContextResult: { _, _, _, _ in return false }, sendBotCommand: { _, _ in + }, sendShortcut: { _ in + }, openEditShortcuts: { }, sendBotStart: { _ in }, botSwitchChatWithPayload: { _, _ in }, beginMediaRecording: { _ in diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index ea4b09cbcf..9fa32c57fa 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -1327,6 +1327,7 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { statusBarHeight: layout.statusBarHeight ?? 0.0, sideInset: layout.safeInsets.left, isSearchActive: self.isSearchDisplayControllerActive, + isSearchEnabled: true, primaryContent: headerContent?.primaryContent, secondaryContent: headerContent?.secondaryContent, secondaryTransition: self.inlineStackContainerTransitionFraction, diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 22a06898ba..4396b5b4f4 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -92,10 +92,12 @@ public enum ChatListItemContent { public struct CustomMessageListData: Equatable { public var commandPrefix: String? + public var searchQuery: String? public var messageCount: Int? - public init(commandPrefix: String?, messageCount: Int?) { + public init(commandPrefix: String?, searchQuery: String?, messageCount: Int?) { self.commandPrefix = commandPrefix + self.searchQuery = searchQuery self.messageCount = messageCount } } @@ -1625,7 +1627,19 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { isForumAvatar = true } } + + var avatarDiameter = min(60.0, floor(item.presentationData.fontSize.baseDisplaySize * 60.0 / 17.0)) + + if case let .peer(peerData) = item.content, let customMessageListData = peerData.customMessageListData, customMessageListData.commandPrefix != nil { + avatarDiameter = 40.0 + } + if avatarDiameter != 60.0 { + let avatarFontSize = floor(avatarDiameter * 26.0 / 60.0) + if self.avatarNode.font.pointSize != avatarFontSize { + self.avatarNode.font = avatarPlaceholderFont(size: avatarFontSize) + } + } self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForumAvatar ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0)) if peer.isPremium && peer.id != item.context.account.peerId { @@ -2011,33 +2025,48 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let editingOffset: CGFloat var reorderInset: CGFloat = 0.0 if item.editing { - let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, item.selected, true) + let selectionControlStyle: ItemListSelectableControlNode.Style + if case let .peer(peerData) = item.content, let customMessageListData = peerData.customMessageListData, customMessageListData.commandPrefix != nil { + selectionControlStyle = .small + } else { + selectionControlStyle = .compact + } + + let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, item.selected, selectionControlStyle) if promoInfo == nil && !isPeerGroup { selectableControlSizeAndApply = sizeAndApply } editingOffset = sizeAndApply.0 + var canReorder = false + if case let .chatList(index) = item.index, index.pinningIndex != nil, promoInfo == nil, !isPeerGroup { - let sizeAndApply = reorderControlLayout(item.presentationData.theme) - reorderControlSizeAndApply = sizeAndApply - reorderInset = sizeAndApply.0 + canReorder = true } else if case let .forum(pinnedIndex, _, _, _, _) = item.index, case .index = pinnedIndex { if case let .chat(itemPeer) = contentPeer, case let .channel(channel) = itemPeer.peer { let canPin = channel.flags.contains(.isCreator) || channel.hasPermission(.pinMessages) if canPin { - let sizeAndApply = reorderControlLayout(item.presentationData.theme) - reorderControlSizeAndApply = sizeAndApply - reorderInset = sizeAndApply.0 + canReorder = true } } } + + if case let .peer(peerData) = item.content, let customMessageListData = peerData.customMessageListData, customMessageListData.commandPrefix != nil { + canReorder = true + } + + if canReorder { + let sizeAndApply = reorderControlLayout(item.presentationData.theme) + reorderControlSizeAndApply = sizeAndApply + reorderInset = sizeAndApply.0 + } } else { editingOffset = 0.0 } let enableChatListPhotos = true - + // if changed, adjust setupItem accordingly var avatarDiameter = min(60.0, floor(item.presentationData.fontSize.baseDisplaySize * 60.0 / 17.0)) let avatarLeftInset: CGFloat @@ -2427,6 +2456,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText) let boldTextFont = Font.semibold(floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0)) mutableAttributedText.insert(NSAttributedString(string: commandPrefix + " ", font: boldTextFont, textColor: theme.titleColor), at: 0) + if let searchQuery = customMessageListData.searchQuery { + let range = (mutableAttributedText.string as NSString).range(of: searchQuery) + if range.location == 0 { + mutableAttributedText.addAttribute(.foregroundColor, value: item.presentationData.theme.list.itemAccentColor, range: range) + } + } attributedText = mutableAttributedText } @@ -3127,7 +3162,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { itemHeight -= 21.0 if case let .peer(peerData) = item.content, let customMessageListData = peerData.customMessageListData, customMessageListData.commandPrefix != nil { itemHeight += measureLayout.size.height * 2.0 - itemHeight += 22.0 + itemHeight += 20.0 } else { itemHeight += titleLayout.size.height itemHeight += measureLayout.size.height * 3.0 diff --git a/submodules/ChatPresentationInterfaceState/Sources/ChatPanelInterfaceInteraction.swift b/submodules/ChatPresentationInterfaceState/Sources/ChatPanelInterfaceInteraction.swift index 02ad1afa74..98187511ea 100644 --- a/submodules/ChatPresentationInterfaceState/Sources/ChatPanelInterfaceInteraction.swift +++ b/submodules/ChatPresentationInterfaceState/Sources/ChatPanelInterfaceInteraction.swift @@ -104,6 +104,8 @@ public final class ChatPanelInterfaceInteraction { public let togglePeerNotifications: () -> Void public let sendContextResult: (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool public let sendBotCommand: (Peer, String) -> Void + public let sendShortcut: (QuickReplyMessageShortcut) -> Void + public let openEditShortcuts: () -> Void public let sendBotStart: (String?) -> Void public let botSwitchChatWithPayload: (PeerId, String) -> Void public let beginMediaRecording: (Bool) -> Void @@ -217,6 +219,8 @@ public final class ChatPanelInterfaceInteraction { togglePeerNotifications: @escaping () -> Void, sendContextResult: @escaping (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool, sendBotCommand: @escaping (Peer, String) -> Void, + sendShortcut: @escaping (QuickReplyMessageShortcut) -> Void, + openEditShortcuts: @escaping () -> Void, sendBotStart: @escaping (String?) -> Void, botSwitchChatWithPayload: @escaping (PeerId, String) -> Void, beginMediaRecording: @escaping (Bool) -> Void, @@ -329,6 +333,8 @@ public final class ChatPanelInterfaceInteraction { self.togglePeerNotifications = togglePeerNotifications self.sendContextResult = sendContextResult self.sendBotCommand = sendBotCommand + self.sendShortcut = sendShortcut + self.openEditShortcuts = openEditShortcuts self.sendBotStart = sendBotStart self.botSwitchChatWithPayload = botSwitchChatWithPayload self.beginMediaRecording = beginMediaRecording @@ -448,6 +454,8 @@ public final class ChatPanelInterfaceInteraction { }, sendContextResult: { _, _, _, _ in return false }, sendBotCommand: { _, _ in + }, sendShortcut: { _ in + }, openEditShortcuts: { }, sendBotStart: { _ in }, botSwitchChatWithPayload: { _, _ in }, beginMediaRecording: { _ in diff --git a/submodules/ContactListUI/Sources/ContactsControllerNode.swift b/submodules/ContactListUI/Sources/ContactsControllerNode.swift index 6105a64ba9..32642969bf 100644 --- a/submodules/ContactListUI/Sources/ContactsControllerNode.swift +++ b/submodules/ContactListUI/Sources/ContactsControllerNode.swift @@ -362,6 +362,7 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { statusBarHeight: layout.statusBarHeight ?? 0.0, sideInset: layout.safeInsets.left, isSearchActive: self.isSearchDisplayControllerActive, + isSearchEnabled: true, primaryContent: primaryContent, secondaryContent: nil, secondaryTransition: 0.0, diff --git a/submodules/ItemListAddressItem/Sources/ItemListAddressItem.swift b/submodules/ItemListAddressItem/Sources/ItemListAddressItem.swift index ede2fdcd3a..fe08667473 100644 --- a/submodules/ItemListAddressItem/Sources/ItemListAddressItem.swift +++ b/submodules/ItemListAddressItem/Sources/ItemListAddressItem.swift @@ -188,7 +188,7 @@ public class ItemListAddressItemNode: ListViewItemNode { var leftOffset: CGFloat = 0.0 var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)? if let selected = item.selected { - let (selectionWidth, selectionApply) = selectionNodeLayout(item.theme.list.itemCheckColors.strokeColor, item.theme.list.itemCheckColors.fillColor, item.theme.list.itemCheckColors.foregroundColor, selected, false) + let (selectionWidth, selectionApply) = selectionNodeLayout(item.theme.list.itemCheckColors.strokeColor, item.theme.list.itemCheckColors.fillColor, item.theme.list.itemCheckColors.foregroundColor, selected, .regular) selectionNodeWidthAndApply = (selectionWidth, selectionApply) leftOffset += selectionWidth - 8.0 } diff --git a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift index dd7996cd03..43710530f4 100644 --- a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift +++ b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift @@ -440,7 +440,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { if case let .check(checked) = item.control { selected = checked } - let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, true) + let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, .compact) selectableControlSizeAndApply = sizeAndApply editingOffset = sizeAndApply.0 } else { diff --git a/submodules/ItemListUI/Sources/ItemListSelectableControlNode.swift b/submodules/ItemListUI/Sources/ItemListSelectableControlNode.swift index 87cd88ca50..ceac041c53 100644 --- a/submodules/ItemListUI/Sources/ItemListSelectableControlNode.swift +++ b/submodules/ItemListUI/Sources/ItemListSelectableControlNode.swift @@ -5,6 +5,12 @@ import Display import CheckNode public final class ItemListSelectableControlNode: ASDisplayNode { + public enum Style { + case regular + case compact + case small + } + private let checkNode: CheckNode public init(strokeColor: UIColor, fillColor: UIColor, foregroundColor: UIColor) { @@ -16,8 +22,8 @@ public final class ItemListSelectableControlNode: ASDisplayNode { self.addSubnode(self.checkNode) } - public static func asyncLayout(_ node: ItemListSelectableControlNode?) -> (_ strokeColor: UIColor, _ fillColor: UIColor, _ foregroundColor: UIColor, _ selected: Bool, _ compact: Bool) -> (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode) { - return { strokeColor, fillColor, foregroundColor, selected, compact in + public static func asyncLayout(_ node: ItemListSelectableControlNode?) -> (_ strokeColor: UIColor, _ fillColor: UIColor, _ foregroundColor: UIColor, _ selected: Bool, _ style: Style) -> (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode) { + return { strokeColor, fillColor, foregroundColor, selected, style in let resultNode: ItemListSelectableControlNode if let node = node { resultNode = node @@ -25,9 +31,28 @@ public final class ItemListSelectableControlNode: ASDisplayNode { resultNode = ItemListSelectableControlNode(strokeColor: strokeColor, fillColor: fillColor, foregroundColor: foregroundColor) } - return (compact ? 38.0 : 45.0, { size, animated in - let checkSize = CGSize(width: 26.0, height: 26.0) - resultNode.checkNode.frame = CGRect(origin: CGPoint(x: compact ? 11.0 : 13.0, y: floorToScreenPixels((size.height - checkSize.height) / 2.0)), size: checkSize) + let offsetSize: CGFloat + switch style { + case .regular: + offsetSize = 45.0 + case .compact: + offsetSize = 38.0 + case .small: + offsetSize = 44.0 + } + + return (offsetSize, { size, animated in + let checkSize: CGSize + let checkOffset: CGFloat + switch style { + case .regular, .compact: + checkSize = CGSize(width: 26.0, height: 26.0) + checkOffset = style == .compact ? 11.0 : 13.0 + case .small: + checkSize = CGSize(width: 22.0, height: 22.0) + checkOffset = 16.0 + } + resultNode.checkNode.frame = CGRect(origin: CGPoint(x: checkOffset, y: floorToScreenPixels((size.height - checkSize.height) / 2.0)), size: checkSize) resultNode.checkNode.setSelected(selected, animated: animated) return resultNode }) diff --git a/submodules/ItemListUI/Sources/Items/ItemListTextWithLabelItem.swift b/submodules/ItemListUI/Sources/Items/ItemListTextWithLabelItem.swift index 6dd6f49b08..1f4a6c2f4a 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListTextWithLabelItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListTextWithLabelItem.swift @@ -189,7 +189,7 @@ public class ItemListTextWithLabelItemNode: ListViewItemNode { var leftOffset: CGFloat = 0.0 var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)? if let selected = item.selected { - let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, false) + let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, .regular) selectionNodeWidthAndApply = (selectionWidth, selectionApply) leftOffset += selectionWidth - 8.0 } diff --git a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift index 3fe9f80400..9840e11b37 100644 --- a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift @@ -595,7 +595,7 @@ public final class ListMessageFileItemNode: ListMessageNode { var leftOffset: CGFloat = 0.0 var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)? if case let .selectable(selected) = item.selection { - let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.theme.list.itemCheckColors.fillColor, item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, selected, false) + let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.theme.list.itemCheckColors.fillColor, item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, selected, .regular) selectionNodeWidthAndApply = (selectionWidth, selectionApply) leftOffset += selectionWidth } diff --git a/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift index a640ceb8d1..a585475f19 100644 --- a/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift @@ -259,7 +259,7 @@ public final class ListMessageSnippetItemNode: ListMessageNode { var leftOffset: CGFloat = 0.0 var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)? if case let .selectable(selected) = item.selection { - let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.theme.list.itemCheckColors.fillColor, item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, selected, false) + let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.theme.list.itemCheckColors.fillColor, item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, selected, .regular) selectionNodeWidthAndApply = (selectionWidth, selectionApply) leftOffset += selectionWidth } diff --git a/submodules/Postbox/Sources/Message.swift b/submodules/Postbox/Sources/Message.swift index 3f465a5af5..58c14eda19 100644 --- a/submodules/Postbox/Sources/Message.swift +++ b/submodules/Postbox/Sources/Message.swift @@ -736,6 +736,14 @@ public final class Message { self.associatedStories = associatedStories } + public func withUpdatedStableId(stableId: UInt32) -> Message { + return Message(stableId: stableId, stableVersion: self.stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, customTags: self.customTags, forwardInfo: self.forwardInfo, author: self.author, text: self.text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds, associatedMedia: self.associatedMedia, associatedThreadInfo: self.associatedThreadInfo, associatedStories: self.associatedStories) + } + + public func withUpdatedId(id: MessageId) -> Message { + return Message(stableId: self.stableId, stableVersion: self.stableVersion, id: id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, customTags: self.customTags, forwardInfo: self.forwardInfo, author: self.author, text: self.text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds, associatedMedia: self.associatedMedia, associatedThreadInfo: self.associatedThreadInfo, associatedStories: self.associatedStories) + } + public func withUpdatedStableVersion(stableVersion: UInt32) -> Message { return Message(stableId: self.stableId, stableVersion: stableVersion, id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, groupInfo: self.groupInfo, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, customTags: self.customTags, forwardInfo: self.forwardInfo, author: self.author, text: self.text, attributes: self.attributes, media: self.media, peers: self.peers, associatedMessages: self.associatedMessages, associatedMessageIds: self.associatedMessageIds, associatedMedia: self.associatedMedia, associatedThreadInfo: self.associatedThreadInfo, associatedStories: self.associatedStories) } diff --git a/submodules/PremiumUI/Sources/GiftOptionItem.swift b/submodules/PremiumUI/Sources/GiftOptionItem.swift index 0ff43e8df6..9a304ed762 100644 --- a/submodules/PremiumUI/Sources/GiftOptionItem.swift +++ b/submodules/PremiumUI/Sources/GiftOptionItem.swift @@ -296,7 +296,7 @@ class GiftOptionItemNode: ItemListRevealOptionsItemNode { var editingOffset: CGFloat = 0.0 if let isSelected = item.isSelected { - let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, isSelected, false) + let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, isSelected, .regular) selectableControlSizeAndApply = sizeAndApply editingOffset = sizeAndApply.0 } diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 4188aaf0c2..47f52d79d8 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -12,6 +12,7 @@ public enum Api { public enum phone {} public enum photos {} public enum premium {} + public enum smsjobs {} public enum stats {} public enum stickers {} public enum storage {} @@ -34,6 +35,7 @@ public enum Api { public enum phone {} public enum photos {} public enum premium {} + public enum smsjobs {} public enum stats {} public enum stickers {} public enum stories {} @@ -99,6 +101,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-944407322] = { return Api.BotMenuButton.parse_botMenuButton($0) } dict[1113113093] = { return Api.BotMenuButton.parse_botMenuButtonCommands($0) } dict[1966318984] = { return Api.BotMenuButton.parse_botMenuButtonDefault($0) } + dict[-1104414653] = { return Api.BusinessLocation.parse_businessLocation($0) } + dict[302717625] = { return Api.BusinessWeeklyOpen.parse_businessWeeklyOpen($0) } + dict[-1936543592] = { return Api.BusinessWorkHours.parse_businessWorkHours($0) } dict[1462101002] = { return Api.CdnConfig.parse_cdnConfig($0) } dict[-914167110] = { return Api.CdnPublicKey.parse_cdnPublicKey($0) } dict[531458253] = { return Api.ChannelAdminLogEvent.parse_channelAdminLogEvent($0) } @@ -473,7 +478,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[340088945] = { return Api.MediaArea.parse_mediaAreaSuggestedReaction($0) } dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) } dict[64088654] = { return Api.MediaAreaCoordinates.parse_mediaAreaCoordinates($0) } - dict[508332649] = { return Api.Message.parse_message($0) } + dict[-1502839044] = { return Api.Message.parse_message($0) } dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) } dict[721967202] = { return Api.Message.parse_messageService($0) } dict[-872240531] = { return Api.MessageAction.parse_messageActionBoostApply($0) } @@ -812,6 +817,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-651419003] = { return Api.SendMessageAction.parse_speakingInGroupCallAction($0) } dict[-1239335713] = { return Api.ShippingOption.parse_shippingOption($0) } dict[-2010155333] = { return Api.SimpleWebViewResult.parse_simpleWebViewResultUrl($0) } + dict[-425595208] = { return Api.SmsJob.parse_smsJob($0) } dict[-313293833] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) } dict[1035529315] = { return Api.SponsoredWebPage.parse_sponsoredWebPage($0) } dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) } @@ -846,6 +852,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1964978502] = { return Api.TextWithEntities.parse_textWithEntities($0) } dict[-1609668650] = { return Api.Theme.parse_theme($0) } dict[-94849324] = { return Api.ThemeSettings.parse_themeSettings($0) } + dict[-7173643] = { return Api.Timezone.parse_timezone($0) } dict[-305282981] = { return Api.TopPeer.parse_topPeer($0) } dict[344356834] = { return Api.TopPeerCategory.parse_topPeerCategoryBotsInline($0) } dict[-1419371685] = { return Api.TopPeerCategory.parse_topPeerCategoryBotsPM($0) } @@ -897,6 +904,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1906403213] = { return Api.Update.parse_updateDcOptions($0) } dict[-1020437742] = { return Api.Update.parse_updateDeleteChannelMessages($0) } dict[-1576161051] = { return Api.Update.parse_updateDeleteMessages($0) } + dict[1407644140] = { return Api.Update.parse_updateDeleteQuickReply($0) } + dict[1450174413] = { return Api.Update.parse_updateDeleteQuickReplyMessages($0) } dict[-1870238482] = { return Api.Update.parse_updateDeleteScheduledMessages($0) } dict[654302845] = { return Api.Update.parse_updateDialogFilter($0) } dict[-1512627963] = { return Api.Update.parse_updateDialogFilterOrder($0) } @@ -930,6 +939,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1656358105] = { return Api.Update.parse_updateNewChannelMessage($0) } dict[314359194] = { return Api.Update.parse_updateNewEncryptedMessage($0) } dict[522914557] = { return Api.Update.parse_updateNewMessage($0) } + dict[-1386034803] = { return Api.Update.parse_updateNewQuickReply($0) } dict[967122427] = { return Api.Update.parse_updateNewScheduledMessage($0) } dict[1753886890] = { return Api.Update.parse_updateNewStickerSet($0) } dict[-1094555409] = { return Api.Update.parse_updateNotifySettings($0) } @@ -947,6 +957,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1751942566] = { return Api.Update.parse_updatePinnedSavedDialogs($0) } dict[-298113238] = { return Api.Update.parse_updatePrivacy($0) } dict[861169551] = { return Api.Update.parse_updatePtsChanged($0) } + dict[230929261] = { return Api.Update.parse_updateQuickReplies($0) } + dict[1040518415] = { return Api.Update.parse_updateQuickReplyMessage($0) } dict[-693004986] = { return Api.Update.parse_updateReadChannelDiscussionInbox($0) } dict[1767677564] = { return Api.Update.parse_updateReadChannelDiscussionOutbox($0) } dict[-1842450928] = { return Api.Update.parse_updateReadChannelInbox($0) } @@ -966,6 +978,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1960361625] = { return Api.Update.parse_updateSavedRingtones($0) } dict[2103604867] = { return Api.Update.parse_updateSentStoryReaction($0) } dict[-337352679] = { return Api.Update.parse_updateServiceNotification($0) } + dict[-245208620] = { return Api.Update.parse_updateSmsJob($0) } dict[834816008] = { return Api.Update.parse_updateStickerSets($0) } dict[196268545] = { return Api.Update.parse_updateStickerSetsOrder($0) } dict[738741697] = { return Api.Update.parse_updateStoriesStealthMode($0) } @@ -993,7 +1006,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1831650802] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) } dict[559694904] = { return Api.User.parse_user($0) } dict[-742634630] = { return Api.User.parse_userEmpty($0) } - dict[-1179571092] = { return Api.UserFull.parse_userFull($0) } + dict[-501688336] = { return Api.UserFull.parse_userFull($0) } dict[-2100168954] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) } dict[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) } dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) } @@ -1120,6 +1133,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[2013922064] = { return Api.help.TermsOfService.parse_termsOfService($0) } dict[686618977] = { return Api.help.TermsOfServiceUpdate.parse_termsOfServiceUpdate($0) } dict[-483352705] = { return Api.help.TermsOfServiceUpdate.parse_termsOfServiceUpdateEmpty($0) } + dict[2071260529] = { return Api.help.TimezonesList.parse_timezonesList($0) } + dict[-1761146676] = { return Api.help.TimezonesList.parse_timezonesListNotModified($0) } dict[32192344] = { return Api.help.UserInfo.parse_userInfo($0) } dict[-206688531] = { return Api.help.UserInfo.parse_userInfoEmpty($0) } dict[-275956116] = { return Api.messages.AffectedFoundMessages.parse_affectedFoundMessages($0) } @@ -1170,6 +1185,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[978610270] = { return Api.messages.Messages.parse_messagesSlice($0) } dict[863093588] = { return Api.messages.PeerDialogs.parse_peerDialogs($0) } dict[1753266509] = { return Api.messages.PeerSettings.parse_peerSettings($0) } + dict[2094438528] = { return Api.messages.QuickReplies.parse_quickReplies($0) } + dict[1603398491] = { return Api.messages.QuickReplies.parse_quickRepliesNotModified($0) } + dict[-1810973582] = { return Api.messages.QuickReply.parse_quickReply($0) } dict[-352454890] = { return Api.messages.Reactions.parse_reactions($0) } dict[-1334846497] = { return Api.messages.Reactions.parse_reactionsNotModified($0) } dict[-1999405994] = { return Api.messages.RecentStickers.parse_recentStickers($0) } @@ -1222,6 +1240,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-2030542532] = { return Api.premium.BoostsList.parse_boostsList($0) } dict[1230586490] = { return Api.premium.BoostsStatus.parse_boostsStatus($0) } dict[-1696454430] = { return Api.premium.MyBoosts.parse_myBoosts($0) } + dict[-594852657] = { return Api.smsjobs.EligibilityToJoin.parse_eligibleToJoin($0) } + dict[720277905] = { return Api.smsjobs.Status.parse_status($0) } dict[963421692] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) } dict[-276825834] = { return Api.stats.MegagroupStats.parse_megagroupStats($0) } dict[2145983508] = { return Api.stats.MessageStats.parse_messageStats($0) } @@ -1276,7 +1296,7 @@ public extension Api { return parser(reader) } else { - telegramApiLog("Type constructor \(String(signature, radix: 16, uppercase: false)) not found") + telegramApiLog("Type constructor \(String(UInt32(bitPattern: signature), radix: 16, uppercase: false)) not found") return nil } } @@ -1366,6 +1386,12 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.BotMenuButton: _1.serialize(buffer, boxed) + case let _1 as Api.BusinessLocation: + _1.serialize(buffer, boxed) + case let _1 as Api.BusinessWeeklyOpen: + _1.serialize(buffer, boxed) + case let _1 as Api.BusinessWorkHours: + _1.serialize(buffer, boxed) case let _1 as Api.CdnConfig: _1.serialize(buffer, boxed) case let _1 as Api.CdnPublicKey: @@ -1798,6 +1824,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.SimpleWebViewResult: _1.serialize(buffer, boxed) + case let _1 as Api.SmsJob: + _1.serialize(buffer, boxed) case let _1 as Api.SponsoredMessage: _1.serialize(buffer, boxed) case let _1 as Api.SponsoredWebPage: @@ -1844,6 +1872,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.ThemeSettings: _1.serialize(buffer, boxed) + case let _1 as Api.Timezone: + _1.serialize(buffer, boxed) case let _1 as Api.TopPeer: _1.serialize(buffer, boxed) case let _1 as Api.TopPeerCategory: @@ -2006,6 +2036,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.help.TermsOfServiceUpdate: _1.serialize(buffer, boxed) + case let _1 as Api.help.TimezonesList: + _1.serialize(buffer, boxed) case let _1 as Api.help.UserInfo: _1.serialize(buffer, boxed) case let _1 as Api.messages.AffectedFoundMessages: @@ -2076,6 +2108,10 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.messages.PeerSettings: _1.serialize(buffer, boxed) + case let _1 as Api.messages.QuickReplies: + _1.serialize(buffer, boxed) + case let _1 as Api.messages.QuickReply: + _1.serialize(buffer, boxed) case let _1 as Api.messages.Reactions: _1.serialize(buffer, boxed) case let _1 as Api.messages.RecentStickers: @@ -2152,6 +2188,10 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.premium.MyBoosts: _1.serialize(buffer, boxed) + case let _1 as Api.smsjobs.EligibilityToJoin: + _1.serialize(buffer, boxed) + case let _1 as Api.smsjobs.Status: + _1.serialize(buffer, boxed) case let _1 as Api.stats.BroadcastStats: _1.serialize(buffer, boxed) case let _1 as Api.stats.MegagroupStats: diff --git a/submodules/TelegramApi/Sources/Api12.swift b/submodules/TelegramApi/Sources/Api12.swift index f63228f098..a4134abcf7 100644 --- a/submodules/TelegramApi/Sources/Api12.swift +++ b/submodules/TelegramApi/Sources/Api12.swift @@ -424,15 +424,15 @@ public extension Api { } public extension Api { indirect enum Message: TypeConstructorDescription { - case message(flags: Int32, id: Int32, fromId: Api.Peer?, fromBoostsApplied: Int32?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?) + case message(flags: Int32, id: Int32, fromId: Api.Peer?, fromBoostsApplied: Int32?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?, quickReplyShortcutId: Int32?) case messageEmpty(flags: Int32, id: Int32, peerId: Api.Peer?) case messageService(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, replyTo: Api.MessageReplyHeader?, date: Int32, action: Api.MessageAction, ttlPeriod: Int32?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .message(let flags, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod): + case .message(let flags, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId): if boxed { - buffer.appendInt32(508332649) + buffer.appendInt32(-1502839044) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false) @@ -465,6 +465,7 @@ public extension Api { item.serialize(buffer, true) }} if Int(flags) & Int(1 << 25) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 30) != 0 {serializeInt32(quickReplyShortcutId!, buffer: buffer, boxed: false)} break case .messageEmpty(let flags, let id, let peerId): if boxed { @@ -492,8 +493,8 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .message(let flags, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod): - return ("message", [("flags", flags as Any), ("id", id as Any), ("fromId", fromId as Any), ("fromBoostsApplied", fromBoostsApplied as Any), ("peerId", peerId as Any), ("savedPeerId", savedPeerId as Any), ("fwdFrom", fwdFrom as Any), ("viaBotId", viaBotId as Any), ("replyTo", replyTo as Any), ("date", date as Any), ("message", message as Any), ("media", media as Any), ("replyMarkup", replyMarkup as Any), ("entities", entities as Any), ("views", views as Any), ("forwards", forwards as Any), ("replies", replies as Any), ("editDate", editDate as Any), ("postAuthor", postAuthor as Any), ("groupedId", groupedId as Any), ("reactions", reactions as Any), ("restrictionReason", restrictionReason as Any), ("ttlPeriod", ttlPeriod as Any)]) + case .message(let flags, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId): + return ("message", [("flags", flags as Any), ("id", id as Any), ("fromId", fromId as Any), ("fromBoostsApplied", fromBoostsApplied as Any), ("peerId", peerId as Any), ("savedPeerId", savedPeerId as Any), ("fwdFrom", fwdFrom as Any), ("viaBotId", viaBotId as Any), ("replyTo", replyTo as Any), ("date", date as Any), ("message", message as Any), ("media", media as Any), ("replyMarkup", replyMarkup as Any), ("entities", entities as Any), ("views", views as Any), ("forwards", forwards as Any), ("replies", replies as Any), ("editDate", editDate as Any), ("postAuthor", postAuthor as Any), ("groupedId", groupedId as Any), ("reactions", reactions as Any), ("restrictionReason", restrictionReason as Any), ("ttlPeriod", ttlPeriod as Any), ("quickReplyShortcutId", quickReplyShortcutId as Any)]) case .messageEmpty(let flags, let id, let peerId): return ("messageEmpty", [("flags", flags as Any), ("id", id as Any), ("peerId", peerId as Any)]) case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action, let ttlPeriod): @@ -570,6 +571,8 @@ public extension Api { } } var _23: Int32? if Int(_1!) & Int(1 << 25) != 0 {_23 = reader.readInt32() } + var _24: Int32? + if Int(_1!) & Int(1 << 30) != 0 {_24 = reader.readInt32() } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = (Int(_1!) & Int(1 << 8) == 0) || _3 != nil @@ -593,8 +596,9 @@ public extension Api { let _c21 = (Int(_1!) & Int(1 << 20) == 0) || _21 != nil let _c22 = (Int(_1!) & Int(1 << 22) == 0) || _22 != nil let _c23 = (Int(_1!) & Int(1 << 25) == 0) || _23 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 { - return Api.Message.message(flags: _1!, id: _2!, fromId: _3, fromBoostsApplied: _4, peerId: _5!, savedPeerId: _6, fwdFrom: _7, viaBotId: _8, replyTo: _9, date: _10!, message: _11!, media: _12, replyMarkup: _13, entities: _14, views: _15, forwards: _16, replies: _17, editDate: _18, postAuthor: _19, groupedId: _20, reactions: _21, restrictionReason: _22, ttlPeriod: _23) + let _c24 = (Int(_1!) & Int(1 << 30) == 0) || _24 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 { + return Api.Message.message(flags: _1!, id: _2!, fromId: _3, fromBoostsApplied: _4, peerId: _5!, savedPeerId: _6, fwdFrom: _7, viaBotId: _8, replyTo: _9, date: _10!, message: _11!, media: _12, replyMarkup: _13, entities: _14, views: _15, forwards: _16, replies: _17, editDate: _18, postAuthor: _19, groupedId: _20, reactions: _21, restrictionReason: _22, ttlPeriod: _23, quickReplyShortcutId: _24) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 5f696bd03a..4427b1efe7 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -588,6 +588,138 @@ public extension Api { } } +public extension Api { + enum BusinessLocation: TypeConstructorDescription { + case businessLocation(geoPoint: Api.GeoPoint, address: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .businessLocation(let geoPoint, let address): + if boxed { + buffer.appendInt32(-1104414653) + } + geoPoint.serialize(buffer, true) + serializeString(address, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .businessLocation(let geoPoint, let address): + return ("businessLocation", [("geoPoint", geoPoint as Any), ("address", address as Any)]) + } + } + + public static func parse_businessLocation(_ reader: BufferReader) -> BusinessLocation? { + var _1: Api.GeoPoint? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.GeoPoint + } + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.BusinessLocation.businessLocation(geoPoint: _1!, address: _2!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum BusinessWeeklyOpen: TypeConstructorDescription { + case businessWeeklyOpen(startMinute: Int32, endMinute: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .businessWeeklyOpen(let startMinute, let endMinute): + if boxed { + buffer.appendInt32(302717625) + } + serializeInt32(startMinute, buffer: buffer, boxed: false) + serializeInt32(endMinute, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .businessWeeklyOpen(let startMinute, let endMinute): + return ("businessWeeklyOpen", [("startMinute", startMinute as Any), ("endMinute", endMinute as Any)]) + } + } + + public static func parse_businessWeeklyOpen(_ reader: BufferReader) -> BusinessWeeklyOpen? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.BusinessWeeklyOpen.businessWeeklyOpen(startMinute: _1!, endMinute: _2!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum BusinessWorkHours: TypeConstructorDescription { + case businessWorkHours(flags: Int32, timezoneId: String, weeklyOpen: [Api.BusinessWeeklyOpen]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .businessWorkHours(let flags, let timezoneId, let weeklyOpen): + if boxed { + buffer.appendInt32(-1936543592) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(timezoneId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(weeklyOpen.count)) + for item in weeklyOpen { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .businessWorkHours(let flags, let timezoneId, let weeklyOpen): + return ("businessWorkHours", [("flags", flags as Any), ("timezoneId", timezoneId as Any), ("weeklyOpen", weeklyOpen as Any)]) + } + } + + public static func parse_businessWorkHours(_ reader: BufferReader) -> BusinessWorkHours? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.BusinessWeeklyOpen]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BusinessWeeklyOpen.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.BusinessWorkHours.businessWorkHours(flags: _1!, timezoneId: _2!, weeklyOpen: _3!) + } + else { + return nil + } + } + + } +} public extension Api { enum CdnConfig: TypeConstructorDescription { case cdnConfig(publicKeys: [Api.CdnPublicKey]) diff --git a/submodules/TelegramApi/Sources/Api21.swift b/submodules/TelegramApi/Sources/Api21.swift index 174f9c3cb7..c09e5c1ee6 100644 --- a/submodules/TelegramApi/Sources/Api21.swift +++ b/submodules/TelegramApi/Sources/Api21.swift @@ -84,6 +84,50 @@ public extension Api { } } +public extension Api { + enum SmsJob: TypeConstructorDescription { + case smsJob(jobId: String, phoneNumber: String, text: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .smsJob(let jobId, let phoneNumber, let text): + if boxed { + buffer.appendInt32(-425595208) + } + serializeString(jobId, buffer: buffer, boxed: false) + serializeString(phoneNumber, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .smsJob(let jobId, let phoneNumber, let text): + return ("smsJob", [("jobId", jobId as Any), ("phoneNumber", phoneNumber as Any), ("text", text as Any)]) + } + } + + public static func parse_smsJob(_ reader: BufferReader) -> SmsJob? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SmsJob.smsJob(jobId: _1!, phoneNumber: _2!, text: _3!) + } + else { + return nil + } + } + + } +} public extension Api { indirect enum SponsoredMessage: TypeConstructorDescription { case sponsoredMessage(flags: Int32, randomId: Buffer, fromId: Api.Peer?, chatInvite: Api.ChatInvite?, chatInviteHash: String?, channelPost: Int32?, startParam: String?, webpage: Api.SponsoredWebPage?, app: Api.BotApp?, message: String, entities: [Api.MessageEntity]?, buttonText: String?, sponsorInfo: String?, additionalInfo: String?) diff --git a/submodules/TelegramApi/Sources/Api22.swift b/submodules/TelegramApi/Sources/Api22.swift index 3d1854bcb3..b4715fe70e 100644 --- a/submodules/TelegramApi/Sources/Api22.swift +++ b/submodules/TelegramApi/Sources/Api22.swift @@ -254,6 +254,50 @@ public extension Api { } } +public extension Api { + enum Timezone: TypeConstructorDescription { + case timezone(id: String, name: String, utcOffset: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .timezone(let id, let name, let utcOffset): + if boxed { + buffer.appendInt32(-7173643) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(name, buffer: buffer, boxed: false) + serializeInt32(utcOffset, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .timezone(let id, let name, let utcOffset): + return ("timezone", [("id", id as Any), ("name", name as Any), ("utcOffset", utcOffset as Any)]) + } + } + + public static func parse_timezone(_ reader: BufferReader) -> Timezone? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Timezone.timezone(id: _1!, name: _2!, utcOffset: _3!) + } + else { + return nil + } + } + + } +} public extension Api { enum TopPeer: TypeConstructorDescription { case topPeer(peer: Api.Peer, rating: Double) @@ -503,6 +547,8 @@ public extension Api { case updateDcOptions(dcOptions: [Api.DcOption]) case updateDeleteChannelMessages(channelId: Int64, messages: [Int32], pts: Int32, ptsCount: Int32) case updateDeleteMessages(messages: [Int32], pts: Int32, ptsCount: Int32) + case updateDeleteQuickReply(shortcutId: Int32) + case updateDeleteQuickReplyMessages(shortcutId: Int32, messages: [Int32]) case updateDeleteScheduledMessages(peer: Api.Peer, messages: [Int32]) case updateDialogFilter(flags: Int32, id: Int32, filter: Api.DialogFilter?) case updateDialogFilterOrder(order: [Int32]) @@ -536,6 +582,7 @@ public extension Api { case updateNewChannelMessage(message: Api.Message, pts: Int32, ptsCount: Int32) case updateNewEncryptedMessage(message: Api.EncryptedMessage, qts: Int32) case updateNewMessage(message: Api.Message, pts: Int32, ptsCount: Int32) + case updateNewQuickReply(quickReply: Api.messages.QuickReply) case updateNewScheduledMessage(message: Api.Message) case updateNewStickerSet(stickerset: Api.messages.StickerSet) case updateNotifySettings(peer: Api.NotifyPeer, notifySettings: Api.PeerNotifySettings) @@ -553,6 +600,8 @@ public extension Api { case updatePinnedSavedDialogs(flags: Int32, order: [Api.DialogPeer]?) case updatePrivacy(key: Api.PrivacyKey, rules: [Api.PrivacyRule]) case updatePtsChanged + case updateQuickReplies(quickReplies: [Api.messages.QuickReply]) + case updateQuickReplyMessage(message: Api.Message) case updateReadChannelDiscussionInbox(flags: Int32, channelId: Int64, topMsgId: Int32, readMaxId: Int32, broadcastId: Int64?, broadcastPost: Int32?) case updateReadChannelDiscussionOutbox(channelId: Int64, topMsgId: Int32, readMaxId: Int32) case updateReadChannelInbox(flags: Int32, folderId: Int32?, channelId: Int64, maxId: Int32, stillUnreadCount: Int32, pts: Int32) @@ -572,6 +621,7 @@ public extension Api { case updateSavedRingtones case updateSentStoryReaction(peer: Api.Peer, storyId: Int32, reaction: Api.Reaction) case updateServiceNotification(flags: Int32, inboxDate: Int32?, type: String, message: String, media: Api.MessageMedia, entities: [Api.MessageEntity]) + case updateSmsJob(jobId: String) case updateStickerSets(flags: Int32) case updateStickerSetsOrder(flags: Int32, order: [Int64]) case updateStoriesStealthMode(stealthMode: Api.StoriesStealthMode) @@ -981,6 +1031,23 @@ public extension Api { serializeInt32(pts, buffer: buffer, boxed: false) serializeInt32(ptsCount, buffer: buffer, boxed: false) break + case .updateDeleteQuickReply(let shortcutId): + if boxed { + buffer.appendInt32(1407644140) + } + serializeInt32(shortcutId, buffer: buffer, boxed: false) + break + case .updateDeleteQuickReplyMessages(let shortcutId, let messages): + if boxed { + buffer.appendInt32(1450174413) + } + serializeInt32(shortcutId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + serializeInt32(item, buffer: buffer, boxed: false) + } + break case .updateDeleteScheduledMessages(let peer, let messages): if boxed { buffer.appendInt32(-1870238482) @@ -1251,6 +1318,12 @@ public extension Api { serializeInt32(pts, buffer: buffer, boxed: false) serializeInt32(ptsCount, buffer: buffer, boxed: false) break + case .updateNewQuickReply(let quickReply): + if boxed { + buffer.appendInt32(-1386034803) + } + quickReply.serialize(buffer, true) + break case .updateNewScheduledMessage(let message): if boxed { buffer.appendInt32(967122427) @@ -1402,6 +1475,22 @@ public extension Api { buffer.appendInt32(861169551) } + break + case .updateQuickReplies(let quickReplies): + if boxed { + buffer.appendInt32(230929261) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(quickReplies.count)) + for item in quickReplies { + item.serialize(buffer, true) + } + break + case .updateQuickReplyMessage(let message): + if boxed { + buffer.appendInt32(1040518415) + } + message.serialize(buffer, true) break case .updateReadChannelDiscussionInbox(let flags, let channelId, let topMsgId, let readMaxId, let broadcastId, let broadcastPost): if boxed { @@ -1560,6 +1649,12 @@ public extension Api { item.serialize(buffer, true) } break + case .updateSmsJob(let jobId): + if boxed { + buffer.appendInt32(-245208620) + } + serializeString(jobId, buffer: buffer, boxed: false) + break case .updateStickerSets(let flags): if boxed { buffer.appendInt32(834816008) @@ -1761,6 +1856,10 @@ public extension Api { return ("updateDeleteChannelMessages", [("channelId", channelId as Any), ("messages", messages as Any), ("pts", pts as Any), ("ptsCount", ptsCount as Any)]) case .updateDeleteMessages(let messages, let pts, let ptsCount): return ("updateDeleteMessages", [("messages", messages as Any), ("pts", pts as Any), ("ptsCount", ptsCount as Any)]) + case .updateDeleteQuickReply(let shortcutId): + return ("updateDeleteQuickReply", [("shortcutId", shortcutId as Any)]) + case .updateDeleteQuickReplyMessages(let shortcutId, let messages): + return ("updateDeleteQuickReplyMessages", [("shortcutId", shortcutId as Any), ("messages", messages as Any)]) case .updateDeleteScheduledMessages(let peer, let messages): return ("updateDeleteScheduledMessages", [("peer", peer as Any), ("messages", messages as Any)]) case .updateDialogFilter(let flags, let id, let filter): @@ -1827,6 +1926,8 @@ public extension Api { return ("updateNewEncryptedMessage", [("message", message as Any), ("qts", qts as Any)]) case .updateNewMessage(let message, let pts, let ptsCount): return ("updateNewMessage", [("message", message as Any), ("pts", pts as Any), ("ptsCount", ptsCount as Any)]) + case .updateNewQuickReply(let quickReply): + return ("updateNewQuickReply", [("quickReply", quickReply as Any)]) case .updateNewScheduledMessage(let message): return ("updateNewScheduledMessage", [("message", message as Any)]) case .updateNewStickerSet(let stickerset): @@ -1861,6 +1962,10 @@ public extension Api { return ("updatePrivacy", [("key", key as Any), ("rules", rules as Any)]) case .updatePtsChanged: return ("updatePtsChanged", []) + case .updateQuickReplies(let quickReplies): + return ("updateQuickReplies", [("quickReplies", quickReplies as Any)]) + case .updateQuickReplyMessage(let message): + return ("updateQuickReplyMessage", [("message", message as Any)]) case .updateReadChannelDiscussionInbox(let flags, let channelId, let topMsgId, let readMaxId, let broadcastId, let broadcastPost): return ("updateReadChannelDiscussionInbox", [("flags", flags as Any), ("channelId", channelId as Any), ("topMsgId", topMsgId as Any), ("readMaxId", readMaxId as Any), ("broadcastId", broadcastId as Any), ("broadcastPost", broadcastPost as Any)]) case .updateReadChannelDiscussionOutbox(let channelId, let topMsgId, let readMaxId): @@ -1899,6 +2004,8 @@ public extension Api { return ("updateSentStoryReaction", [("peer", peer as Any), ("storyId", storyId as Any), ("reaction", reaction as Any)]) case .updateServiceNotification(let flags, let inboxDate, let type, let message, let media, let entities): return ("updateServiceNotification", [("flags", flags as Any), ("inboxDate", inboxDate as Any), ("type", type as Any), ("message", message as Any), ("media", media as Any), ("entities", entities as Any)]) + case .updateSmsJob(let jobId): + return ("updateSmsJob", [("jobId", jobId as Any)]) case .updateStickerSets(let flags): return ("updateStickerSets", [("flags", flags as Any)]) case .updateStickerSetsOrder(let flags, let order): @@ -2766,6 +2873,33 @@ public extension Api { return nil } } + public static func parse_updateDeleteQuickReply(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateDeleteQuickReply(shortcutId: _1!) + } + else { + return nil + } + } + public static func parse_updateDeleteQuickReplyMessages(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Int32]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateDeleteQuickReplyMessages(shortcutId: _1!, messages: _2!) + } + else { + return nil + } + } public static func parse_updateDeleteScheduledMessages(_ reader: BufferReader) -> Update? { var _1: Api.Peer? if let signature = reader.readInt32() { @@ -3321,6 +3455,19 @@ public extension Api { return nil } } + public static func parse_updateNewQuickReply(_ reader: BufferReader) -> Update? { + var _1: Api.messages.QuickReply? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.messages.QuickReply + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateNewQuickReply(quickReply: _1!) + } + else { + return nil + } + } public static func parse_updateNewScheduledMessage(_ reader: BufferReader) -> Update? { var _1: Api.Message? if let signature = reader.readInt32() { @@ -3608,6 +3755,32 @@ public extension Api { public static func parse_updatePtsChanged(_ reader: BufferReader) -> Update? { return Api.Update.updatePtsChanged } + public static func parse_updateQuickReplies(_ reader: BufferReader) -> Update? { + var _1: [Api.messages.QuickReply]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.messages.QuickReply.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateQuickReplies(quickReplies: _1!) + } + else { + return nil + } + } + public static func parse_updateQuickReplyMessage(_ reader: BufferReader) -> Update? { + var _1: Api.Message? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.Message + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateQuickReplyMessage(message: _1!) + } + else { + return nil + } + } public static func parse_updateReadChannelDiscussionInbox(_ reader: BufferReader) -> Update? { var _1: Int32? _1 = reader.readInt32() @@ -3876,6 +4049,17 @@ public extension Api { return nil } } + public static func parse_updateSmsJob(_ reader: BufferReader) -> Update? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateSmsJob(jobId: _1!) + } + else { + return nil + } + } public static func parse_updateStickerSets(_ reader: BufferReader) -> Update? { var _1: Int32? _1 = reader.readInt32() diff --git a/submodules/TelegramApi/Sources/Api23.swift b/submodules/TelegramApi/Sources/Api23.swift index 2d684d02d3..320cf74bfb 100644 --- a/submodules/TelegramApi/Sources/Api23.swift +++ b/submodules/TelegramApi/Sources/Api23.swift @@ -602,15 +602,16 @@ public extension Api { } public extension Api { enum UserFull: TypeConstructorDescription { - case userFull(flags: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, themeEmoticon: String?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, premiumGifts: [Api.PremiumGiftOption]?, wallpaper: Api.WallPaper?, stories: Api.PeerStories?) + case userFull(flags: Int32, flags2: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, themeEmoticon: String?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, premiumGifts: [Api.PremiumGiftOption]?, wallpaper: Api.WallPaper?, stories: Api.PeerStories?, businessWorkHours: Api.BusinessWorkHours?, businessLocation: Api.BusinessLocation?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .userFull(let flags, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let premiumGifts, let wallpaper, let stories): + case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let premiumGifts, let wallpaper, let stories, let businessWorkHours, let businessLocation): if boxed { - buffer.appendInt32(-1179571092) + buffer.appendInt32(-501688336) } serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(flags2, buffer: buffer, boxed: false) serializeInt64(id, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 1) != 0 {serializeString(about!, buffer: buffer, boxed: false)} settings.serialize(buffer, true) @@ -634,102 +635,117 @@ public extension Api { }} if Int(flags) & Int(1 << 24) != 0 {wallpaper!.serialize(buffer, true)} if Int(flags) & Int(1 << 25) != 0 {stories!.serialize(buffer, true)} + if Int(flags2) & Int(1 << 0) != 0 {businessWorkHours!.serialize(buffer, true)} + if Int(flags2) & Int(1 << 1) != 0 {businessLocation!.serialize(buffer, true)} break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .userFull(let flags, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let premiumGifts, let wallpaper, let stories): - return ("userFull", [("flags", flags as Any), ("id", id as Any), ("about", about as Any), ("settings", settings as Any), ("personalPhoto", personalPhoto as Any), ("profilePhoto", profilePhoto as Any), ("fallbackPhoto", fallbackPhoto as Any), ("notifySettings", notifySettings as Any), ("botInfo", botInfo as Any), ("pinnedMsgId", pinnedMsgId as Any), ("commonChatsCount", commonChatsCount as Any), ("folderId", folderId as Any), ("ttlPeriod", ttlPeriod as Any), ("themeEmoticon", themeEmoticon as Any), ("privateForwardName", privateForwardName as Any), ("botGroupAdminRights", botGroupAdminRights as Any), ("botBroadcastAdminRights", botBroadcastAdminRights as Any), ("premiumGifts", premiumGifts as Any), ("wallpaper", wallpaper as Any), ("stories", stories as Any)]) + case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let premiumGifts, let wallpaper, let stories, let businessWorkHours, let businessLocation): + return ("userFull", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("about", about as Any), ("settings", settings as Any), ("personalPhoto", personalPhoto as Any), ("profilePhoto", profilePhoto as Any), ("fallbackPhoto", fallbackPhoto as Any), ("notifySettings", notifySettings as Any), ("botInfo", botInfo as Any), ("pinnedMsgId", pinnedMsgId as Any), ("commonChatsCount", commonChatsCount as Any), ("folderId", folderId as Any), ("ttlPeriod", ttlPeriod as Any), ("themeEmoticon", themeEmoticon as Any), ("privateForwardName", privateForwardName as Any), ("botGroupAdminRights", botGroupAdminRights as Any), ("botBroadcastAdminRights", botBroadcastAdminRights as Any), ("premiumGifts", premiumGifts as Any), ("wallpaper", wallpaper as Any), ("stories", stories as Any), ("businessWorkHours", businessWorkHours as Any), ("businessLocation", businessLocation as Any)]) } } public static func parse_userFull(_ reader: BufferReader) -> UserFull? { var _1: Int32? _1 = reader.readInt32() - var _2: Int64? - _2 = reader.readInt64() - var _3: String? - if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } - var _4: Api.PeerSettings? + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + _3 = reader.readInt64() + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: Api.PeerSettings? if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.PeerSettings + _5 = Api.parse(reader, signature: signature) as? Api.PeerSettings } - var _5: Api.Photo? - if Int(_1!) & Int(1 << 21) != 0 {if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.Photo - } } var _6: Api.Photo? - if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { + if Int(_1!) & Int(1 << 21) != 0 {if let signature = reader.readInt32() { _6 = Api.parse(reader, signature: signature) as? Api.Photo } } var _7: Api.Photo? - if Int(_1!) & Int(1 << 22) != 0 {if let signature = reader.readInt32() { + if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { _7 = Api.parse(reader, signature: signature) as? Api.Photo } } - var _8: Api.PeerNotifySettings? + var _8: Api.Photo? + if Int(_1!) & Int(1 << 22) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _9: Api.PeerNotifySettings? if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings + _9 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings } - var _9: Api.BotInfo? + var _10: Api.BotInfo? if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { - _9 = Api.parse(reader, signature: signature) as? Api.BotInfo + _10 = Api.parse(reader, signature: signature) as? Api.BotInfo } } - var _10: Int32? - if Int(_1!) & Int(1 << 6) != 0 {_10 = reader.readInt32() } var _11: Int32? - _11 = reader.readInt32() + if Int(_1!) & Int(1 << 6) != 0 {_11 = reader.readInt32() } var _12: Int32? - if Int(_1!) & Int(1 << 11) != 0 {_12 = reader.readInt32() } + _12 = reader.readInt32() var _13: Int32? - if Int(_1!) & Int(1 << 14) != 0 {_13 = reader.readInt32() } - var _14: String? - if Int(_1!) & Int(1 << 15) != 0 {_14 = parseString(reader) } + if Int(_1!) & Int(1 << 11) != 0 {_13 = reader.readInt32() } + var _14: Int32? + if Int(_1!) & Int(1 << 14) != 0 {_14 = reader.readInt32() } var _15: String? - if Int(_1!) & Int(1 << 16) != 0 {_15 = parseString(reader) } - var _16: Api.ChatAdminRights? - if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() { - _16 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights - } } + if Int(_1!) & Int(1 << 15) != 0 {_15 = parseString(reader) } + var _16: String? + if Int(_1!) & Int(1 << 16) != 0 {_16 = parseString(reader) } var _17: Api.ChatAdminRights? - if Int(_1!) & Int(1 << 18) != 0 {if let signature = reader.readInt32() { + if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() { _17 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights } } - var _18: [Api.PremiumGiftOption]? + var _18: Api.ChatAdminRights? + if Int(_1!) & Int(1 << 18) != 0 {if let signature = reader.readInt32() { + _18 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights + } } + var _19: [Api.PremiumGiftOption]? if Int(_1!) & Int(1 << 19) != 0 {if let _ = reader.readInt32() { - _18 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PremiumGiftOption.self) + _19 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PremiumGiftOption.self) } } - var _19: Api.WallPaper? + var _20: Api.WallPaper? if Int(_1!) & Int(1 << 24) != 0 {if let signature = reader.readInt32() { - _19 = Api.parse(reader, signature: signature) as? Api.WallPaper + _20 = Api.parse(reader, signature: signature) as? Api.WallPaper } } - var _20: Api.PeerStories? + var _21: Api.PeerStories? if Int(_1!) & Int(1 << 25) != 0 {if let signature = reader.readInt32() { - _20 = Api.parse(reader, signature: signature) as? Api.PeerStories + _21 = Api.parse(reader, signature: signature) as? Api.PeerStories + } } + var _22: Api.BusinessWorkHours? + if Int(_2!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _22 = Api.parse(reader, signature: signature) as? Api.BusinessWorkHours + } } + var _23: Api.BusinessLocation? + if Int(_2!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _23 = Api.parse(reader, signature: signature) as? Api.BusinessLocation } } let _c1 = _1 != nil let _c2 = _2 != nil - let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil - let _c4 = _4 != nil - let _c5 = (Int(_1!) & Int(1 << 21) == 0) || _5 != nil - let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil - let _c7 = (Int(_1!) & Int(1 << 22) == 0) || _7 != nil - let _c8 = _8 != nil - let _c9 = (Int(_1!) & Int(1 << 3) == 0) || _9 != nil - let _c10 = (Int(_1!) & Int(1 << 6) == 0) || _10 != nil - let _c11 = _11 != nil - let _c12 = (Int(_1!) & Int(1 << 11) == 0) || _12 != nil - let _c13 = (Int(_1!) & Int(1 << 14) == 0) || _13 != nil - let _c14 = (Int(_1!) & Int(1 << 15) == 0) || _14 != nil - let _c15 = (Int(_1!) & Int(1 << 16) == 0) || _15 != nil - let _c16 = (Int(_1!) & Int(1 << 17) == 0) || _16 != nil - let _c17 = (Int(_1!) & Int(1 << 18) == 0) || _17 != nil - let _c18 = (Int(_1!) & Int(1 << 19) == 0) || _18 != nil - let _c19 = (Int(_1!) & Int(1 << 24) == 0) || _19 != nil - let _c20 = (Int(_1!) & Int(1 << 25) == 0) || _20 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 { - return Api.UserFull.userFull(flags: _1!, id: _2!, about: _3, settings: _4!, personalPhoto: _5, profilePhoto: _6, fallbackPhoto: _7, notifySettings: _8!, botInfo: _9, pinnedMsgId: _10, commonChatsCount: _11!, folderId: _12, ttlPeriod: _13, themeEmoticon: _14, privateForwardName: _15, botGroupAdminRights: _16, botBroadcastAdminRights: _17, premiumGifts: _18, wallpaper: _19, stories: _20) + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 21) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 22) == 0) || _8 != nil + let _c9 = _9 != nil + let _c10 = (Int(_1!) & Int(1 << 3) == 0) || _10 != nil + let _c11 = (Int(_1!) & Int(1 << 6) == 0) || _11 != nil + let _c12 = _12 != nil + let _c13 = (Int(_1!) & Int(1 << 11) == 0) || _13 != nil + let _c14 = (Int(_1!) & Int(1 << 14) == 0) || _14 != nil + let _c15 = (Int(_1!) & Int(1 << 15) == 0) || _15 != nil + let _c16 = (Int(_1!) & Int(1 << 16) == 0) || _16 != nil + let _c17 = (Int(_1!) & Int(1 << 17) == 0) || _17 != nil + let _c18 = (Int(_1!) & Int(1 << 18) == 0) || _18 != nil + let _c19 = (Int(_1!) & Int(1 << 19) == 0) || _19 != nil + let _c20 = (Int(_1!) & Int(1 << 24) == 0) || _20 != nil + let _c21 = (Int(_1!) & Int(1 << 25) == 0) || _21 != nil + let _c22 = (Int(_2!) & Int(1 << 0) == 0) || _22 != nil + let _c23 = (Int(_2!) & Int(1 << 1) == 0) || _23 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 { + return Api.UserFull.userFull(flags: _1!, flags2: _2!, id: _3!, about: _4, settings: _5!, personalPhoto: _6, profilePhoto: _7, fallbackPhoto: _8, notifySettings: _9!, botInfo: _10, pinnedMsgId: _11, commonChatsCount: _12!, folderId: _13, ttlPeriod: _14, themeEmoticon: _15, privateForwardName: _16, botGroupAdminRights: _17, botBroadcastAdminRights: _18, premiumGifts: _19, wallpaper: _20, stories: _21, businessWorkHours: _22, businessLocation: _23) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index 90373cb39c..aba59a202f 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -354,6 +354,64 @@ public extension Api.help { } } +public extension Api.help { + enum TimezonesList: TypeConstructorDescription { + case timezonesList(timezones: [Api.Timezone], hash: Int32) + case timezonesListNotModified + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .timezonesList(let timezones, let hash): + if boxed { + buffer.appendInt32(2071260529) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(timezones.count)) + for item in timezones { + item.serialize(buffer, true) + } + serializeInt32(hash, buffer: buffer, boxed: false) + break + case .timezonesListNotModified: + if boxed { + buffer.appendInt32(-1761146676) + } + + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .timezonesList(let timezones, let hash): + return ("timezonesList", [("timezones", timezones as Any), ("hash", hash as Any)]) + case .timezonesListNotModified: + return ("timezonesListNotModified", []) + } + } + + public static func parse_timezonesList(_ reader: BufferReader) -> TimezonesList? { + var _1: [Api.Timezone]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Timezone.self) + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.help.TimezonesList.timezonesList(timezones: _1!, hash: _2!) + } + else { + return nil + } + } + public static func parse_timezonesListNotModified(_ reader: BufferReader) -> TimezonesList? { + return Api.help.TimezonesList.timezonesListNotModified + } + + } +} public extension Api.help { enum UserInfo: TypeConstructorDescription { case userInfo(message: String, entities: [Api.MessageEntity], author: String, date: Int32) diff --git a/submodules/TelegramApi/Sources/Api28.swift b/submodules/TelegramApi/Sources/Api28.swift index 639e18a7b2..4b1dfe924a 100644 --- a/submodules/TelegramApi/Sources/Api28.swift +++ b/submodules/TelegramApi/Sources/Api28.swift @@ -1288,6 +1288,138 @@ public extension Api.messages { } } +public extension Api.messages { + enum QuickReplies: TypeConstructorDescription { + case quickReplies(quickReplies: [Api.messages.QuickReply], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + case quickRepliesNotModified + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .quickReplies(let quickReplies, let messages, let chats, let users): + if boxed { + buffer.appendInt32(2094438528) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(quickReplies.count)) + for item in quickReplies { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .quickRepliesNotModified: + if boxed { + buffer.appendInt32(1603398491) + } + + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .quickReplies(let quickReplies, let messages, let chats, let users): + return ("quickReplies", [("quickReplies", quickReplies as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)]) + case .quickRepliesNotModified: + return ("quickRepliesNotModified", []) + } + } + + public static func parse_quickReplies(_ reader: BufferReader) -> QuickReplies? { + var _1: [Api.messages.QuickReply]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.messages.QuickReply.self) + } + var _2: [Api.Message]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: [Api.User]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.QuickReplies.quickReplies(quickReplies: _1!, messages: _2!, chats: _3!, users: _4!) + } + else { + return nil + } + } + public static func parse_quickRepliesNotModified(_ reader: BufferReader) -> QuickReplies? { + return Api.messages.QuickReplies.quickRepliesNotModified + } + + } +} +public extension Api.messages { + enum QuickReply: TypeConstructorDescription { + case quickReply(shortcutId: Int32, shortcut: String, topMessage: Int32, count: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .quickReply(let shortcutId, let shortcut, let topMessage, let count): + if boxed { + buffer.appendInt32(-1810973582) + } + serializeInt32(shortcutId, buffer: buffer, boxed: false) + serializeString(shortcut, buffer: buffer, boxed: false) + serializeInt32(topMessage, buffer: buffer, boxed: false) + serializeInt32(count, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .quickReply(let shortcutId, let shortcut, let topMessage, let count): + return ("quickReply", [("shortcutId", shortcutId as Any), ("shortcut", shortcut as Any), ("topMessage", topMessage as Any), ("count", count as Any)]) + } + } + + public static func parse_quickReply(_ reader: BufferReader) -> QuickReply? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.QuickReply.quickReply(shortcutId: _1!, shortcut: _2!, topMessage: _3!, count: _4!) + } + else { + return nil + } + } + + } +} public extension Api.messages { enum Reactions: TypeConstructorDescription { case reactions(hash: Int64, reactions: [Api.Reaction]) @@ -1424,155 +1556,3 @@ public extension Api.messages { } } -public extension Api.messages { - enum SavedDialogs: TypeConstructorDescription { - case savedDialogs(dialogs: [Api.SavedDialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) - case savedDialogsNotModified(count: Int32) - case savedDialogsSlice(count: Int32, dialogs: [Api.SavedDialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .savedDialogs(let dialogs, let messages, let chats, let users): - if boxed { - buffer.appendInt32(-130358751) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(dialogs.count)) - for item in dialogs { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(messages.count)) - for item in messages { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(chats.count)) - for item in chats { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users.count)) - for item in users { - item.serialize(buffer, true) - } - break - case .savedDialogsNotModified(let count): - if boxed { - buffer.appendInt32(-1071681560) - } - serializeInt32(count, buffer: buffer, boxed: false) - break - case .savedDialogsSlice(let count, let dialogs, let messages, let chats, let users): - if boxed { - buffer.appendInt32(1153080793) - } - serializeInt32(count, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(dialogs.count)) - for item in dialogs { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(messages.count)) - for item in messages { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(chats.count)) - for item in chats { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users.count)) - for item in users { - item.serialize(buffer, true) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .savedDialogs(let dialogs, let messages, let chats, let users): - return ("savedDialogs", [("dialogs", dialogs as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)]) - case .savedDialogsNotModified(let count): - return ("savedDialogsNotModified", [("count", count as Any)]) - case .savedDialogsSlice(let count, let dialogs, let messages, let chats, let users): - return ("savedDialogsSlice", [("count", count as Any), ("dialogs", dialogs as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)]) - } - } - - public static func parse_savedDialogs(_ reader: BufferReader) -> SavedDialogs? { - var _1: [Api.SavedDialog]? - if let _ = reader.readInt32() { - _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedDialog.self) - } - var _2: [Api.Message]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) - } - var _3: [Api.Chat]? - if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) - } - var _4: [Api.User]? - if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.messages.SavedDialogs.savedDialogs(dialogs: _1!, messages: _2!, chats: _3!, users: _4!) - } - else { - return nil - } - } - public static func parse_savedDialogsNotModified(_ reader: BufferReader) -> SavedDialogs? { - var _1: Int32? - _1 = reader.readInt32() - let _c1 = _1 != nil - if _c1 { - return Api.messages.SavedDialogs.savedDialogsNotModified(count: _1!) - } - else { - return nil - } - } - public static func parse_savedDialogsSlice(_ reader: BufferReader) -> SavedDialogs? { - var _1: Int32? - _1 = reader.readInt32() - var _2: [Api.SavedDialog]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedDialog.self) - } - var _3: [Api.Message]? - if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) - } - var _4: [Api.Chat]? - if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) - } - var _5: [Api.User]? - if let _ = reader.readInt32() { - _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.messages.SavedDialogs.savedDialogsSlice(count: _1!, dialogs: _2!, messages: _3!, chats: _4!, users: _5!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api29.swift b/submodules/TelegramApi/Sources/Api29.swift index e19625e558..483f630d4b 100644 --- a/submodules/TelegramApi/Sources/Api29.swift +++ b/submodules/TelegramApi/Sources/Api29.swift @@ -1,3 +1,155 @@ +public extension Api.messages { + enum SavedDialogs: TypeConstructorDescription { + case savedDialogs(dialogs: [Api.SavedDialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + case savedDialogsNotModified(count: Int32) + case savedDialogsSlice(count: Int32, dialogs: [Api.SavedDialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .savedDialogs(let dialogs, let messages, let chats, let users): + if boxed { + buffer.appendInt32(-130358751) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dialogs.count)) + for item in dialogs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .savedDialogsNotModified(let count): + if boxed { + buffer.appendInt32(-1071681560) + } + serializeInt32(count, buffer: buffer, boxed: false) + break + case .savedDialogsSlice(let count, let dialogs, let messages, let chats, let users): + if boxed { + buffer.appendInt32(1153080793) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dialogs.count)) + for item in dialogs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .savedDialogs(let dialogs, let messages, let chats, let users): + return ("savedDialogs", [("dialogs", dialogs as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)]) + case .savedDialogsNotModified(let count): + return ("savedDialogsNotModified", [("count", count as Any)]) + case .savedDialogsSlice(let count, let dialogs, let messages, let chats, let users): + return ("savedDialogsSlice", [("count", count as Any), ("dialogs", dialogs as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)]) + } + } + + public static func parse_savedDialogs(_ reader: BufferReader) -> SavedDialogs? { + var _1: [Api.SavedDialog]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedDialog.self) + } + var _2: [Api.Message]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: [Api.User]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.SavedDialogs.savedDialogs(dialogs: _1!, messages: _2!, chats: _3!, users: _4!) + } + else { + return nil + } + } + public static func parse_savedDialogsNotModified(_ reader: BufferReader) -> SavedDialogs? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.messages.SavedDialogs.savedDialogsNotModified(count: _1!) + } + else { + return nil + } + } + public static func parse_savedDialogsSlice(_ reader: BufferReader) -> SavedDialogs? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.SavedDialog]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedDialog.self) + } + var _3: [Api.Message]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _4: [Api.Chat]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _5: [Api.User]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.messages.SavedDialogs.savedDialogsSlice(count: _1!, dialogs: _2!, messages: _3!, chats: _4!, users: _5!) + } + else { + return nil + } + } + + } +} public extension Api.messages { enum SavedGifs: TypeConstructorDescription { case savedGifs(hash: Int64, gifs: [Api.Document]) @@ -1398,95 +1550,3 @@ public extension Api.payments { } } -public extension Api.payments { - enum SavedInfo: TypeConstructorDescription { - case savedInfo(flags: Int32, savedInfo: Api.PaymentRequestedInfo?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .savedInfo(let flags, let savedInfo): - if boxed { - buffer.appendInt32(-74456004) - } - serializeInt32(flags, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .savedInfo(let flags, let savedInfo): - return ("savedInfo", [("flags", flags as Any), ("savedInfo", savedInfo as Any)]) - } - } - - public static func parse_savedInfo(_ reader: BufferReader) -> SavedInfo? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Api.PaymentRequestedInfo? - if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo - } } - let _c1 = _1 != nil - let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil - if _c1 && _c2 { - return Api.payments.SavedInfo.savedInfo(flags: _1!, savedInfo: _2) - } - else { - return nil - } - } - - } -} -public extension Api.payments { - enum ValidatedRequestedInfo: TypeConstructorDescription { - case validatedRequestedInfo(flags: Int32, id: String?, shippingOptions: [Api.ShippingOption]?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .validatedRequestedInfo(let flags, let id, let shippingOptions): - if boxed { - buffer.appendInt32(-784000893) - } - serializeInt32(flags, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {serializeString(id!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(shippingOptions!.count)) - for item in shippingOptions! { - item.serialize(buffer, true) - }} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .validatedRequestedInfo(let flags, let id, let shippingOptions): - return ("validatedRequestedInfo", [("flags", flags as Any), ("id", id as Any), ("shippingOptions", shippingOptions as Any)]) - } - } - - public static func parse_validatedRequestedInfo(_ reader: BufferReader) -> ValidatedRequestedInfo? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - if Int(_1!) & Int(1 << 0) != 0 {_2 = parseString(reader) } - var _3: [Api.ShippingOption]? - if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ShippingOption.self) - } } - let _c1 = _1 != nil - let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil - let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil - if _c1 && _c2 && _c3 { - return Api.payments.ValidatedRequestedInfo.validatedRequestedInfo(flags: _1!, id: _2, shippingOptions: _3) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api30.swift b/submodules/TelegramApi/Sources/Api30.swift index 5c39686c7d..2a1f98c411 100644 --- a/submodules/TelegramApi/Sources/Api30.swift +++ b/submodules/TelegramApi/Sources/Api30.swift @@ -1,3 +1,95 @@ +public extension Api.payments { + enum SavedInfo: TypeConstructorDescription { + case savedInfo(flags: Int32, savedInfo: Api.PaymentRequestedInfo?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .savedInfo(let flags, let savedInfo): + if boxed { + buffer.appendInt32(-74456004) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .savedInfo(let flags, let savedInfo): + return ("savedInfo", [("flags", flags as Any), ("savedInfo", savedInfo as Any)]) + } + } + + public static func parse_savedInfo(_ reader: BufferReader) -> SavedInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.PaymentRequestedInfo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + if _c1 && _c2 { + return Api.payments.SavedInfo.savedInfo(flags: _1!, savedInfo: _2) + } + else { + return nil + } + } + + } +} +public extension Api.payments { + enum ValidatedRequestedInfo: TypeConstructorDescription { + case validatedRequestedInfo(flags: Int32, id: String?, shippingOptions: [Api.ShippingOption]?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .validatedRequestedInfo(let flags, let id, let shippingOptions): + if boxed { + buffer.appendInt32(-784000893) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(id!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(shippingOptions!.count)) + for item in shippingOptions! { + item.serialize(buffer, true) + }} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .validatedRequestedInfo(let flags, let id, let shippingOptions): + return ("validatedRequestedInfo", [("flags", flags as Any), ("id", id as Any), ("shippingOptions", shippingOptions as Any)]) + } + } + + public static func parse_validatedRequestedInfo(_ reader: BufferReader) -> ValidatedRequestedInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + if Int(_1!) & Int(1 << 0) != 0 {_2 = parseString(reader) } + var _3: [Api.ShippingOption]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ShippingOption.self) + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.payments.ValidatedRequestedInfo.validatedRequestedInfo(flags: _1!, id: _2, shippingOptions: _3) + } + else { + return nil + } + } + + } +} public extension Api.phone { enum ExportedGroupCallInvite: TypeConstructorDescription { case exportedGroupCallInvite(link: String) @@ -724,6 +816,110 @@ public extension Api.premium { } } +public extension Api.smsjobs { + enum EligibilityToJoin: TypeConstructorDescription { + case eligibleToJoin(termsUrl: String, monthlySentSms: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .eligibleToJoin(let termsUrl, let monthlySentSms): + if boxed { + buffer.appendInt32(-594852657) + } + serializeString(termsUrl, buffer: buffer, boxed: false) + serializeInt32(monthlySentSms, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .eligibleToJoin(let termsUrl, let monthlySentSms): + return ("eligibleToJoin", [("termsUrl", termsUrl as Any), ("monthlySentSms", monthlySentSms as Any)]) + } + } + + public static func parse_eligibleToJoin(_ reader: BufferReader) -> EligibilityToJoin? { + var _1: String? + _1 = parseString(reader) + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.smsjobs.EligibilityToJoin.eligibleToJoin(termsUrl: _1!, monthlySentSms: _2!) + } + else { + return nil + } + } + + } +} +public extension Api.smsjobs { + enum Status: TypeConstructorDescription { + case status(flags: Int32, recentSent: Int32, recentSince: Int32, recentRemains: Int32, totalSent: Int32, totalSince: Int32, lastGiftSlug: String?, termsUrl: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .status(let flags, let recentSent, let recentSince, let recentRemains, let totalSent, let totalSince, let lastGiftSlug, let termsUrl): + if boxed { + buffer.appendInt32(720277905) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(recentSent, buffer: buffer, boxed: false) + serializeInt32(recentSince, buffer: buffer, boxed: false) + serializeInt32(recentRemains, buffer: buffer, boxed: false) + serializeInt32(totalSent, buffer: buffer, boxed: false) + serializeInt32(totalSince, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(lastGiftSlug!, buffer: buffer, boxed: false)} + serializeString(termsUrl, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .status(let flags, let recentSent, let recentSince, let recentRemains, let totalSent, let totalSince, let lastGiftSlug, let termsUrl): + return ("status", [("flags", flags as Any), ("recentSent", recentSent as Any), ("recentSince", recentSince as Any), ("recentRemains", recentRemains as Any), ("totalSent", totalSent as Any), ("totalSince", totalSince as Any), ("lastGiftSlug", lastGiftSlug as Any), ("termsUrl", termsUrl as Any)]) + } + } + + public static func parse_status(_ reader: BufferReader) -> Status? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int32? + _6 = reader.readInt32() + var _7: String? + if Int(_1!) & Int(1 << 1) != 0 {_7 = parseString(reader) } + var _8: String? + _8 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.smsjobs.Status.status(flags: _1!, recentSent: _2!, recentSince: _3!, recentRemains: _4!, totalSent: _5!, totalSince: _6!, lastGiftSlug: _7, termsUrl: _8!) + } + else { + return nil + } + } + + } +} public extension Api.stats { enum BroadcastStats: TypeConstructorDescription { case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, reactionsPerPost: Api.StatsAbsValueAndPrev, viewsPerStory: Api.StatsAbsValueAndPrev, sharesPerStory: Api.StatsAbsValueAndPrev, reactionsPerStory: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph, storyInteractionsGraph: Api.StatsGraph, storyReactionsByEmotionGraph: Api.StatsGraph, recentPostsInteractions: [Api.PostInteractionCounters]) @@ -1376,171 +1572,3 @@ public extension Api.storage { } } -public extension Api.stories { - enum AllStories: TypeConstructorDescription { - case allStories(flags: Int32, count: Int32, state: String, peerStories: [Api.PeerStories], chats: [Api.Chat], users: [Api.User], stealthMode: Api.StoriesStealthMode) - case allStoriesNotModified(flags: Int32, state: String, stealthMode: Api.StoriesStealthMode) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .allStories(let flags, let count, let state, let peerStories, let chats, let users, let stealthMode): - if boxed { - buffer.appendInt32(1862033025) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(count, buffer: buffer, boxed: false) - serializeString(state, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(peerStories.count)) - for item in peerStories { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(chats.count)) - for item in chats { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users.count)) - for item in users { - item.serialize(buffer, true) - } - stealthMode.serialize(buffer, true) - break - case .allStoriesNotModified(let flags, let state, let stealthMode): - if boxed { - buffer.appendInt32(291044926) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(state, buffer: buffer, boxed: false) - stealthMode.serialize(buffer, true) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .allStories(let flags, let count, let state, let peerStories, let chats, let users, let stealthMode): - return ("allStories", [("flags", flags as Any), ("count", count as Any), ("state", state as Any), ("peerStories", peerStories as Any), ("chats", chats as Any), ("users", users as Any), ("stealthMode", stealthMode as Any)]) - case .allStoriesNotModified(let flags, let state, let stealthMode): - return ("allStoriesNotModified", [("flags", flags as Any), ("state", state as Any), ("stealthMode", stealthMode as Any)]) - } - } - - public static func parse_allStories(_ reader: BufferReader) -> AllStories? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - var _3: String? - _3 = parseString(reader) - var _4: [Api.PeerStories]? - if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PeerStories.self) - } - var _5: [Api.Chat]? - if let _ = reader.readInt32() { - _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) - } - var _6: [Api.User]? - if let _ = reader.readInt32() { - _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - var _7: Api.StoriesStealthMode? - if let signature = reader.readInt32() { - _7 = Api.parse(reader, signature: signature) as? Api.StoriesStealthMode - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil - let _c7 = _7 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { - return Api.stories.AllStories.allStories(flags: _1!, count: _2!, state: _3!, peerStories: _4!, chats: _5!, users: _6!, stealthMode: _7!) - } - else { - return nil - } - } - public static func parse_allStoriesNotModified(_ reader: BufferReader) -> AllStories? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: Api.StoriesStealthMode? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.StoriesStealthMode - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.stories.AllStories.allStoriesNotModified(flags: _1!, state: _2!, stealthMode: _3!) - } - else { - return nil - } - } - - } -} -public extension Api.stories { - enum PeerStories: TypeConstructorDescription { - case peerStories(stories: Api.PeerStories, chats: [Api.Chat], users: [Api.User]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .peerStories(let stories, let chats, let users): - if boxed { - buffer.appendInt32(-890861720) - } - stories.serialize(buffer, true) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(chats.count)) - for item in chats { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users.count)) - for item in users { - item.serialize(buffer, true) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .peerStories(let stories, let chats, let users): - return ("peerStories", [("stories", stories as Any), ("chats", chats as Any), ("users", users as Any)]) - } - } - - public static func parse_peerStories(_ reader: BufferReader) -> PeerStories? { - var _1: Api.PeerStories? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.PeerStories - } - var _2: [Api.Chat]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) - } - var _3: [Api.User]? - if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.stories.PeerStories.peerStories(stories: _1!, chats: _2!, users: _3!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api31.swift b/submodules/TelegramApi/Sources/Api31.swift index 52e6eb8e1f..2b161fbd97 100644 --- a/submodules/TelegramApi/Sources/Api31.swift +++ b/submodules/TelegramApi/Sources/Api31.swift @@ -1,3 +1,171 @@ +public extension Api.stories { + enum AllStories: TypeConstructorDescription { + case allStories(flags: Int32, count: Int32, state: String, peerStories: [Api.PeerStories], chats: [Api.Chat], users: [Api.User], stealthMode: Api.StoriesStealthMode) + case allStoriesNotModified(flags: Int32, state: String, stealthMode: Api.StoriesStealthMode) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .allStories(let flags, let count, let state, let peerStories, let chats, let users, let stealthMode): + if boxed { + buffer.appendInt32(1862033025) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(count, buffer: buffer, boxed: false) + serializeString(state, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(peerStories.count)) + for item in peerStories { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + stealthMode.serialize(buffer, true) + break + case .allStoriesNotModified(let flags, let state, let stealthMode): + if boxed { + buffer.appendInt32(291044926) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(state, buffer: buffer, boxed: false) + stealthMode.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .allStories(let flags, let count, let state, let peerStories, let chats, let users, let stealthMode): + return ("allStories", [("flags", flags as Any), ("count", count as Any), ("state", state as Any), ("peerStories", peerStories as Any), ("chats", chats as Any), ("users", users as Any), ("stealthMode", stealthMode as Any)]) + case .allStoriesNotModified(let flags, let state, let stealthMode): + return ("allStoriesNotModified", [("flags", flags as Any), ("state", state as Any), ("stealthMode", stealthMode as Any)]) + } + } + + public static func parse_allStories(_ reader: BufferReader) -> AllStories? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: [Api.PeerStories]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PeerStories.self) + } + var _5: [Api.Chat]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _6: [Api.User]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + var _7: Api.StoriesStealthMode? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.StoriesStealthMode + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.stories.AllStories.allStories(flags: _1!, count: _2!, state: _3!, peerStories: _4!, chats: _5!, users: _6!, stealthMode: _7!) + } + else { + return nil + } + } + public static func parse_allStoriesNotModified(_ reader: BufferReader) -> AllStories? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Api.StoriesStealthMode? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.StoriesStealthMode + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.stories.AllStories.allStoriesNotModified(flags: _1!, state: _2!, stealthMode: _3!) + } + else { + return nil + } + } + + } +} +public extension Api.stories { + enum PeerStories: TypeConstructorDescription { + case peerStories(stories: Api.PeerStories, chats: [Api.Chat], users: [Api.User]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .peerStories(let stories, let chats, let users): + if boxed { + buffer.appendInt32(-890861720) + } + stories.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .peerStories(let stories, let chats, let users): + return ("peerStories", [("stories", stories as Any), ("chats", chats as Any), ("users", users as Any)]) + } + } + + public static func parse_peerStories(_ reader: BufferReader) -> PeerStories? { + var _1: Api.PeerStories? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.PeerStories + } + var _2: [Api.Chat]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _3: [Api.User]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.stories.PeerStories.peerStories(stories: _1!, chats: _2!, users: _3!) + } + else { + return nil + } + } + + } +} public extension Api.stories { enum Stories: TypeConstructorDescription { case stories(count: Int32, stories: [Api.StoryItem], chats: [Api.Chat], users: [Api.User]) diff --git a/submodules/TelegramApi/Sources/Api32.swift b/submodules/TelegramApi/Sources/Api32.swift index d280ba8d81..d8338e5bd5 100644 --- a/submodules/TelegramApi/Sources/Api32.swift +++ b/submodules/TelegramApi/Sources/Api32.swift @@ -1261,6 +1261,39 @@ public extension Api.functions.account { }) } } +public extension Api.functions.account { + static func updateBusinessLocation(flags: Int32, geoPoint: Api.InputGeoPoint?, address: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1040005974) + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {geoPoint!.serialize(buffer, true)} + if Int(flags) & Int(1 << 0) != 0 {serializeString(address!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "account.updateBusinessLocation", parameters: [("flags", String(describing: flags)), ("geoPoint", String(describing: geoPoint)), ("address", String(describing: address))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} +public extension Api.functions.account { + static func updateBusinessWorkHours(flags: Int32, businessWorkHours: Api.BusinessWorkHours?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1258348646) + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {businessWorkHours!.serialize(buffer, true)} + return (FunctionDescription(name: "account.updateBusinessWorkHours", parameters: [("flags", String(describing: flags)), ("businessWorkHours", String(describing: businessWorkHours))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.account { static func updateColor(flags: Int32, color: Int32?, backgroundEmojiId: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -4130,6 +4163,21 @@ public extension Api.functions.help { }) } } +public extension Api.functions.help { + static func getTimezonesList(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1236468288) + serializeInt32(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "help.getTimezonesList", parameters: [("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.TimezonesList? in + let reader = BufferReader(buffer) + var result: Api.help.TimezonesList? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.TimezonesList + } + return result + }) + } +} public extension Api.functions.help { static func getUserInfo(userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -4393,6 +4441,21 @@ public extension Api.functions.messages { }) } } +public extension Api.functions.messages { + static func checkQuickReplyShortcut(shortcut: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-237962285) + serializeString(shortcut, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.checkQuickReplyShortcut", parameters: [("shortcut", String(describing: shortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.messages { static func clearAllDrafts() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -4562,6 +4625,26 @@ public extension Api.functions.messages { }) } } +public extension Api.functions.messages { + static func deleteQuickReplyMessages(shortcutId: Int32, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-519706352) + serializeInt32(shortcutId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.deleteQuickReplyMessages", parameters: [("shortcutId", String(describing: shortcutId)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } +} public extension Api.functions.messages { static func deleteRevokedExportedChatInvites(peer: Api.InputPeer, adminId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -4760,9 +4843,9 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func editMessage(flags: Int32, peer: Api.InputPeer, id: Int32, message: String?, media: Api.InputMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func editMessage(flags: Int32, peer: Api.InputPeer, id: Int32, message: String?, media: Api.InputMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, quickReplyShortcutId: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(1224152952) + buffer.appendInt32(-539934715) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) serializeInt32(id, buffer: buffer, boxed: false) @@ -4775,7 +4858,8 @@ public extension Api.functions.messages { item.serialize(buffer, true) }} if Int(flags) & Int(1 << 15) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)} - return (FunctionDescription(name: "messages.editMessage", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("id", String(describing: id)), ("message", String(describing: message)), ("media", String(describing: media)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 17) != 0 {serializeInt32(quickReplyShortcutId!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "messages.editMessage", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("id", String(describing: id)), ("message", String(describing: message)), ("media", String(describing: media)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("quickReplyShortcutId", String(describing: quickReplyShortcutId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -4785,6 +4869,22 @@ public extension Api.functions.messages { }) } } +public extension Api.functions.messages { + static func editQuickReplyShortcut(shortcutId: Int32, shortcut: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1543519471) + serializeInt32(shortcutId, buffer: buffer, boxed: false) + serializeString(shortcut, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.editQuickReplyShortcut", parameters: [("shortcutId", String(describing: shortcutId)), ("shortcut", String(describing: shortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.messages { static func exportChatInvite(flags: Int32, peer: Api.InputPeer, expireDate: Int32?, usageLimit: Int32?, title: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -4821,9 +4921,9 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func forwardMessages(flags: Int32, fromPeer: Api.InputPeer, id: [Int32], randomId: [Int64], toPeer: Api.InputPeer, topMsgId: Int32?, scheduleDate: Int32?, sendAs: Api.InputPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func forwardMessages(flags: Int32, fromPeer: Api.InputPeer, id: [Int32], randomId: [Int64], toPeer: Api.InputPeer, topMsgId: Int32?, scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-966673468) + buffer.appendInt32(-709978674) serializeInt32(flags, buffer: buffer, boxed: false) fromPeer.serialize(buffer, true) buffer.appendInt32(481674261) @@ -4840,7 +4940,8 @@ public extension Api.functions.messages { if Int(flags) & Int(1 << 9) != 0 {serializeInt32(topMsgId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 10) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 13) != 0 {sendAs!.serialize(buffer, true)} - return (FunctionDescription(name: "messages.forwardMessages", parameters: [("flags", String(describing: flags)), ("fromPeer", String(describing: fromPeer)), ("id", String(describing: id)), ("randomId", String(describing: randomId)), ("toPeer", String(describing: toPeer)), ("topMsgId", String(describing: topMsgId)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 17) != 0 {serializeString(quickReplyShortcut!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "messages.forwardMessages", parameters: [("flags", String(describing: flags)), ("fromPeer", String(describing: fromPeer)), ("id", String(describing: id)), ("randomId", String(describing: randomId)), ("toPeer", String(describing: toPeer)), ("topMsgId", String(describing: topMsgId)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -5804,6 +5905,43 @@ public extension Api.functions.messages { }) } } +public extension Api.functions.messages { + static func getQuickReplies(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-729550168) + serializeInt64(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getQuickReplies", parameters: [("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.QuickReplies? in + let reader = BufferReader(buffer) + var result: Api.messages.QuickReplies? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.QuickReplies + } + return result + }) + } +} +public extension Api.functions.messages { + static func getQuickReplyMessages(flags: Int32, shortcutId: Int32, id: [Int32]?, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1801153085) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(shortcutId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id!.count)) + for item in id! { + serializeInt32(item, buffer: buffer, boxed: false) + }} + serializeInt64(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.getQuickReplyMessages", parameters: [("flags", String(describing: flags)), ("shortcutId", String(describing: shortcutId)), ("id", String(describing: id)), ("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in + let reader = BufferReader(buffer) + var result: Api.messages.Messages? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.messages.Messages + } + return result + }) + } +} public extension Api.functions.messages { static func getRecentLocations(peer: Api.InputPeer, limit: Int32, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -6566,6 +6704,25 @@ public extension Api.functions.messages { }) } } +public extension Api.functions.messages { + static func reorderQuickReplies(order: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1613961479) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order.count)) + for item in order { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.reorderQuickReplies", parameters: [("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.messages { static func reorderStickerSets(flags: Int32, order: [Int64]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -7029,9 +7186,9 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func sendInlineBotResult(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, randomId: Int64, queryId: Int64, id: String, scheduleDate: Int32?, sendAs: Api.InputPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func sendInlineBotResult(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, randomId: Int64, queryId: Int64, id: String, scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-138647366) + buffer.appendInt32(-407001673) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) if Int(flags) & Int(1 << 0) != 0 {replyTo!.serialize(buffer, true)} @@ -7040,7 +7197,8 @@ public extension Api.functions.messages { serializeString(id, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 10) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 13) != 0 {sendAs!.serialize(buffer, true)} - return (FunctionDescription(name: "messages.sendInlineBotResult", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("randomId", String(describing: randomId)), ("queryId", String(describing: queryId)), ("id", String(describing: id)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 17) != 0 {serializeString(quickReplyShortcut!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "messages.sendInlineBotResult", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("randomId", String(describing: randomId)), ("queryId", String(describing: queryId)), ("id", String(describing: id)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -7051,9 +7209,9 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func sendMedia(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, media: Api.InputMedia, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, sendAs: Api.InputPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func sendMedia(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, media: Api.InputMedia, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(1926021693) + buffer.appendInt32(-10487971) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) if Int(flags) & Int(1 << 0) != 0 {replyTo!.serialize(buffer, true)} @@ -7068,7 +7226,8 @@ public extension Api.functions.messages { }} if Int(flags) & Int(1 << 10) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 13) != 0 {sendAs!.serialize(buffer, true)} - return (FunctionDescription(name: "messages.sendMedia", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("media", String(describing: media)), ("message", String(describing: message)), ("randomId", String(describing: randomId)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 17) != 0 {serializeString(quickReplyShortcut!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "messages.sendMedia", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("media", String(describing: media)), ("message", String(describing: message)), ("randomId", String(describing: randomId)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -7079,9 +7238,9 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func sendMessage(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, sendAs: Api.InputPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func sendMessage(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(671943023) + buffer.appendInt32(1750387040) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) if Int(flags) & Int(1 << 0) != 0 {replyTo!.serialize(buffer, true)} @@ -7095,7 +7254,8 @@ public extension Api.functions.messages { }} if Int(flags) & Int(1 << 10) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 13) != 0 {sendAs!.serialize(buffer, true)} - return (FunctionDescription(name: "messages.sendMessage", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("message", String(describing: message)), ("randomId", String(describing: randomId)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 17) != 0 {serializeString(quickReplyShortcut!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "messages.sendMessage", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("message", String(describing: message)), ("randomId", String(describing: randomId)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -7106,9 +7266,9 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func sendMultiMedia(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, multiMedia: [Api.InputSingleMedia], scheduleDate: Int32?, sendAs: Api.InputPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func sendMultiMedia(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, multiMedia: [Api.InputSingleMedia], scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(1164872071) + buffer.appendInt32(-2027543192) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) if Int(flags) & Int(1 << 0) != 0 {replyTo!.serialize(buffer, true)} @@ -7119,7 +7279,24 @@ public extension Api.functions.messages { } if Int(flags) & Int(1 << 10) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 13) != 0 {sendAs!.serialize(buffer, true)} - return (FunctionDescription(name: "messages.sendMultiMedia", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("multiMedia", String(describing: multiMedia)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 17) != 0 {serializeString(quickReplyShortcut!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "messages.sendMultiMedia", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("multiMedia", String(describing: multiMedia)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } +} +public extension Api.functions.messages { + static func sendQuickReplyMessages(peer: Api.InputPeer, shortcutId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(857029332) + peer.serialize(buffer, true) + serializeInt32(shortcutId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messages.sendQuickReplyMessages", parameters: [("peer", String(describing: peer)), ("shortcutId", String(describing: shortcutId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -8795,6 +8972,113 @@ public extension Api.functions.premium { }) } } +public extension Api.functions.smsjobs { + static func finishJob(flags: Int32, jobId: String, error: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1327415076) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(jobId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(error!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "smsjobs.finishJob", parameters: [("flags", String(describing: flags)), ("jobId", String(describing: jobId)), ("error", String(describing: error))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} +public extension Api.functions.smsjobs { + static func getSmsJob(jobId: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(2005766191) + serializeString(jobId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "smsjobs.getSmsJob", parameters: [("jobId", String(describing: jobId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.SmsJob? in + let reader = BufferReader(buffer) + var result: Api.SmsJob? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.SmsJob + } + return result + }) + } +} +public extension Api.functions.smsjobs { + static func getStatus() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(279353576) + + return (FunctionDescription(name: "smsjobs.getStatus", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.smsjobs.Status? in + let reader = BufferReader(buffer) + var result: Api.smsjobs.Status? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.smsjobs.Status + } + return result + }) + } +} +public extension Api.functions.smsjobs { + static func isEligibleToJoin() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(249313744) + + return (FunctionDescription(name: "smsjobs.isEligibleToJoin", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.smsjobs.EligibilityToJoin? in + let reader = BufferReader(buffer) + var result: Api.smsjobs.EligibilityToJoin? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.smsjobs.EligibilityToJoin + } + return result + }) + } +} +public extension Api.functions.smsjobs { + static func join() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1488007635) + + return (FunctionDescription(name: "smsjobs.join", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} +public extension Api.functions.smsjobs { + static func leave() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1734824589) + + return (FunctionDescription(name: "smsjobs.leave", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} +public extension Api.functions.smsjobs { + static func updateSettings(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(155164863) + serializeInt32(flags, buffer: buffer, boxed: false) + return (FunctionDescription(name: "smsjobs.updateSettings", parameters: [("flags", String(describing: flags))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.stats { static func getBroadcastStats(flags: Int32, channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 76754ca04c..7829c5dcd7 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -126,7 +126,7 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute], func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? { switch messsage { - case let .message(_, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): let chatPeerId = messagePeerId return chatPeerId.peerId case let .messageEmpty(_, _, peerId): @@ -142,7 +142,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? { func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { switch message { - case let .message(_, _, fromId, _, chatPeerId, savedPeerId, fwdHeader, viaBotId, replyTo, _, _, media, _, entities, _, _, _, _, _, _, _, _, _): + case let .message(_, _, fromId, _, chatPeerId, savedPeerId, fwdHeader, viaBotId, replyTo, _, _, media, _, entities, _, _, _, _, _, _, _, _, _, _): let peerId: PeerId = chatPeerId.peerId var result = [peerId] @@ -263,7 +263,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { func apiMessageAssociatedMessageIds(_ message: Api.Message) -> (replyIds: ReferencedReplyMessageIds, generalIds: [MessageId])? { switch message { - case let .message(_, id, _, _, chatPeerId, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, id, _, _, chatPeerId, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): if let replyTo = replyTo { let peerId: PeerId = chatPeerId.peerId @@ -597,7 +597,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes extension StoreMessage { convenience init?(apiMessage: Api.Message, accountPeerId: PeerId, peerIsForum: Bool, namespace: MessageId.Namespace = Namespaces.Message.Cloud) { switch apiMessage { - case let .message(flags, id, fromId, boosts, chatPeerId, savedPeerId, fwdFrom, viaBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod): + case let .message(flags, id, fromId, boosts, chatPeerId, savedPeerId, fwdFrom, viaBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod, _): let resolvedFromId = fromId?.peerId ?? chatPeerId.peerId let peerId: PeerId diff --git a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift index 2532a673a4..e568ed9c78 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift @@ -174,7 +174,7 @@ private func requestEditMessageInternal(accountPeerId: PeerId, postbox: Postbox, } } - return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: text, media: inputMedia, replyMarkup: nil, entities: apiEntities, scheduleDate: effectiveScheduleTime)) + return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: text, media: inputMedia, replyMarkup: nil, entities: apiEntities, scheduleDate: effectiveScheduleTime, quickReplyShortcutId: nil)) |> map { result -> Api.Updates? in return result } @@ -304,7 +304,7 @@ func _internal_requestEditLiveLocation(postbox: Postbox, network: Network, state inputMedia = .inputMediaGeoLive(flags: 1 << 0, geoPoint: .inputGeoPoint(flags: 0, lat: media.latitude, long: media.longitude, accuracyRadius: nil), heading: nil, period: nil, proximityNotificationRadius: nil) } - return network.request(Api.functions.messages.editMessage(flags: 1 << 14, peer: inputPeer, id: messageId.id, message: nil, media: inputMedia, replyMarkup: nil, entities: nil, scheduleDate: nil)) + return network.request(Api.functions.messages.editMessage(flags: 1 << 14, peer: inputPeer, id: messageId.id, message: nil, media: inputMedia, replyMarkup: nil, entities: nil, scheduleDate: nil, quickReplyShortcutId: nil)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) diff --git a/submodules/TelegramCore/Sources/PendingMessages/StandaloneSendMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/StandaloneSendMessage.swift index 5496447f8c..bfeb829948 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/StandaloneSendMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/StandaloneSendMessage.swift @@ -410,7 +410,7 @@ private func sendUploadedMessageContent( } } - sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), info: .acknowledgement, tag: dependencyTag) + sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), info: .acknowledgement, tag: dependencyTag) case let .media(inputMedia, text): if bubbleUpEmojiOrStickersets { flags |= Int32(1 << 15) @@ -432,7 +432,7 @@ private func sendUploadedMessageContent( } } - sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), tag: dependencyTag) + sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), tag: dependencyTag) |> map(NetworkRequestResult.result) case let .forward(sourceInfo): var topMsgId: Int32? @@ -442,7 +442,7 @@ private func sendUploadedMessageContent( } if let forwardSourceInfoAttribute = forwardSourceInfoAttribute, let sourcePeer = transaction.getPeer(forwardSourceInfoAttribute.messageId.peerId), let sourceInputPeer = apiInputPeer(sourcePeer) { - sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), tag: dependencyTag) + sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), tag: dependencyTag) |> map(NetworkRequestResult.result) } else { sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "internal")) @@ -468,7 +468,7 @@ private func sendUploadedMessageContent( } } - sendMessageRequest = network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyTo: replyTo, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id, scheduleDate: scheduleTime, sendAs: sendAsInputPeer)) + sendMessageRequest = network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyTo: replyTo, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil)) |> map(NetworkRequestResult.result) case .messageScreenshot: let replyTo: Api.InputReplyTo @@ -633,7 +633,7 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M } } - sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer)) + sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil)) |> `catch` { _ -> Signal in return .complete() } @@ -651,7 +651,7 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M } } - sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer)) + sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil)) |> `catch` { _ -> Signal in return .complete() } diff --git a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift index b0fd855035..50e1d1d148 100644 --- a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift @@ -1444,7 +1444,7 @@ public final class AccountViewTracker { if i < slice.count { let value = result[i] transaction.updatePeerCachedData(peerIds: Set([slice[i].0]), update: { _, cachedData in - var cachedData = cachedData as? CachedUserData ?? CachedUserData(about: nil, botInfo: nil, editableBotInfo: nil, peerStatusSettings: nil, pinnedMessageId: nil, isBlocked: false, commonGroupCount: 0, voiceCallsAvailable: true, videoCallsAvailable: true, callsPrivate: true, canPinMessages: true, hasScheduledMessages: true, autoremoveTimeout: .unknown, themeEmoticon: nil, photo: .unknown, personalPhoto: .unknown, fallbackPhoto: .unknown, premiumGiftOptions: [], voiceMessagesAvailable: true, wallpaper: nil, flags: []) + var cachedData = cachedData as? CachedUserData ?? CachedUserData(about: nil, botInfo: nil, editableBotInfo: nil, peerStatusSettings: nil, pinnedMessageId: nil, isBlocked: false, commonGroupCount: 0, voiceCallsAvailable: true, videoCallsAvailable: true, callsPrivate: true, canPinMessages: true, hasScheduledMessages: true, autoremoveTimeout: .unknown, themeEmoticon: nil, photo: .unknown, personalPhoto: .unknown, fallbackPhoto: .unknown, premiumGiftOptions: [], voiceMessagesAvailable: true, wallpaper: nil, flags: [], businessHours: nil, businessLocation: nil) var flags = cachedData.flags if case .boolTrue = value { flags.insert(.premiumRequired) diff --git a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift index 6bb8c76657..79999c1058 100644 --- a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift +++ b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift @@ -96,7 +96,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes var updatedTimestamp: Int32? if let apiMessage = apiMessage { switch apiMessage { - case let .message(_, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _): updatedTimestamp = date case .messageEmpty: break diff --git a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift index bab864f5a6..85d6551e74 100644 --- a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift +++ b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift @@ -878,7 +878,7 @@ public final class PendingMessageManager { } else if let inputSourcePeerId = forwardPeerIds.first, let inputSourcePeer = transaction.getPeer(inputSourcePeerId).flatMap(apiInputPeer) { let dependencyTag = PendingMessageRequestDependencyTag(messageId: messages[0].0.id) - sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: inputSourcePeer, id: forwardIds.map { $0.0.id }, randomId: forwardIds.map { $0.1 }, toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), tag: dependencyTag) + sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: inputSourcePeer, id: forwardIds.map { $0.0.id }, randomId: forwardIds.map { $0.1 }, toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), tag: dependencyTag) } else { assertionFailure() sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "Invalid forward source")) @@ -993,7 +993,7 @@ public final class PendingMessageManager { } } - sendMessageRequest = network.request(Api.functions.messages.sendMultiMedia(flags: flags, peer: inputPeer, replyTo: replyTo, multiMedia: singleMedias, scheduleDate: scheduleTime, sendAs: sendAsInputPeer)) + sendMessageRequest = network.request(Api.functions.messages.sendMultiMedia(flags: flags, peer: inputPeer, replyTo: replyTo, multiMedia: singleMedias, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil)) } return sendMessageRequest @@ -1291,7 +1291,7 @@ public final class PendingMessageManager { } } - sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: message.text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), info: .acknowledgement, tag: dependencyTag) + sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: message.text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), info: .acknowledgement, tag: dependencyTag) case let .media(inputMedia, text): if bubbleUpEmojiOrStickersets { flags |= Int32(1 << 15) @@ -1356,7 +1356,7 @@ public final class PendingMessageManager { } } - sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), tag: dependencyTag) + sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), tag: dependencyTag) |> map(NetworkRequestResult.result) case let .forward(sourceInfo): var topMsgId: Int32? @@ -1366,7 +1366,7 @@ public final class PendingMessageManager { } if let forwardSourceInfoAttribute = forwardSourceInfoAttribute, let sourcePeer = transaction.getPeer(forwardSourceInfoAttribute.messageId.peerId), let sourceInputPeer = apiInputPeer(sourcePeer) { - sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), tag: dependencyTag) + sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), tag: dependencyTag) |> map(NetworkRequestResult.result) } else { sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "internal")) @@ -1429,7 +1429,7 @@ public final class PendingMessageManager { } } - sendMessageRequest = network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyTo: replyTo, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id, scheduleDate: scheduleTime, sendAs: sendAsInputPeer)) + sendMessageRequest = network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyTo: replyTo, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil)) |> map(NetworkRequestResult.result) case .messageScreenshot: let replyTo: Api.InputReplyTo diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index ebac41c4cf..6e1311188e 100644 --- a/submodules/TelegramCore/Sources/State/Serialization.swift +++ b/submodules/TelegramCore/Sources/State/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 174 + return 176 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/State/UpdateMessageService.swift b/submodules/TelegramCore/Sources/State/UpdateMessageService.swift index d3091dad12..279064d68a 100644 --- a/submodules/TelegramCore/Sources/State/UpdateMessageService.swift +++ b/submodules/TelegramCore/Sources/State/UpdateMessageService.swift @@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService { self.putNext(groups) } case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities, ttlPeriod): - let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: .peerUser(userId: fromId), fromBoostsApplied: nil, peerId: Api.Peer.peerChat(chatId: chatId), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod) + let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: .peerUser(userId: fromId), fromBoostsApplied: nil, peerId: Api.Peer.peerChat(chatId: chatId), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil) let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount) let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) if groups.count != 0 { @@ -74,7 +74,7 @@ class UpdateMessageService: NSObject, MTMessageService { let generatedPeerId = Api.Peer.peerUser(userId: userId) - let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, fromBoostsApplied: nil, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod) + let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, fromBoostsApplied: nil, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil) let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount) let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) if groups.count != 0 { diff --git a/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift b/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift index 87f132c4ca..a75e264534 100644 --- a/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift +++ b/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift @@ -104,7 +104,7 @@ extension Api.MessageMedia { extension Api.Message { var rawId: Int32 { switch self { - case let .message(_, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): return id case let .messageEmpty(_, id, _): return id @@ -115,7 +115,7 @@ extension Api.Message { func id(namespace: MessageId.Namespace = Namespaces.Message.Cloud) -> MessageId? { switch self { - case let .message(_, id, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, id, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): let peerId: PeerId = messagePeerId.peerId return MessageId(peerId: peerId, namespace: namespace, id: id) case let .messageEmpty(_, id, peerId): @@ -132,7 +132,7 @@ extension Api.Message { var peerId: PeerId? { switch self { - case let .message(_, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): let peerId: PeerId = messagePeerId.peerId return peerId case let .messageEmpty(_, _, peerId): @@ -145,7 +145,7 @@ extension Api.Message { var timestamp: Int32? { switch self { - case let .message(_, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _): return date case let .messageService(_, _, _, _, _, date, _, _): return date @@ -156,7 +156,7 @@ extension Api.Message { var preCachedResources: [(MediaResource, Data)]? { switch self { - case let .message(_, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _): return media?.preCachedResources default: return nil @@ -165,7 +165,7 @@ extension Api.Message { var preCachedStories: [StoryId: Api.StoryItem]? { switch self { - case let .message(_, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _): return media?.preCachedStories default: return nil diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift index 87c5e65003..4099a39f97 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift @@ -247,6 +247,183 @@ public final class EditableBotInfo: PostboxCoding, Equatable { } } +public final class TelegramBusinessHours: Equatable, Codable { + public struct WorkingTimeInterval: Equatable, Codable { + private enum CodingKeys: String, CodingKey { + case startMinute + case endMinute + } + + public let startMinute: Int + public let endMinute: Int + + public init(startMinute: Int, endMinute: Int) { + self.startMinute = startMinute + self.endMinute = endMinute + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.startMinute = Int(try container.decode(Int32.self, forKey: .startMinute)) + self.endMinute = Int(try container.decode(Int32.self, forKey: .endMinute)) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(Int32(clamping: self.startMinute), forKey: .startMinute) + try container.encode(Int32(clamping: self.endMinute), forKey: .endMinute) + } + + public static func ==(lhs: WorkingTimeInterval, rhs: WorkingTimeInterval) -> Bool { + if lhs.startMinute != rhs.startMinute { + return false + } + if lhs.endMinute != rhs.endMinute { + return false + } + return true + } + } + + public let timezoneId: String + public let weeklyTimeIntervals: [WorkingTimeInterval] + + public init(timezoneId: String, weeklyTimeIntervals: [WorkingTimeInterval]) { + self.timezoneId = timezoneId + self.weeklyTimeIntervals = weeklyTimeIntervals + } + + public static func ==(lhs: TelegramBusinessHours, rhs: TelegramBusinessHours) -> Bool { + if lhs.timezoneId != rhs.timezoneId { + return false + } + if lhs.weeklyTimeIntervals != rhs.weeklyTimeIntervals { + return false + } + return true + } + + public enum WeekDay { + case closed + case open + case intervals([WorkingTimeInterval]) + } + + public func splitIntoWeekDays() -> [WeekDay] { + var mappedDays: [[WorkingTimeInterval]] = Array(repeating: [], count: 7) + + for interval in self.weeklyTimeIntervals { + let startDayIndex = interval.startMinute / (24 * 60) + if startDayIndex < 0 || startDayIndex >= 7 { + continue + } + + let startTimeInsideDay = interval.startMinute - startDayIndex * (24 * 60) + let endTimeInsideDay = interval.endMinute - startDayIndex * (24 * 60) + + mappedDays[startDayIndex].append(WorkingTimeInterval( + startMinute: startTimeInsideDay, + endMinute: endTimeInsideDay + )) + } + + return mappedDays.map { day -> WeekDay in + var minutes = IndexSet() + for interval in day { + minutes.insert(integersIn: interval.startMinute ..< interval.endMinute) + } + if minutes.isEmpty { + return .closed + } else if minutes == IndexSet(integersIn: 0 ..< 24 * 60) { + return .open + } else { + return .intervals(day) + } + } + } +} + +public final class TelegramBusinessLocation: Equatable, Codable { + public struct Coordinates: Equatable, Codable { + public let latitude: Double + public let longitude: Double + + public init(latitude: Double, longitude: Double) { + self.latitude = latitude + self.longitude = longitude + } + } + + public let address: String + public let coordinates: Coordinates? + + public init(address: String, coordinates: Coordinates?) { + self.address = address + self.coordinates = coordinates + } + + public static func ==(lhs: TelegramBusinessLocation, rhs: TelegramBusinessLocation) -> Bool { + if lhs.address != rhs.address { + return false + } + if lhs.coordinates != rhs.coordinates { + return false + } + return true + } +} + +extension TelegramBusinessHours.WorkingTimeInterval { + init(apiInterval: Api.BusinessWeeklyOpen) { + switch apiInterval { + case let .businessWeeklyOpen(startMinute, endMinute): + self.init(startMinute: Int(startMinute), endMinute: Int(endMinute)) + } + } + + var apiInterval: Api.BusinessWeeklyOpen { + return .businessWeeklyOpen(startMinute: Int32(clamping: self.startMinute), endMinute: Int32(clamping: self.endMinute)) + } +} + +extension TelegramBusinessHours { + convenience init(apiWorkingHours: Api.BusinessWorkHours) { + switch apiWorkingHours { + case let .businessWorkHours(_, timezoneId, weeklyOpen): + self.init(timezoneId: timezoneId, weeklyTimeIntervals: weeklyOpen.map(TelegramBusinessHours.WorkingTimeInterval.init(apiInterval:))) + } + } + + var apiBusinessHours: Api.BusinessWorkHours { + return .businessWorkHours(flags: 0, timezoneId: self.timezoneId, weeklyOpen: self.weeklyTimeIntervals.map(\.apiInterval)) + } +} + +extension TelegramBusinessLocation.Coordinates { + init?(apiGeoPoint: Api.GeoPoint) { + switch apiGeoPoint { + case let .geoPoint(_, long, lat, _, _): + self.init(latitude: lat, longitude: long) + case .geoPointEmpty: + return nil + } + } + + var apiInputGeoPoint: Api.InputGeoPoint { + return .inputGeoPoint(flags: 0, lat: self.latitude, long: self.longitude, accuracyRadius: nil) + } +} + +extension TelegramBusinessLocation { + convenience init(apiLocation: Api.BusinessLocation) { + switch apiLocation { + case let .businessLocation(geoPoint, address): + self.init(address: address, coordinates: Coordinates(apiGeoPoint: geoPoint)) + } + } +} public final class CachedUserData: CachedPeerData { public let about: String? @@ -270,7 +447,8 @@ public final class CachedUserData: CachedPeerData { public let voiceMessagesAvailable: Bool public let wallpaper: TelegramWallpaper? public let flags: CachedUserFlags - + public let businessHours: TelegramBusinessHours? + public let businessLocation: TelegramBusinessLocation? public let peerIds: Set public let messageIds: Set public let associatedHistoryMessageId: MessageId? = nil @@ -297,11 +475,13 @@ public final class CachedUserData: CachedPeerData { self.voiceMessagesAvailable = true self.wallpaper = nil self.flags = CachedUserFlags() + self.businessHours = nil + self.businessLocation = nil self.peerIds = Set() self.messageIds = Set() } - public init(about: String?, botInfo: BotInfo?, editableBotInfo: EditableBotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, premiumGiftOptions: [CachedPremiumGiftOption], voiceMessagesAvailable: Bool, wallpaper: TelegramWallpaper?, flags: CachedUserFlags) { + public init(about: String?, botInfo: BotInfo?, editableBotInfo: EditableBotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, premiumGiftOptions: [CachedPremiumGiftOption], voiceMessagesAvailable: Bool, wallpaper: TelegramWallpaper?, flags: CachedUserFlags, businessHours: TelegramBusinessHours?, businessLocation: TelegramBusinessLocation?) { self.about = about self.botInfo = botInfo self.editableBotInfo = editableBotInfo @@ -323,6 +503,8 @@ public final class CachedUserData: CachedPeerData { self.voiceMessagesAvailable = voiceMessagesAvailable self.wallpaper = wallpaper self.flags = flags + self.businessHours = businessHours + self.businessLocation = businessLocation self.peerIds = Set() @@ -375,6 +557,9 @@ public final class CachedUserData: CachedPeerData { messageIds.insert(pinnedMessageId) } self.messageIds = messageIds + + self.businessHours = decoder.decodeCodable(TelegramBusinessHours.self, forKey: "bhrs") + self.businessLocation = decoder.decodeCodable(TelegramBusinessLocation.self, forKey: "bloc") } public func encode(_ encoder: PostboxEncoder) { @@ -435,6 +620,18 @@ public final class CachedUserData: CachedPeerData { } encoder.encodeInt32(self.flags.rawValue, forKey: "fl") + + if let businessHours = self.businessHours { + encoder.encodeCodable(businessHours, forKey: "bhrs") + } else { + encoder.encodeNil(forKey: "bhrs") + } + + if let businessLocation = self.businessLocation { + encoder.encodeCodable(businessLocation, forKey: "bloc") + } else { + encoder.encodeNil(forKey: "bloc") + } } public func isEqual(to: CachedPeerData) -> Bool { @@ -448,91 +645,105 @@ public final class CachedUserData: CachedPeerData { if other.canPinMessages != self.canPinMessages { return false } + if other.businessHours != self.businessHours { + return false + } + if other.businessLocation != self.businessLocation { + return false + } return other.about == self.about && other.botInfo == self.botInfo && other.editableBotInfo == self.editableBotInfo && self.peerStatusSettings == other.peerStatusSettings && self.isBlocked == other.isBlocked && self.commonGroupCount == other.commonGroupCount && self.voiceCallsAvailable == other.voiceCallsAvailable && self.videoCallsAvailable == other.videoCallsAvailable && self.callsPrivate == other.callsPrivate && self.hasScheduledMessages == other.hasScheduledMessages && self.autoremoveTimeout == other.autoremoveTimeout && self.themeEmoticon == other.themeEmoticon && self.photo == other.photo && self.personalPhoto == other.personalPhoto && self.fallbackPhoto == other.fallbackPhoto && self.premiumGiftOptions == other.premiumGiftOptions && self.voiceMessagesAvailable == other.voiceMessagesAvailable && self.flags == other.flags && self.wallpaper == other.wallpaper } public func withUpdatedAbout(_ about: String?) -> CachedUserData { - return CachedUserData(about: about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedBotInfo(_ botInfo: BotInfo?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedEditableBotInfo(_ editableBotInfo: EditableBotInfo?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedIsBlocked(_ isBlocked: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedCommonGroupCount(_ commonGroupCount: Int32) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedVoiceCallsAvailable(_ voiceCallsAvailable: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedVideoCallsAvailable(_ videoCallsAvailable: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedCallsPrivate(_ callsPrivate: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedCanPinMessages(_ canPinMessages: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedAutoremoveTimeout(_ autoremoveTimeout: CachedPeerAutoremoveTimeout) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedThemeEmoticon(_ themeEmoticon: String?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedPhoto(_ photo: CachedPeerProfilePhoto) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedPersonalPhoto(_ personalPhoto: CachedPeerProfilePhoto) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedFallbackPhoto(_ fallbackPhoto: CachedPeerProfilePhoto) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedPremiumGiftOptions(_ premiumGiftOptions: [CachedPremiumGiftOption]) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedVoiceMessagesAvailable(_ voiceMessagesAvailable: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedWallpaper(_ wallpaper: TelegramWallpaper?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: wallpaper, flags: self.flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation) } public func withUpdatedFlags(_ flags: CachedUserFlags) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: flags) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: flags, businessHours: self.businessHours, businessLocation: self.businessLocation) + } + + public func withUpdatedBusinessHours(_ businessHours: TelegramBusinessHours?) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: businessHours, businessLocation: self.businessLocation) + } + + public func withUpdatedBusinessLocation(_ businessLocation: TelegramBusinessLocation?) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, premiumGiftOptions: self.premiumGiftOptions, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: businessLocation) } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift index c61b94706a..a483fd4329 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift @@ -280,6 +280,7 @@ private enum PreferencesKeyValues: Int32 { case audioTranscriptionTrialState = 33 case didCacheSavedMessageTagsPrefix = 34 case displaySavedChatsAsTopics = 35 + case shortcutMessages = 36 } public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey { @@ -463,6 +464,12 @@ public struct PreferencesKeys { key.setInt32(0, value: PreferencesKeyValues.displaySavedChatsAsTopics.rawValue) return key } + + public static func shortcutMessages() -> ValueBoxKey { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.shortcutMessages.rawValue) + return key + } } private enum SharedDataKeyValues: Int32 { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift index f6d798ebe7..db2a419409 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift @@ -105,5 +105,65 @@ public extension TelegramEngine { |> ignoreValues |> then(remoteApply) } + + public func updateAccountBusinessHours(businessHours: TelegramBusinessHours?) -> Signal { + let peerId = self.account.peerId + + var flags: Int32 = 0 + if businessHours != nil { + flags |= 1 << 0 + } + let remoteApply: Signal = self.account.network.request(Api.functions.account.updateBusinessWorkHours(flags: flags, businessWorkHours: businessHours?.apiBusinessHours)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> ignoreValues + + return self.account.postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + let current = current as? CachedUserData ?? CachedUserData() + return current.withUpdatedBusinessHours(businessHours) + }) + } + |> ignoreValues + |> then(remoteApply) + } + + public func updateAccountBusinessLocation(businessLocation: TelegramBusinessLocation?) -> Signal { + let peerId = self.account.peerId + + var flags: Int32 = 0 + + var inputGeoPoint: Api.InputGeoPoint? + var inputAddress: String? + if let businessLocation { + flags |= 1 << 0 + inputGeoPoint = businessLocation.coordinates?.apiInputGeoPoint ?? .inputGeoPointEmpty + inputAddress = businessLocation.address + } + + let remoteApply: Signal = self.account.network.request(Api.functions.account.updateBusinessLocation(flags: flags, geoPoint: inputGeoPoint, address: inputAddress)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> ignoreValues + + return self.account.postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + let current = current as? CachedUserData ?? CachedUserData() + return current.withUpdatedBusinessLocation(businessLocation) + }) + } + |> ignoreValues + |> then(remoteApply) + } + + public func shortcutMessages() -> Signal { + return _internal_shortcutMessages(account: self.account) + } + + public func updateShortcutMessages(state: QuickReplyMessageShortcutsState) { + let _ = _internal_updateShortcutMessages(account: self.account, state: state).startStandalone() + } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift index 441d293a94..52c7fbb6b0 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift @@ -4,6 +4,7 @@ import Postbox public typealias EngineExportedPeerInvitation = ExportedInvitation public typealias EngineSecretChatKeyFingerprint = SecretChatKeyFingerprint + public enum EnginePeerCachedInfoItem { case known(T) case unknown @@ -1443,6 +1444,61 @@ public extension TelegramEngine.EngineData.Item { } } } + + public struct BusinessHours: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { + public typealias Result = TelegramBusinessHours? + fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .cachedPeerData(peerId: self.id) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? CachedPeerDataView else { + preconditionFailure() + } + if let cachedData = view.cachedPeerData as? CachedUserData { + return cachedData.businessHours + } else { + return nil + } + } + } + + public struct BusinessLocation: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { + public typealias Result = TelegramBusinessLocation? + + fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .cachedPeerData(peerId: self.id) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? CachedPeerDataView else { + preconditionFailure() + } + if let cachedData = view.cachedPeerData as? CachedUserData { + return cachedData.businessLocation + } else { + return nil + } + } + } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ForwardGame.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ForwardGame.swift index b61557dec8..f7e5d42833 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ForwardGame.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ForwardGame.swift @@ -14,7 +14,7 @@ func _internal_forwardGameWithScore(account: Account, messageId: MessageId, to p flags |= (1 << 13) } - return account.network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: fromInputPeer, id: [messageId.id], randomId: [Int64.random(in: Int64.min ... Int64.max)], toPeer: toInputPeer, topMsgId: threadId.flatMap { Int32(clamping: $0) }, scheduleDate: nil, sendAs: sendAsInputPeer)) + return account.network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: fromInputPeer, id: [messageId.id], randomId: [Int64.random(in: Int64.min ... Int64.max)], toPeer: toInputPeer, topMsgId: threadId.flatMap { Int32(clamping: $0) }, scheduleDate: nil, sendAs: sendAsInputPeer, quickReplyShortcut: nil)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift index 1ddb77458b..d7174c3e95 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift @@ -135,7 +135,7 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager pollMediaFlags |= 1 << 1 } - return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(flags: pollMediaFlags, poll: .poll(id: poll.pollId.id, flags: pollFlags, question: poll.text, answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil), correctAnswers: correctAnswers, solution: mappedSolution, solutionEntities: mappedSolutionEntities), replyMarkup: nil, entities: nil, scheduleDate: nil)) + return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(flags: pollMediaFlags, poll: .poll(id: poll.pollId.id, flags: pollFlags, question: poll.text, answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil), correctAnswers: correctAnswers, solution: mappedSolution, solutionEntities: mappedSolutionEntities), replyMarkup: nil, entities: nil, scheduleDate: nil, quickReplyShortcutId: nil)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/QuickReplyMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/QuickReplyMessages.swift new file mode 100644 index 0000000000..34dde0d272 --- /dev/null +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/QuickReplyMessages.swift @@ -0,0 +1,157 @@ +import Foundation +import Postbox +import SwiftSignalKit +import TelegramApi +import MtProtoKit + +public final class QuickReplyMessageShortcut: Codable, Equatable { + private final class CodableMessage: Codable { + let message: Message + + init(message: Message) { + self.message = message + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + var media: [Media] = [] + if let mediaData = try container.decodeIfPresent(Data.self, forKey: "media") { + if let value = PostboxDecoder(buffer: MemoryBuffer(data: mediaData)).decodeRootObject() as? Media { + media.append(value) + } + } + + var attributes: [MessageAttribute] = [] + if let attributesData = try container.decodeIfPresent([Data].self, forKey: "attributes") { + for attribute in attributesData { + if let value = PostboxDecoder(buffer: MemoryBuffer(data: attribute)).decodeRootObject() as? MessageAttribute { + attributes.append(value) + } + } + } + + self.message = Message( + stableId: 0, + stableVersion: 0, + id: MessageId(peerId: PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(0)), namespace: 0, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: 0, + flags: [], + tags: [], + globalTags: [], + localTags: [], + customTags: [], + forwardInfo: nil, + author: nil, + text: try container.decode(String.self, forKey: "text"), + attributes: attributes, + media: media, + peers: SimpleDictionary(), + associatedMessages: SimpleDictionary(), + associatedMessageIds: [], + associatedMedia: [:], + associatedThreadInfo: nil, + associatedStories: [:] + ) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + if let media = self.message.media.first { + let mediaEncoder = PostboxEncoder() + mediaEncoder.encodeRootObject(media) + try container.encode(mediaEncoder.makeData(), forKey: "media") + } + + var attributesData: [Data] = [] + for attribute in self.message.attributes { + let attributeEncoder = PostboxEncoder() + attributeEncoder.encodeRootObject(attribute) + attributesData.append(attributeEncoder.makeData()) + } + try container.encode(attributesData, forKey: "attributes") + + try container.encode(self.message.text, forKey: "text") + } + } + + public let id: Int32 + public let shortcut: String + public let messages: [EngineMessage] + + public init(id: Int32, shortcut: String, messages: [EngineMessage]) { + self.id = id + self.shortcut = shortcut + self.messages = messages + } + + public static func ==(lhs: QuickReplyMessageShortcut, rhs: QuickReplyMessageShortcut) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.shortcut != rhs.shortcut { + return false + } + if lhs.messages != rhs.messages { + return false + } + return true + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.id = try container.decode(Int32.self, forKey: "id") + self.shortcut = try container.decode(String.self, forKey: "shortcut") + self.messages = try container.decode([CodableMessage].self, forKey: "messages").map { EngineMessage($0.message) } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.id, forKey: "id") + try container.encode(self.shortcut, forKey: "shortcut") + try container.encode(self.messages.map { CodableMessage(message: $0._asMessage()) }, forKey: "messages") + } +} + +public final class QuickReplyMessageShortcutsState: Codable, Equatable { + public let shortcuts: [QuickReplyMessageShortcut] + + public init(shortcuts: [QuickReplyMessageShortcut]) { + self.shortcuts = shortcuts + } + + public static func ==(lhs: QuickReplyMessageShortcutsState, rhs: QuickReplyMessageShortcutsState) -> Bool { + if lhs.shortcuts != rhs.shortcuts { + return false + } + return true + } +} + +func _internal_shortcutMessages(account: Account) -> Signal { + let viewKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.shortcutMessages()])) + return account.postbox.combinedView(keys: [viewKey]) + |> map { views -> QuickReplyMessageShortcutsState in + guard let view = views.views[viewKey] as? PreferencesView else { + return QuickReplyMessageShortcutsState(shortcuts: []) + } + guard let value = view.values[PreferencesKeys.shortcutMessages()]?.get(QuickReplyMessageShortcutsState.self) else { + return QuickReplyMessageShortcutsState(shortcuts: []) + } + return value + } +} + +func _internal_updateShortcutMessages(account: Account, state: QuickReplyMessageShortcutsState) -> Signal { + return account.postbox.transaction { transaction -> Void in + transaction.setPreferencesEntry(key: PreferencesKeys.shortcutMessages(), value: PreferencesEntry(state)) + } + |> ignoreValues +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift index 81af3adfb1..eced71f7af 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift @@ -216,7 +216,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee let _ = accountUser switch fullUser { - case let .userFull(_, _, _, _, _, _, _, userFullNotifySettings, _, _, _, _, _, _, _, _, _, _, _, _): + case let .userFull(_, _, _, _, _, _, _, _, userFullNotifySettings, _, _, _, _, _, _, _, _, _, _, _, _, _, _): updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers) transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: userFullNotifySettings)]) } @@ -228,7 +228,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee previous = CachedUserData() } switch fullUser { - case let .userFull(userFullFlags, _, userFullAbout, userFullSettings, personalPhoto, profilePhoto, fallbackPhoto, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon, _, _, _, userPremiumGiftOptions, userWallpaper, stories): + case let .userFull(userFullFlags, _, _, userFullAbout, userFullSettings, personalPhoto, profilePhoto, fallbackPhoto, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon, _, _, _, userPremiumGiftOptions, userWallpaper, stories, businessWorkHours, businessLocation): let _ = stories let botInfo = userFullBotInfo.flatMap(BotInfo.init(apiBotInfo:)) let isBlocked = (userFullFlags & (1 << 0)) != 0 @@ -286,6 +286,16 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee let wallpaper = userWallpaper.flatMap { TelegramWallpaper(apiWallpaper: $0) } + var mappedBusinessHours: TelegramBusinessHours? + if let businessWorkHours { + mappedBusinessHours = TelegramBusinessHours(apiWorkingHours: businessWorkHours) + } + + var mappedBusinessLocation: TelegramBusinessLocation? + if let businessLocation { + mappedBusinessLocation = TelegramBusinessLocation(apiLocation: businessLocation) + } + return previous.withUpdatedAbout(userFullAbout) .withUpdatedBotInfo(botInfo) .withUpdatedEditableBotInfo(editableBotInfo) @@ -307,6 +317,8 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee .withUpdatedVoiceMessagesAvailable(voiceMessagesAvailable) .withUpdatedWallpaper(wallpaper) .withUpdatedFlags(flags) + .withUpdatedBusinessHours(mappedBusinessHours) + .withUpdatedBusinessLocation(mappedBusinessLocation) } }) } diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index d4068def28..cb3a0680f6 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -436,7 +436,7 @@ swift_library( "//submodules/TelegramUI/Components/Settings/ChatbotSetupScreen", "//submodules/TelegramUI/Components/Settings/BusinessLocationSetupScreen", "//submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen", - "//submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen", + "//submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen", ] + select({ "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "//build-system:ios_sim_arm64": [], diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift index 76bab24066..47f0d60b62 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift @@ -97,6 +97,8 @@ public final class ChatRecentActionsController: TelegramBaseController { }, sendContextResult: { _, _, _, _ in return false }, sendBotCommand: { _, _ in + }, sendShortcut: { _ in + }, openEditShortcuts: { }, sendBotStart: { _ in }, botSwitchChatWithPayload: { _, _ in }, beginMediaRecording: { _ in diff --git a/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListNavigationBar.swift b/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListNavigationBar.swift index 4f8e504ce4..d59b4fe772 100644 --- a/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListNavigationBar.swift +++ b/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListNavigationBar.swift @@ -27,6 +27,7 @@ public final class ChatListNavigationBar: Component { public let statusBarHeight: CGFloat public let sideInset: CGFloat public let isSearchActive: Bool + public let isSearchEnabled: Bool public let primaryContent: ChatListHeaderComponent.Content? public let secondaryContent: ChatListHeaderComponent.Content? public let secondaryTransition: CGFloat @@ -48,6 +49,7 @@ public final class ChatListNavigationBar: Component { statusBarHeight: CGFloat, sideInset: CGFloat, isSearchActive: Bool, + isSearchEnabled: Bool, primaryContent: ChatListHeaderComponent.Content?, secondaryContent: ChatListHeaderComponent.Content?, secondaryTransition: CGFloat, @@ -68,6 +70,7 @@ public final class ChatListNavigationBar: Component { self.statusBarHeight = statusBarHeight self.sideInset = sideInset self.isSearchActive = isSearchActive + self.isSearchEnabled = isSearchEnabled self.primaryContent = primaryContent self.secondaryContent = secondaryContent self.secondaryTransition = secondaryTransition @@ -102,6 +105,9 @@ public final class ChatListNavigationBar: Component { if lhs.isSearchActive != rhs.isSearchActive { return false } + if lhs.isSearchEnabled != rhs.isSearchEnabled { + return false + } if lhs.primaryContent != rhs.primaryContent { return false } @@ -316,6 +322,9 @@ public final class ChatListNavigationBar: Component { searchContentNode.updateLayout(size: searchSize, leftInset: component.sideInset, rightInset: component.sideInset, transition: transition.containedViewLayoutTransition) + transition.setAlpha(view: searchContentNode.view, alpha: component.isSearchEnabled ? 1.0 : 0.5) + searchContentNode.isUserInteractionEnabled = component.isSearchEnabled + let headerTransition = transition let storiesOffsetFraction: CGFloat @@ -520,6 +529,7 @@ public final class ChatListNavigationBar: Component { statusBarHeight: component.statusBarHeight, sideInset: component.sideInset, isSearchActive: component.isSearchActive, + isSearchEnabled: component.isSearchEnabled, primaryContent: component.primaryContent, secondaryContent: component.secondaryContent, secondaryTransition: component.secondaryTransition, diff --git a/submodules/TelegramUI/Components/ListMultilineTextFieldItemComponent/Sources/ListMultilineTextFieldItemComponent.swift b/submodules/TelegramUI/Components/ListMultilineTextFieldItemComponent/Sources/ListMultilineTextFieldItemComponent.swift index 5b1a14776e..6a7e63e973 100644 --- a/submodules/TelegramUI/Components/ListMultilineTextFieldItemComponent/Sources/ListMultilineTextFieldItemComponent.swift +++ b/submodules/TelegramUI/Components/ListMultilineTextFieldItemComponent/Sources/ListMultilineTextFieldItemComponent.swift @@ -29,6 +29,7 @@ public final class ListMultilineTextFieldItemComponent: Component { public let placeholder: String public let autocapitalizationType: UITextAutocapitalizationType public let autocorrectionType: UITextAutocorrectionType + public let characterLimit: Int? public let updated: ((String) -> Void)? public let tag: AnyObject? @@ -41,6 +42,7 @@ public final class ListMultilineTextFieldItemComponent: Component { placeholder: String, autocapitalizationType: UITextAutocapitalizationType = .sentences, autocorrectionType: UITextAutocorrectionType = .default, + characterLimit: Int? = nil, updated: ((String) -> Void)?, tag: AnyObject? = nil ) { @@ -52,6 +54,7 @@ public final class ListMultilineTextFieldItemComponent: Component { self.placeholder = placeholder self.autocapitalizationType = autocapitalizationType self.autocorrectionType = autocorrectionType + self.characterLimit = characterLimit self.updated = updated self.tag = tag } @@ -81,6 +84,9 @@ public final class ListMultilineTextFieldItemComponent: Component { if lhs.autocorrectionType != rhs.autocorrectionType { return false } + if lhs.characterLimit != rhs.characterLimit { + return false + } if (lhs.updated == nil) != (rhs.updated == nil) { return false } @@ -189,6 +195,7 @@ public final class ListMultilineTextFieldItemComponent: Component { return NSAttributedString(string: resetText.value, font: Font.regular(17.0), textColor: component.theme.list.itemPrimaryTextColor) }, isOneLineWhenUnfocused: false, + characterLimit: component.characterLimit, formatMenuAvailability: .none, lockedFormatAction: { }, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 575cb91b27..b25d2960a5 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -346,6 +346,8 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { }, sendContextResult: { _, _, _, _ in return false }, sendBotCommand: { _, _ in + }, sendShortcut: { _ in + }, openEditShortcuts: { }, sendBotStart: { _ in }, botSwitchChatWithPayload: { _, _ in }, beginMediaRecording: { _ in @@ -1162,6 +1164,91 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese interaction.requestLayout(false) })) } + + if let businessHours = cachedData.businessHours { + //TODO:localize + var businessHoursText: String = "" + let days = businessHours.splitIntoWeekDays() + for i in 0 ..< days.count { + let title: String + //TODO:localize + switch i { + case 0: + title = "Monday" + case 1: + title = "Tuesday" + case 2: + title = "Wednesday" + case 3: + title = "Thursday" + case 4: + title = "Friday" + case 5: + title = "Saturday" + case 6: + title = "Sunday" + default: + title = " " + } + + //TODO:localize + if !businessHoursText.isEmpty { + businessHoursText += "\n" + } + businessHoursText += "\(title): " + switch days[i] { + case .open: + businessHoursText += "open 24 hours" + case .closed: + businessHoursText += "closed" + case let .intervals(intervals): + func clipMinutes(_ value: Int) -> Int { + return value % (24 * 60) + } + + var resultText: String = "" + for range in intervals { + if !resultText.isEmpty { + resultText.append(", ") + } + let startHours = clipMinutes(range.startMinute) / 60 + let startMinutes = clipMinutes(range.startMinute) % 60 + let startText = stringForShortTimestamp(hours: Int32(startHours), minutes: Int32(startMinutes), dateTimeFormat: PresentationDateTimeFormat()) + let endHours = clipMinutes(range.endMinute) / 60 + let endMinutes = clipMinutes(range.endMinute) % 60 + let endText = stringForShortTimestamp(hours: Int32(endHours), minutes: Int32(endMinutes), dateTimeFormat: PresentationDateTimeFormat()) + resultText.append("\(startText)\u{00a0}- \(endText)") + } + businessHoursText += resultText + } + } + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 300, label: "business hours", text: businessHoursText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.isPremium ? enabledPublicBioEntities : enabledPrivateBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: { + interaction.requestLayout(false) + })) + } + + if let businessLocation = cachedData.businessLocation { + if let coordinates = businessLocation.coordinates { + let imageSignal = chatMapSnapshotImage(engine: context.engine, resource: MapSnapshotMediaResource(latitude: coordinates.latitude, longitude: coordinates.longitude, width: 90, height: 90)) + items[.peerInfo]!.append(PeerInfoScreenAddressItem( + id: 301, + label: "", + text: businessLocation.address, + imageSignal: imageSignal, + action: { + interaction.openLocation() + } + )) + } else { + items[.peerInfo]!.append(PeerInfoScreenAddressItem( + id: 301, + label: "", + text: businessLocation.address, + imageSignal: nil, + action: nil + )) + } + } } if let reactionSourceMessageId = reactionSourceMessageId, !data.isContact { items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 3, text: presentationData.strings.UserInfo_SendMessage, action: { @@ -7529,9 +7616,21 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } private func openLocation() { - guard let data = self.data, let peer = data.peer, let cachedData = data.cachedData as? CachedChannelData, let location = cachedData.peerGeoLocation else { + guard let data = self.data, let peer = data.peer else { return } + + var location: PeerGeoLocation? + if let cachedData = data.cachedData as? CachedChannelData, let locationValue = cachedData.peerGeoLocation { + location = locationValue + } else if let cachedData = data.cachedData as? CachedUserData, let businessLocation = cachedData.businessLocation, let coordinates = businessLocation.coordinates { + location = PeerGeoLocation(latitude: coordinates.latitude, longitude: coordinates.longitude, address: businessLocation.address) + } + + guard let location else { + return + } + let context = self.context let presentationData = self.presentationData let map = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: MapVenue(title: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), address: location.address, provider: nil, id: nil, type: nil), liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil) diff --git a/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift index a062fe259d..72859b0b55 100644 --- a/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift @@ -589,6 +589,8 @@ final class PeerSelectionControllerNode: ASDisplayNode { }, sendContextResult: { _, _, _, _ in return false }, sendBotCommand: { _, _ in + }, sendShortcut: { _ in + }, openEditShortcuts: { }, sendBotStart: { _ in }, botSwitchChatWithPayload: { _, _ in }, beginMediaRecording: { _ in diff --git a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/BUILD b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/BUILD similarity index 92% rename from submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/BUILD rename to submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/BUILD index 8ed69e1537..b64e56b028 100644 --- a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/BUILD +++ b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/BUILD @@ -1,8 +1,8 @@ load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") swift_library( - name = "GreetingMessageSetupScreen", - module_name = "GreetingMessageSetupScreen", + name = "AutomaticBusinessMessageSetupScreen", + module_name = "AutomaticBusinessMessageSetupScreen", srcs = glob([ "Sources/**/*.swift", ]), @@ -45,6 +45,7 @@ swift_library( "//submodules/DateSelectionUI", "//submodules/TelegramStringFormatting", "//submodules/TelegramUI/Components/TimeSelectionActionSheet", + "//submodules/TelegramUI/Components/ChatListHeaderComponent", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageListItemComponent.swift b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageListItemComponent.swift similarity index 99% rename from submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageListItemComponent.swift rename to submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageListItemComponent.swift index 1be73f5742..c1f380e630 100644 --- a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageListItemComponent.swift +++ b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageListItemComponent.swift @@ -235,6 +235,7 @@ final class GreetingMessageListItemComponent: Component { tags: [], customMessageListData: ChatListItemContent.CustomMessageListData( commandPrefix: nil, + searchQuery: nil, messageCount: component.count ) )), diff --git a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageSetupChatContents.swift b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageSetupChatContents.swift similarity index 99% rename from submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageSetupChatContents.swift rename to submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageSetupChatContents.swift index a9a0f9b304..6b233f77bc 100644 --- a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageSetupChatContents.swift +++ b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageSetupChatContents.swift @@ -5,7 +5,7 @@ import Postbox import TelegramCore import AccountContext -final class GreetingMessageSetupChatContents: ChatCustomContentsProtocol { +final class AutomaticBusinessMessageSetupChatContents: ChatCustomContentsProtocol { private final class Impl { let queue: Queue let context: AccountContext diff --git a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageSetupScreen.swift b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageSetupScreen.swift similarity index 97% rename from submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageSetupScreen.swift rename to submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageSetupScreen.swift index 5736c220f2..27e2488031 100644 --- a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/GreetingMessageSetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/AutomaticBusinessMessageSetupScreen.swift @@ -42,21 +42,21 @@ private let checkIcon: UIImage = { })!.withRenderingMode(.alwaysTemplate) }() -final class GreetingMessageSetupScreenComponent: Component { +final class AutomaticBusinessMessageSetupScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext - let mode: GreetingMessageSetupScreen.Mode + let mode: AutomaticBusinessMessageSetupScreen.Mode init( context: AccountContext, - mode: GreetingMessageSetupScreen.Mode + mode: AutomaticBusinessMessageSetupScreen.Mode ) { self.context = context self.mode = mode } - static func ==(lhs: GreetingMessageSetupScreenComponent, rhs: GreetingMessageSetupScreenComponent) -> Bool { + static func ==(lhs: AutomaticBusinessMessageSetupScreenComponent, rhs: AutomaticBusinessMessageSetupScreenComponent) -> Bool { if lhs.context !== rhs.context { return false } @@ -124,7 +124,7 @@ final class GreetingMessageSetupScreenComponent: Component { private var ignoreScrolling: Bool = false private var isUpdating: Bool = false - private var component: GreetingMessageSetupScreenComponent? + private var component: AutomaticBusinessMessageSetupScreenComponent? private(set) weak var state: EmptyComponentState? private var environment: EnvironmentType? @@ -350,7 +350,7 @@ final class GreetingMessageSetupScreenComponent: Component { guard let component = self.component else { return } - let contents = GreetingMessageSetupChatContents( + let contents = AutomaticBusinessMessageSetupChatContents( context: component.context, messages: self.messages, kind: component.mode == .away ? .awayMessageInput : .greetingMessageInput @@ -386,7 +386,8 @@ final class GreetingMessageSetupScreenComponent: Component { let currentValue: Date = (isStartTime ? self.customScheduleStart : self.customScheduleEnd) ?? Date() if isDate { - let calendar = Calendar.current + var calendar = Calendar(identifier: .gregorian) + calendar.timeZone = TimeZone(secondsFromGMT: 0)! let components = calendar.dateComponents([.year, .month, .day], from: currentValue) guard let clippedDate = calendar.date(from: components) else { return @@ -462,7 +463,7 @@ final class GreetingMessageSetupScreenComponent: Component { } } - func update(component: GreetingMessageSetupScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { + func update(component: AutomaticBusinessMessageSetupScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { self.isUpdating = true defer { self.isUpdating = false @@ -811,6 +812,7 @@ final class GreetingMessageSetupScreenComponent: Component { } var icon: ListActionItemComponent.Icon? + var accessory: ListActionItemComponent.Accessory? if let itemDate { let calendar = Calendar.current let hours = calendar.component(.hour, from: itemDate) @@ -861,6 +863,16 @@ final class GreetingMessageSetupScreenComponent: Component { animateScale: false ))) ], spacing: 4.0))), insets: .custom(UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0)), allowUserInteraction: true) + } else { + icon = ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: "Set", + font: Font.regular(presentationData.listsFontSize.baseDisplaySize), + textColor: environment.theme.list.itemSecondaryTextColor + )), + maximumNumberOfLines: 1 + )))) + accessory = .arrow } customScheduleSectionItems.append(AnyComponentWithIdentity(id: customScheduleSectionItems.count, component: AnyComponent(ListActionItemComponent( @@ -876,7 +888,7 @@ final class GreetingMessageSetupScreenComponent: Component { ))), ], alignment: .left, spacing: 2.0)), icon: icon, - accessory: nil, + accessory: accessory, action: itemDate != nil ? nil : { [weak self] _ in guard let self else { return @@ -1242,7 +1254,7 @@ final class GreetingMessageSetupScreenComponent: Component { } } -public final class GreetingMessageSetupScreen: ViewControllerComponentContainer { +public final class AutomaticBusinessMessageSetupScreen: ViewControllerComponentContainer { public enum Mode { case greeting case away @@ -1253,7 +1265,7 @@ public final class GreetingMessageSetupScreen: ViewControllerComponentContainer public init(context: AccountContext, mode: Mode) { self.context = context - super.init(context: context, component: GreetingMessageSetupScreenComponent( + super.init(context: context, component: AutomaticBusinessMessageSetupScreenComponent( context: context, mode: mode ), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil) @@ -1263,14 +1275,14 @@ public final class GreetingMessageSetupScreen: ViewControllerComponentContainer self.navigationItem.backBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) self.scrollToTop = { [weak self] in - guard let self, let componentView = self.node.hostView.componentView as? GreetingMessageSetupScreenComponent.View else { + guard let self, let componentView = self.node.hostView.componentView as? AutomaticBusinessMessageSetupScreenComponent.View else { return } componentView.scrollToTop() } self.attemptNavigation = { [weak self] complete in - guard let self, let componentView = self.node.hostView.componentView as? GreetingMessageSetupScreenComponent.View else { + guard let self, let componentView = self.node.hostView.componentView as? AutomaticBusinessMessageSetupScreenComponent.View else { return true } diff --git a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/QuickReplyEmptyStateComponent.swift b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplyEmptyStateComponent.swift similarity index 100% rename from submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/QuickReplyEmptyStateComponent.swift rename to submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplyEmptyStateComponent.swift diff --git a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/QuickReplySetupScreen.swift b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift similarity index 63% rename from submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/QuickReplySetupScreen.swift rename to submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift index 0b0303fb1c..e3eb272ea3 100644 --- a/submodules/TelegramUI/Components/Settings/GreetingMessageSetupScreen/Sources/QuickReplySetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift @@ -18,16 +18,20 @@ import ItemListPeerActionItem import ItemListUI import ChatListUI import QuickReplyNameAlertController +import ChatListHeaderComponent final class QuickReplySetupScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext + let initialData: QuickReplySetupScreen.InitialData init( - context: AccountContext + context: AccountContext, + initialData: QuickReplySetupScreen.InitialData ) { self.context = context + self.initialData = initialData } static func ==(lhs: QuickReplySetupScreenComponent, rhs: QuickReplySetupScreenComponent) -> Bool { @@ -38,16 +42,6 @@ final class QuickReplySetupScreenComponent: Component { return true } - private struct ShortcutItem: Equatable { - var shortcut: String - var messages: [EngineMessage] - - init(shortcut: String, messages: [EngineMessage]) { - self.shortcut = shortcut - self.messages = messages - } - } - private enum ContentEntry: Comparable, Identifiable { enum Id: Hashable { case add @@ -58,23 +52,23 @@ final class QuickReplySetupScreenComponent: Component { switch self { case .add: return .add - case let .item(item, _, _): + case let .item(item, _, _, _): return .item(item.shortcut) } } case add - case item(item: ShortcutItem, accountPeer: EnginePeer, sortIndex: Int) + case item(item: QuickReplyMessageShortcut, accountPeer: EnginePeer, sortIndex: Int, isEditing: Bool) static func <(lhs: ContentEntry, rhs: ContentEntry) -> Bool { switch lhs { case .add: return false - case let .item(lhsItem, _, lhsSortIndex): + case let .item(lhsItem, _, lhsSortIndex, _): switch rhs { case .add: return false - case let .item(rhsItem, _, rhsSortIndex): + case let .item(rhsItem, _, rhsSortIndex, _): if lhsSortIndex != rhsSortIndex { return lhsSortIndex < rhsSortIndex } @@ -106,7 +100,7 @@ final class QuickReplySetupScreenComponent: Component { parentView.openQuickReplyChat(shortcut: nil) } ) - case let .item(item, accountPeer, _): + case let .item(item, accountPeer, _, isEditing): let chatListNodeInteraction = ChatListNodeInteraction( context: listNode.context, animationCache: listNode.context.animationCache, @@ -235,10 +229,11 @@ final class QuickReplySetupScreenComponent: Component { tags: [], customMessageListData: ChatListItemContent.CustomMessageListData( commandPrefix: "/\(item.shortcut)", + searchQuery: nil, messageCount: nil ) )), - editing: false, + editing: isEditing, hasActiveRevealControls: false, selected: false, header: nil, @@ -285,11 +280,16 @@ final class QuickReplySetupScreenComponent: Component { let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(listNode: self), directionHint: nil) } let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(listNode: self), directionHint: nil) } + var options: ListViewDeleteAndInsertOptions = [.Synchronous, .LowLatency] + if animated { + options.insert(.AnimateInsertion) + } + self.transaction( deleteIndices: deletions, insertIndicesAndItems: insertions, updateIndicesAndItems: updates, - options: [.Synchronous, .LowLatency], + options: options, scrollToItem: nil, stationaryItemRange: nil, updateOpaqueState: nil, @@ -303,14 +303,20 @@ final class QuickReplySetupScreenComponent: Component { private var emptyState: ComponentView? private var contentListNode: ContentListNode? + private let navigationBarView = ComponentView() + private var navigationHeight: CGFloat? + private var isUpdating: Bool = false private var component: QuickReplySetupScreenComponent? private(set) weak var state: EmptyComponentState? private var environment: EnvironmentType? - private var items: [ShortcutItem] = [] + private var items: [QuickReplyMessageShortcut] = [] private var messagesDisposable: Disposable? + + private var isEditing: Bool = false + private var isSearchDisplayControllerActive: Bool = false private var accountPeer: EnginePeer? @@ -330,6 +336,10 @@ final class QuickReplySetupScreenComponent: Component { } func attemptNavigation(complete: @escaping () -> Void) -> Bool { + guard let component = self.component else { + return true + } + component.context.engine.accountData.updateShortcutMessages(state: QuickReplyMessageShortcutsState(shortcuts: self.items)) return true } @@ -339,9 +349,22 @@ final class QuickReplySetupScreenComponent: Component { } if let shortcut { - let contents = GreetingMessageSetupChatContents( + var mappedMessages: [EngineMessage] = [] + if let messages = self.items.first(where: { $0.shortcut == shortcut })?.messages { + var nextId: Int32 = 1 + for message in messages { + var mappedMessage = message._asMessage() + mappedMessage = mappedMessage.withUpdatedId(id: MessageId(peerId: component.context.account.peerId, namespace: 0, id: nextId)) + mappedMessage = mappedMessage.withUpdatedStableId(stableId: UInt32(nextId)) + mappedMessage = mappedMessage.withUpdatedTimestamp(nextId) + mappedMessages.append(EngineMessage(mappedMessage)) + + nextId += 1 + } + } + let contents = AutomaticBusinessMessageSetupChatContents( context: component.context, - messages: self.items.first(where: { $0.shortcut == shortcut })?.messages ?? [], + messages: mappedMessages, kind: .quickReplyMessageInput(shortcut: shortcut) ) let chatController = component.context.sharedContext.makeChatController( @@ -359,7 +382,7 @@ final class QuickReplySetupScreenComponent: Component { guard let self else { return } - let messages = messages.map(EngineMessage.init) + let messages = messages.reversed().map(EngineMessage.init) if messages.isEmpty { if let index = self.items.firstIndex(where: { $0.shortcut == shortcut }) { @@ -367,12 +390,9 @@ final class QuickReplySetupScreenComponent: Component { } } else { if let index = self.items.firstIndex(where: { $0.shortcut == shortcut }) { - self.items[index].messages = messages + self.items[index] = QuickReplyMessageShortcut(id: self.items[index].id, shortcut: self.items[index].shortcut, messages: messages) } else { - self.items.insert(ShortcutItem( - shortcut: shortcut, - messages: messages - ), at: 0) + self.items.insert(QuickReplyMessageShortcut(id: Int32.random(in: Int32.min ... Int32.max), shortcut: shortcut, messages: messages), at: 0) } } @@ -406,6 +426,147 @@ final class QuickReplySetupScreenComponent: Component { self.contentListNode?.clearHighlightAnimated(true) } + private func updateNavigationBar( + component: QuickReplySetupScreenComponent, + theme: PresentationTheme, + strings: PresentationStrings, + size: CGSize, + insets: UIEdgeInsets, + statusBarHeight: CGFloat, + transition: Transition, + deferScrollApplication: Bool + ) -> CGFloat { + var rightButtons: [AnyComponentWithIdentity] = [] + if self.isEditing { + rightButtons.append(AnyComponentWithIdentity(id: "done", component: AnyComponent(NavigationButtonComponent( + content: .text(title: strings.Common_Done, isBold: true), + pressed: { [weak self] _ in + guard let self else { + return + } + self.isEditing = false + self.state?.updated(transition: .spring(duration: 0.4)) + } + )))) + } else { + rightButtons.append(AnyComponentWithIdentity(id: "edit", component: AnyComponent(NavigationButtonComponent( + content: .text(title: strings.Common_Edit, isBold: false), + pressed: { [weak self] _ in + guard let self else { + return + } + self.isEditing = true + self.state?.updated(transition: .spring(duration: 0.4)) + } + )))) + } + let headerContent: ChatListHeaderComponent.Content? = ChatListHeaderComponent.Content( + title: "Quick Replies", + navigationBackTitle: nil, + titleComponent: nil, + chatListTitle: nil, + leftButton: nil, + rightButtons: rightButtons, + backTitle: "Back", + backPressed: { [weak self] in + guard let self else { + return + } + self.environment?.controller()?.dismiss() + } + ) + + let navigationBarSize = self.navigationBarView.update( + transition: transition, + component: AnyComponent(ChatListNavigationBar( + context: component.context, + theme: theme, + strings: strings, + statusBarHeight: statusBarHeight, + sideInset: insets.left, + isSearchActive: self.isSearchDisplayControllerActive, + isSearchEnabled: !self.isEditing, + primaryContent: headerContent, + secondaryContent: nil, + secondaryTransition: 0.0, + storySubscriptions: nil, + storiesIncludeHidden: false, + uploadProgress: [:], + tabsNode: nil, + tabsNodeIsSearch: false, + accessoryPanelContainer: nil, + accessoryPanelContainerHeight: 0.0, + activateSearch: { [weak self] searchContentNode in + guard let self else { + return + } + + self.isSearchDisplayControllerActive = true + self.state?.updated(transition: .spring(duration: 0.4)) + }, + openStatusSetup: { _ in + }, + allowAutomaticOrder: { + } + )), + environment: {}, + containerSize: size + ) + if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View { + if deferScrollApplication { + navigationBarComponentView.deferScrollApplication = true + } + + if navigationBarComponentView.superview == nil { + self.addSubview(navigationBarComponentView) + } + transition.setFrame(view: navigationBarComponentView, frame: CGRect(origin: CGPoint(), size: navigationBarSize)) + + return navigationBarSize.height + } else { + return 0.0 + } + } + + private func updateNavigationScrolling(navigationHeight: CGFloat, transition: Transition) { + var mainOffset: CGFloat + if self.items.isEmpty { + mainOffset = navigationHeight + } else { + if let contentListNode = self.contentListNode { + switch contentListNode.visibleContentOffset() { + case .none: + mainOffset = 0.0 + case .unknown: + mainOffset = navigationHeight + case let .known(value): + mainOffset = value + } + } else { + mainOffset = navigationHeight + } + } + + mainOffset = min(mainOffset, ChatListNavigationBar.searchScrollHeight) + if abs(mainOffset) < 0.1 { + mainOffset = 0.0 + } + + let resultingOffset = mainOffset + + var offset = resultingOffset + if self.isSearchDisplayControllerActive { + offset = 0.0 + } + + if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View { + navigationBarComponentView.applyScroll(offset: offset, allowAvatarsExpansion: false, forceUpdate: false, transition: transition.withUserData(ChatListNavigationBar.AnimationHint( + disableStoriesAnimations: false, + crossfadeStoryPeers: false + ))) + } + } + func update(component: QuickReplySetupScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { self.isUpdating = true defer { @@ -413,15 +574,8 @@ final class QuickReplySetupScreenComponent: Component { } if self.component == nil { - let _ = (component.context.engine.data.get( - TelegramEngine.EngineData.Item.Peer.Peer(id: component.context.account.peerId) - ) - |> deliverOnMainQueue).start(next: { [weak self] peer in - guard let self else { - return - } - self.accountPeer = peer - }) + self.accountPeer = component.initialData.accountPeer + self.items = component.initialData.shortcutMessages.shortcuts } let environment = environment[EnvironmentType.self].value @@ -479,29 +633,64 @@ final class QuickReplySetupScreenComponent: Component { } } + let navigationHeight = self.updateNavigationBar( + component: component, + theme: environment.theme, + strings: environment.strings, + size: availableSize, + insets: environment.safeInsets, + statusBarHeight: environment.statusBarHeight, + transition: transition, + deferScrollApplication: true + ) + self.navigationHeight = navigationHeight + let contentListNode: ContentListNode if let current = self.contentListNode { contentListNode = current } else { contentListNode = ContentListNode(parentView: self, context: component.context) self.contentListNode = contentListNode - self.addSubview(contentListNode.view) + + contentListNode.visibleContentOffsetChanged = { [weak self] offset in + guard let self else { + return + } + guard let navigationHeight = self.navigationHeight else { + return + } + + self.updateNavigationScrolling(navigationHeight: navigationHeight, transition: .immediate) + } + + if let navigationBarComponentView = self.navigationBarView.view { + self.insertSubview(contentListNode.view, belowSubview: navigationBarComponentView) + } else { + self.addSubview(contentListNode.view) + } } transition.setFrame(view: contentListNode.view, frame: CGRect(origin: CGPoint(), size: availableSize)) - contentListNode.update(size: availableSize, insets: UIEdgeInsets(top: environment.navigationHeight, left: environment.safeInsets.left, bottom: environment.safeInsets.bottom, right: environment.safeInsets.right), transition: transition) + contentListNode.update(size: availableSize, insets: UIEdgeInsets(top: navigationHeight, left: environment.safeInsets.left, bottom: environment.safeInsets.bottom, right: environment.safeInsets.right), transition: transition) var entries: [ContentEntry] = [] if let accountPeer = self.accountPeer { entries.append(.add) for item in self.items { - entries.append(.item(item: item, accountPeer: accountPeer, sortIndex: entries.count)) + entries.append(.item(item: item, accountPeer: accountPeer, sortIndex: entries.count, isEditing: self.isEditing)) } } - contentListNode.setEntries(entries: entries, animated: false) + contentListNode.setEntries(entries: entries, animated: !transition.animation.isImmediate) contentListNode.isHidden = self.items.isEmpty + self.updateNavigationScrolling(navigationHeight: navigationHeight, transition: transition) + + if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View { + navigationBarComponentView.deferScrollApplication = false + navigationBarComponentView.applyCurrentScroll(transition: transition) + } + return availableSize } } @@ -516,19 +705,28 @@ final class QuickReplySetupScreenComponent: Component { } public final class QuickReplySetupScreen: ViewControllerComponentContainer { + public final class InitialData: QuickReplySetupScreenInitialData { + let accountPeer: EnginePeer? + let shortcutMessages: QuickReplyMessageShortcutsState + + init( + accountPeer: EnginePeer?, + shortcutMessages: QuickReplyMessageShortcutsState + ) { + self.accountPeer = accountPeer + self.shortcutMessages = shortcutMessages + } + } + private let context: AccountContext - public init(context: AccountContext) { + public init(context: AccountContext, initialData: InitialData) { self.context = context super.init(context: context, component: QuickReplySetupScreenComponent( - context: context - ), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil) - - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - //TODO:localize - self.title = "Quick Replies" - self.navigationItem.backBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) + context: context, + initialData: initialData + ), navigationBarAppearance: .none, theme: .default, updatedPresentationData: nil) self.scrollToTop = { [weak self] in guard let self, let componentView = self.node.hostView.componentView as? QuickReplySetupScreenComponent.View else { @@ -560,4 +758,20 @@ public final class QuickReplySetupScreen: ViewControllerComponentContainer { override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) } + + public static func initialData(context: AccountContext) -> Signal { + return combineLatest( + context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId) + ), + context.engine.accountData.shortcutMessages() + |> take(1) + ) + |> map { accountPeer, shortcutMessages -> QuickReplySetupScreenInitialData in + return InitialData( + accountPeer: accountPeer, + shortcutMessages: shortcutMessages + ) + } + } } diff --git a/submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen/Sources/BusinessDaySetupScreen.swift b/submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen/Sources/BusinessDaySetupScreen.swift index d9fb9ed638..a147d2b61f 100644 --- a/submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen/Sources/BusinessDaySetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen/Sources/BusinessDaySetupScreen.swift @@ -23,6 +23,10 @@ import TelegramStringFormatting import PlainButtonComponent import TimeSelectionActionSheet +func clipMinutes(_ value: Int) -> Int { + return value % (24 * 60) +} + final class BusinessDaySetupScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -157,7 +161,7 @@ final class BusinessDaySetupScreenComponent: Component { return } - let controller = TimeSelectionActionSheet(context: component.context, currentValue: Int32(isStartTime ? range.startTime : range.endTime), applyValue: { [weak self] value in + let controller = TimeSelectionActionSheet(context: component.context, currentValue: Int32(isStartTime ? clipMinutes(range.startMinute) : clipMinutes(range.endMinute)) * 60, applyValue: { [weak self] value in guard let self else { return } @@ -165,17 +169,30 @@ final class BusinessDaySetupScreenComponent: Component { return } if let index = self.ranges.firstIndex(where: { $0.id == rangeId }) { + var startMinute = range.startMinute + var endMinute = range.endMinute if isStartTime { - self.ranges[index].startTime = Int(value) + startMinute = Int(value) / 60 } else { - self.ranges[index].endTime = Int(value) + endMinute = Int(value) / 60 } + if endMinute < startMinute { + endMinute = endMinute + 24 * 60 + } + self.ranges[index].startMinute = startMinute + self.ranges[index].endMinute = endMinute + self.validateRanges() + self.state?.updated(transition: .immediate) } }) self.environment?.controller()?.present(controller, in: .window(.root)) } + private func validateRanges() { + self.ranges.sort(by: { $0.startMinute < $1.startMinute }) + } + func update(component: BusinessDaySetupScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { self.isUpdating = true defer { @@ -190,6 +207,7 @@ final class BusinessDaySetupScreenComponent: Component { self.isOpen = component.day.ranges != nil self.ranges = component.day.ranges ?? [] self.nextRangeId = (self.ranges.map(\.id).max() ?? 0) + 1 + self.validateRanges() } self.component = component @@ -309,11 +327,11 @@ final class BusinessDaySetupScreenComponent: Component { rangeSectionTransition = rangeSectionTransition.withAnimation(.none) } - let startHours = range.startTime / (60 * 60) - let startMinutes = range.startTime % (60 * 60) + let startHours = clipMinutes(range.startMinute) / 60 + let startMinutes = clipMinutes(range.startMinute) % 60 let startText = stringForShortTimestamp(hours: Int32(startHours), minutes: Int32(startMinutes), dateTimeFormat: PresentationDateTimeFormat()) - let endHours = range.endTime / (60 * 60) - let endMinutes = range.endTime % (60 * 60) + let endHours = clipMinutes(range.endMinute) / 60 + let endMinutes = clipMinutes(range.endMinute) % 60 let endText = stringForShortTimestamp(hours: Int32(endHours), minutes: Int32(endMinutes), dateTimeFormat: PresentationDateTimeFormat()) var rangeSectionItems: [AnyComponentWithIdentity] = [] @@ -409,6 +427,7 @@ final class BusinessDaySetupScreenComponent: Component { return } self.ranges.removeAll(where: { $0.id == rangeId }) + self.validateRanges() self.state?.updated(transition: .spring(duration: 0.4)) } )))) @@ -473,6 +492,11 @@ final class BusinessDaySetupScreenComponent: Component { self.rangeSections.removeValue(forKey: id) } + var canAddRanges = true + if let lastRange = self.ranges.last, lastRange.endMinute >= 24 * 60 * 2 - 1 { + canAddRanges = false + } + //TODO:localize let addSectionSize = self.addSection.update( transition: transition, @@ -509,10 +533,22 @@ final class BusinessDaySetupScreenComponent: Component { guard let self else { return } + + var rangeStart = 9 * 60 + if let lastRange = self.ranges.last { + rangeStart = lastRange.endMinute + 1 + } + if rangeStart >= 2 * 24 * 60 - 1 { + return + } + let rangeEnd = min(rangeStart + 9 * 60, 2 * 24 * 60) + let rangeId = self.nextRangeId self.nextRangeId += 1 + self.ranges.append(BusinessHoursSetupScreenComponent.WorkingHourRange( - id: rangeId, startTime: 9 * (60 * 60), endTime: 18 * (60 * 60))) + id: rangeId, startMinute: rangeStart, endMinute: rangeEnd)) + self.validateRanges() self.state?.updated(transition: .spring(duration: 0.4)) } ))) @@ -529,9 +565,11 @@ final class BusinessDaySetupScreenComponent: Component { transition.setFrame(view: addSectionView, frame: addSectionFrame) let alphaTransition = transition.animation.isImmediate ? transition : .easeInOut(duration: 0.25) - alphaTransition.setAlpha(view: addSectionView, alpha: self.isOpen ? 1.0 : 0.0) + alphaTransition.setAlpha(view: addSectionView, alpha: (self.isOpen && canAddRanges) ? 1.0 : 0.0) + } + if canAddRanges { + rangesSectionsHeight += addSectionSize.height } - rangesSectionsHeight += addSectionSize.height if self.isOpen { contentHeight += rangesSectionsHeight diff --git a/submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen/Sources/BusinessHoursSetupScreen.swift b/submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen/Sources/BusinessHoursSetupScreen.swift index 773cafe10f..fb5ffcfabc 100644 --- a/submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen/Sources/BusinessHoursSetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/BusinessHoursSetupScreen/Sources/BusinessHoursSetupScreen.swift @@ -26,17 +26,26 @@ final class BusinessHoursSetupScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext + let initialValue: TelegramBusinessHours? + let completion: (TelegramBusinessHours?) -> Void init( - context: AccountContext + context: AccountContext, + initialValue: TelegramBusinessHours?, + completion: @escaping (TelegramBusinessHours?) -> Void ) { self.context = context + self.initialValue = initialValue + self.completion = completion } static func ==(lhs: BusinessHoursSetupScreenComponent, rhs: BusinessHoursSetupScreenComponent) -> Bool { if lhs.context !== rhs.context { return false } + if lhs.initialValue != rhs.initialValue { + return false + } return true } @@ -49,13 +58,13 @@ final class BusinessHoursSetupScreenComponent: Component { struct WorkingHourRange: Equatable { var id: Int - var startTime: Int - var endTime: Int + var startMinute: Int + var endMinute: Int - init(id: Int, startTime: Int, endTime: Int) { + init(id: Int, startMinute: Int, endMinute: Int) { self.id = id - self.startTime = startTime - self.endTime = endTime + self.startMinute = startMinute + self.endMinute = endMinute } } @@ -67,6 +76,74 @@ final class BusinessHoursSetupScreenComponent: Component { } } + struct DaysState: Equatable { + enum ValidationError: Error { + case intersectingRanges + } + + var timezoneId: String + var days: [Day] + + init(timezoneId: String, days: [Day]) { + self.timezoneId = timezoneId + self.days = days + } + + init(businessHours: TelegramBusinessHours) { + self.timezoneId = businessHours.timezoneId + + self.days = businessHours.splitIntoWeekDays().map { day in + switch day { + case .closed: + return Day(ranges: nil) + case .open: + return Day(ranges: []) + case let .intervals(intervals): + var nextIntervalId = 0 + return Day(ranges: intervals.map { interval in + let intervalId = nextIntervalId + nextIntervalId += 1 + return WorkingHourRange(id: intervalId, startMinute: interval.startMinute, endMinute: interval.endMinute) + }) + } + } + } + + func asBusinessHours() throws -> TelegramBusinessHours { + var mappedIntervals: [TelegramBusinessHours.WorkingTimeInterval] = [] + + var filledMinutes = IndexSet() + for i in 0 ..< self.days.count { + let dayStartMinute = i * 24 * 60 + guard var effectiveRanges = self.days[i].ranges else { + continue + } + if effectiveRanges.isEmpty { + effectiveRanges = [WorkingHourRange(id: 0, startMinute: 0, endMinute: 24 * 60)] + } + for range in effectiveRanges { + let minuteRange: Range = (dayStartMinute + range.startMinute) ..< (dayStartMinute + range.endMinute) + + var wrappedMinutes = IndexSet() + if minuteRange.upperBound > 7 * 24 * 60 { + wrappedMinutes.insert(integersIn: minuteRange.lowerBound ..< 7 * 24 * 60) + wrappedMinutes.insert(integersIn: 0 ..< (7 * 24 * 60 - minuteRange.upperBound)) + } else { + wrappedMinutes.insert(integersIn: minuteRange) + } + + if !filledMinutes.intersection(wrappedMinutes).isEmpty { + throw ValidationError.intersectingRanges + } + filledMinutes.formUnion(wrappedMinutes) + mappedIntervals.append(TelegramBusinessHours.WorkingTimeInterval(startMinute: minuteRange.lowerBound, endMinute: minuteRange.upperBound)) + } + } + + return TelegramBusinessHours(timezoneId: self.timezoneId, weeklyTimeIntervals: mappedIntervals) + } + } + final class View: UIView, UIScrollViewDelegate { private let topOverscrollLayer = SimpleLayer() private let scrollView: ScrollView @@ -86,8 +163,7 @@ final class BusinessHoursSetupScreenComponent: Component { private var environment: EnvironmentType? private var showHours: Bool = false - private var days: [Day] = [] - private var timezoneId: String + private var daysState = DaysState(timezoneId: "", days: []) override init(frame: CGRect) { self.scrollView = ScrollView() @@ -102,18 +178,12 @@ final class BusinessHoursSetupScreenComponent: Component { } self.scrollView.alwaysBounceVertical = true - self.timezoneId = TimeZone.current.identifier - super.init(frame: frame) self.scrollView.delegate = self self.addSubview(self.scrollView) self.scrollView.layer.addSublayer(self.topOverscrollLayer) - - self.days = (0 ..< 7).map { _ in - return Day(ranges: []) - } } required init?(coder: NSCoder) { @@ -128,7 +198,28 @@ final class BusinessHoursSetupScreenComponent: Component { } func attemptNavigation(complete: @escaping () -> Void) -> Bool { - return true + guard let component = self.component else { + return true + } + + if self.showHours { + do { + let businessHours = try self.daysState.asBusinessHours() + let _ = component.context.engine.accountData.updateAccountBusinessHours(businessHours: businessHours).startStandalone() + return true + } catch let error { + let _ = error + //TODO:localize + return false + } + } else { + if component.initialValue != nil { + let _ = component.context.engine.accountData.updateAccountBusinessHours(businessHours: nil).startStandalone() + return true + } else { + return true + } + } } func scrollViewDidScroll(_ scrollView: UIScrollView) { @@ -173,6 +264,19 @@ final class BusinessHoursSetupScreenComponent: Component { self.isUpdating = false } + if self.component == nil { + if let initialValue = component.initialValue { + self.showHours = true + self.daysState = DaysState(businessHours: initialValue) + } else { + self.showHours = false + self.daysState.timezoneId = TimeZone.current.identifier + self.daysState.days = (0 ..< 7).map { _ in + return Day(ranges: []) + } + } + } + let environment = environment[EnvironmentType.self].value let themeUpdated = self.environment?.theme !== environment.theme self.environment = environment @@ -331,7 +435,7 @@ final class BusinessHoursSetupScreenComponent: Component { var daysContentHeight: CGFloat = 0.0 var daysSectionItems: [AnyComponentWithIdentity] = [] - for day in self.days { + for day in self.daysState.days { let dayIndex = daysSectionItems.count let title: String @@ -356,7 +460,7 @@ final class BusinessHoursSetupScreenComponent: Component { } let subtitle: String - if let ranges = self.days[dayIndex].ranges { + if let ranges = self.daysState.days[dayIndex].ranges { if ranges.isEmpty { subtitle = "Open 24 Hours" } else { @@ -365,11 +469,11 @@ final class BusinessHoursSetupScreenComponent: Component { if !resultText.isEmpty { resultText.append(", ") } - let startHours = range.startTime / (60 * 60) - let startMinutes = range.startTime % (60 * 60) + let startHours = clipMinutes(range.startMinute) / 60 + let startMinutes = clipMinutes(range.startMinute) % 60 let startText = stringForShortTimestamp(hours: Int32(startHours), minutes: Int32(startMinutes), dateTimeFormat: PresentationDateTimeFormat()) - let endHours = range.endTime / (60 * 60) - let endMinutes = range.endTime % (60 * 60) + let endHours = clipMinutes(range.endMinute) / 60 + let endMinutes = clipMinutes(range.endMinute) % 60 let endText = stringForShortTimestamp(hours: Int32(endHours), minutes: Int32(endMinutes), dateTimeFormat: PresentationDateTimeFormat()) resultText.append("\(startText)\u{00a0}- \(endText)") } @@ -403,11 +507,11 @@ final class BusinessHoursSetupScreenComponent: Component { guard let self else { return } - if dayIndex < self.days.count { - if self.days[dayIndex].ranges == nil { - self.days[dayIndex].ranges = [] + if dayIndex < self.daysState.days.count { + if self.daysState.days[dayIndex].ranges == nil { + self.daysState.days[dayIndex].ranges = [] } else { - self.days[dayIndex].ranges = nil + self.daysState.days[dayIndex].ranges = nil } } self.state?.updated(transition: .immediate) @@ -419,13 +523,13 @@ final class BusinessHoursSetupScreenComponent: Component { self.environment?.controller()?.push(BusinessDaySetupScreen( context: component.context, dayIndex: dayIndex, - day: self.days[dayIndex], + day: self.daysState.days[dayIndex], updateDay: { [weak self] day in guard let self else { return } - if self.days[dayIndex] != day { - self.days[dayIndex] = day + if self.daysState.days[dayIndex] != day { + self.daysState.days[dayIndex] = day self.state?.updated(transition: .immediate) } } @@ -484,7 +588,7 @@ final class BusinessHoursSetupScreenComponent: Component { )), icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( - string: TimeZone(identifier: self.timezoneId)?.localizedName(for: .shortStandard, locale: Locale.current) ?? self.timezoneId, + string: TimeZone(identifier: self.daysState.timezoneId)?.localizedName(for: .shortStandard, locale: Locale.current) ?? self.daysState.timezoneId, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemSecondaryTextColor )), @@ -506,7 +610,7 @@ final class BusinessHoursSetupScreenComponent: Component { controller?.dismiss() return } - self.timezoneId = timezoneId + self.daysState.timezoneId = timezoneId self.state?.updated(transition: .immediate) controller?.dismiss() } @@ -579,11 +683,13 @@ final class BusinessHoursSetupScreenComponent: Component { public final class BusinessHoursSetupScreen: ViewControllerComponentContainer { private let context: AccountContext - public init(context: AccountContext) { + public init(context: AccountContext, initialValue: TelegramBusinessHours?, completion: @escaping (TelegramBusinessHours?) -> Void) { self.context = context super.init(context: context, component: BusinessHoursSetupScreenComponent( - context: context + context: context, + initialValue: initialValue, + completion: completion ), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil) let presentationData = context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/TelegramUI/Components/Settings/BusinessLocationSetupScreen/Sources/BusinessLocationSetupScreen.swift b/submodules/TelegramUI/Components/Settings/BusinessLocationSetupScreen/Sources/BusinessLocationSetupScreen.swift index d61e642db3..f3b2410cd2 100644 --- a/submodules/TelegramUI/Components/Settings/BusinessLocationSetupScreen/Sources/BusinessLocationSetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/BusinessLocationSetupScreen/Sources/BusinessLocationSetupScreen.swift @@ -25,17 +25,26 @@ final class BusinessLocationSetupScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext + let initialValue: TelegramBusinessLocation? + let completion: (TelegramBusinessLocation?) -> Void init( - context: AccountContext + context: AccountContext, + initialValue: TelegramBusinessLocation?, + completion: @escaping (TelegramBusinessLocation?) -> Void ) { self.context = context + self.initialValue = initialValue + self.completion = completion } static func ==(lhs: BusinessLocationSetupScreenComponent, rhs: BusinessLocationSetupScreenComponent) -> Bool { if lhs.context !== rhs.context { return false } + if lhs.initialValue != rhs.initialValue { + return false + } return true } @@ -65,7 +74,7 @@ final class BusinessLocationSetupScreenComponent: Component { private let textFieldTag = NSObject() private var resetAddressText: String? - private var mapCoordinates: (Double, Double)? + private var mapCoordinates: TelegramBusinessLocation.Coordinates? override init(frame: CGRect) { self.scrollView = ScrollView() @@ -100,6 +109,20 @@ final class BusinessLocationSetupScreenComponent: Component { } func attemptNavigation(complete: @escaping () -> Void) -> Bool { + if let component = self.component { + var address = "" + if let textView = self.addressSection.findTaggedView(tag: self.textFieldTag) as? ListMultilineTextFieldItemComponent.View { + address = textView.currentText + } + + var businessLocation: TelegramBusinessLocation? + if !address.isEmpty || self.mapCoordinates != nil { + businessLocation = TelegramBusinessLocation(address: address, coordinates: self.mapCoordinates) + } + + let _ = component.context.engine.accountData.updateAccountBusinessLocation(businessLocation: businessLocation).startStandalone() + } + return true } @@ -147,7 +170,7 @@ final class BusinessLocationSetupScreenComponent: Component { return } - self.mapCoordinates = (location.latitude, location.longitude) + self.mapCoordinates = TelegramBusinessLocation.Coordinates(latitude: location.latitude, longitude: location.longitude) if let textView = self.addressSection.findTaggedView(tag: self.textFieldTag) as? ListMultilineTextFieldItemComponent.View, textView.currentText.isEmpty { self.resetAddressText = address } @@ -163,6 +186,13 @@ final class BusinessLocationSetupScreenComponent: Component { self.isUpdating = false } + if self.component == nil { + if let initialValue = component.initialValue { + self.mapCoordinates = initialValue.coordinates + self.resetAddressText = initialValue.address + } + } + let environment = environment[EnvironmentType.self].value let themeUpdated = self.environment?.theme !== environment.theme self.environment = environment @@ -286,6 +316,7 @@ final class BusinessLocationSetupScreenComponent: Component { placeholder: "Enter Address", autocapitalizationType: .none, autocorrectionType: .no, + characterLimit: 64, updated: { [weak self] value in guard let self else { return @@ -351,8 +382,8 @@ final class BusinessLocationSetupScreenComponent: Component { mapSectionItems.append(AnyComponentWithIdentity(id: 1, component: AnyComponent(MapPreviewComponent( theme: environment.theme, location: MapPreviewComponent.Location( - latitude: mapCoordinates.0, - longitude: mapCoordinates.1 + latitude: mapCoordinates.latitude, + longitude: mapCoordinates.longitude ), action: { [weak self] in guard let self else { @@ -430,11 +461,17 @@ final class BusinessLocationSetupScreenComponent: Component { public final class BusinessLocationSetupScreen: ViewControllerComponentContainer { private let context: AccountContext - public init(context: AccountContext) { + public init( + context: AccountContext, + initialValue: TelegramBusinessLocation?, + completion: @escaping (TelegramBusinessLocation?) -> Void + ) { self.context = context super.init(context: context, component: BusinessLocationSetupScreenComponent( - context: context + context: context, + initialValue: initialValue, + completion: completion ), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil) let presentationData = context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/TelegramUI/Components/Settings/BusinessSetupScreen/Sources/BusinessSetupScreen.swift b/submodules/TelegramUI/Components/Settings/BusinessSetupScreen/Sources/BusinessSetupScreen.swift index 473a158b55..321e821184 100644 --- a/submodules/TelegramUI/Components/Settings/BusinessSetupScreen/Sources/BusinessSetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/BusinessSetupScreen/Sources/BusinessSetupScreen.swift @@ -59,6 +59,10 @@ final class BusinessSetupScreenComponent: Component { private(set) weak var state: EmptyComponentState? private var environment: EnvironmentType? + private var businessHours: TelegramBusinessHours? + private var businessLocation: TelegramBusinessLocation? + private var dataDisposable: Disposable? + override init(frame: CGRect) { self.scrollView = ScrollView() self.scrollView.showsVerticalScrollIndicator = true @@ -85,6 +89,7 @@ final class BusinessSetupScreenComponent: Component { } deinit { + self.dataDisposable?.dispose() } func scrollToTop() { @@ -139,6 +144,20 @@ final class BusinessSetupScreenComponent: Component { self.isUpdating = false } + if self.dataDisposable == nil { + self.dataDisposable = (component.context.engine.data.subscribe( + TelegramEngine.EngineData.Item.Peer.BusinessHours(id: component.context.account.peerId), + TelegramEngine.EngineData.Item.Peer.BusinessLocation(id: component.context.account.peerId) + ) + |> deliverOnMainQueue).start(next: { [weak self] businessHours, businessLocation in + guard let self else { + return + } + self.businessHours = businessHours + self.businessLocation = businessLocation + }) + } + let environment = environment[EnvironmentType.self].value let themeUpdated = self.environment?.theme !== environment.theme self.environment = environment @@ -245,7 +264,8 @@ final class BusinessSetupScreenComponent: Component { guard let self else { return } - self.environment?.controller()?.push(component.context.sharedContext.makeBusinessLocationSetupScreen(context: component.context)) + self.environment?.controller()?.push(component.context.sharedContext.makeBusinessLocationSetupScreen(context: component.context, initialValue: self.businessLocation, completion: { _ in + })) } )) items.append(Item( @@ -256,7 +276,7 @@ final class BusinessSetupScreenComponent: Component { guard let self else { return } - self.environment?.controller()?.push(component.context.sharedContext.makeBusinessHoursSetupScreen(context: component.context)) + self.environment?.controller()?.push(component.context.sharedContext.makeBusinessHoursSetupScreen(context: component.context, initialValue: self.businessHours, completion: { _ in })) } )) items.append(Item( @@ -264,10 +284,19 @@ final class BusinessSetupScreenComponent: Component { title: "Quick Replies", subtitle: "Set up shortcuts with rich text and media to respond to messages faster.", action: { [weak self] in - guard let self, let component = self.component, let environment = self.environment else { + guard let self, let component = self.component else { return } - environment.controller()?.push(component.context.sharedContext.makeQuickReplySetupScreen(context: component.context)) + + let _ = (component.context.sharedContext.makeQuickReplySetupScreenInitialData(context: component.context) + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] initialData in + guard let self, let component = self.component, let environment = self.environment else { + return + } + + environment.controller()?.push(component.context.sharedContext.makeQuickReplySetupScreen(context: component.context, initialData: initialData)) + }) } )) items.append(Item( @@ -278,7 +307,7 @@ final class BusinessSetupScreenComponent: Component { guard let self, let component = self.component, let environment = self.environment else { return } - environment.controller()?.push(component.context.sharedContext.makeGreetingMessageSetupScreen(context: component.context, isAwayMode: false)) + environment.controller()?.push(component.context.sharedContext.makeAutomaticBusinessMessageSetupScreen(context: component.context, isAwayMode: false)) } )) items.append(Item( @@ -289,7 +318,7 @@ final class BusinessSetupScreenComponent: Component { guard let self, let component = self.component, let environment = self.environment else { return } - environment.controller()?.push(component.context.sharedContext.makeGreetingMessageSetupScreen(context: component.context, isAwayMode: true)) + environment.controller()?.push(component.context.sharedContext.makeAutomaticBusinessMessageSetupScreen(context: component.context, isAwayMode: true)) } )) items.append(Item( diff --git a/submodules/TelegramUI/Components/TextFieldComponent/Sources/TextFieldComponent.swift b/submodules/TelegramUI/Components/TextFieldComponent/Sources/TextFieldComponent.swift index c839cf5eee..4ba8b431ac 100644 --- a/submodules/TelegramUI/Components/TextFieldComponent/Sources/TextFieldComponent.swift +++ b/submodules/TelegramUI/Components/TextFieldComponent/Sources/TextFieldComponent.swift @@ -96,6 +96,7 @@ public final class TextFieldComponent: Component { public let customInputView: UIView? public let resetText: NSAttributedString? public let isOneLineWhenUnfocused: Bool + public let characterLimit: Int? public let formatMenuAvailability: FormatMenuAvailability public let lockedFormatAction: () -> Void public let present: (ViewController) -> Void @@ -112,6 +113,7 @@ public final class TextFieldComponent: Component { customInputView: UIView?, resetText: NSAttributedString?, isOneLineWhenUnfocused: Bool, + characterLimit: Int? = nil, formatMenuAvailability: FormatMenuAvailability, lockedFormatAction: @escaping () -> Void, present: @escaping (ViewController) -> Void, @@ -127,6 +129,7 @@ public final class TextFieldComponent: Component { self.customInputView = customInputView self.resetText = resetText self.isOneLineWhenUnfocused = isOneLineWhenUnfocused + self.characterLimit = characterLimit self.formatMenuAvailability = formatMenuAvailability self.lockedFormatAction = lockedFormatAction self.present = present @@ -161,6 +164,9 @@ public final class TextFieldComponent: Component { if lhs.isOneLineWhenUnfocused != rhs.isOneLineWhenUnfocused { return false } + if lhs.characterLimit != rhs.characterLimit { + return false + } if lhs.formatMenuAvailability != rhs.formatMenuAvailability { return false } @@ -537,6 +543,17 @@ public final class TextFieldComponent: Component { } public func chatInputTextNode(shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + guard let component = self.component else { + return true + } + if let characterLimit = component.characterLimit { + let string = self.inputState.inputText.string as NSString + let updatedString = string.replacingCharacters(in: range, with: text) + if (updatedString as NSString).length > characterLimit { + return false + } + } + return true } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index a96ee7d2a1..a769e8a21f 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -9460,6 +9460,56 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } } + }, sendShortcut: { [weak self] shortcut in + guard let self else { + return + } + + self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in + guard let self else { + return + } + self.updateChatPresentationInterfaceState(animated: true, interactive: false, { + $0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))).withUpdatedComposeDisableUrlPreviews([]) } + }) + }, nil) + + var messages: [EnqueueMessage] = [] + for message in shortcut.messages { + var attributes: [MessageAttribute] = [] + let entities = generateTextEntities(message.text, enabledTypes: .all) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) + } + + messages.append(.message( + text: message.text, + attributes: attributes, + inlineStickers: [:], + mediaReference: message.media.first.flatMap { AnyMediaReference.standalone(media: $0) }, + threadId: self.chatLocation.threadId, + replyToMessageId: nil, + replyToStoryId: nil, + localGroupingKey: nil, + correlationId: nil, + bubbleUpEmojiOrStickersets: [] + )) + } + + self.sendMessages(messages) + }, openEditShortcuts: { [weak self] in + guard let self else { + return + } + let _ = (self.context.sharedContext.makeQuickReplySetupScreenInitialData(context: self.context) + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] initialData in + guard let self else { + return + } + + self.push(self.context.sharedContext.makeQuickReplySetupScreen(context: self.context, initialData: initialData)) + }) }, sendBotStart: { [weak self] payload in if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState) { strongSelf.startBot(payload) diff --git a/submodules/TelegramUI/Sources/ChatInterfaceInputContextPanels.swift b/submodules/TelegramUI/Sources/ChatInterfaceInputContextPanels.swift index d6d9a21b33..9ac99003bb 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceInputContextPanels.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceInputContextPanels.swift @@ -15,7 +15,7 @@ private func inputQueryResultPriority(_ result: ChatPresentationInputQueryResult case let .mentions(items): return (2, !items.isEmpty) case let .commands(items): - return (3, !items.isEmpty) + return (3, !items.commands.isEmpty || items.hasShortcuts) case let .contextRequestResult(_, result): var nonEmpty = false if let result = result, !result.results.isEmpty { @@ -141,14 +141,14 @@ func inputContextPanelForChatPresentationIntefaceState(_ chatPresentationInterfa return nil } case let .commands(commands): - if !commands.isEmpty { + if !commands.commands.isEmpty || commands.hasShortcuts { if let currentPanel = currentPanel as? CommandChatInputContextPanelNode { - currentPanel.updateResults(commands) + currentPanel.updateResults(commands.commands, accountPeer: commands.accountPeer, hasShortcuts: commands.hasShortcuts, query: commands.query) return currentPanel } else { let panel = CommandChatInputContextPanelNode(context: context, theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings, fontSize: chatPresentationInterfaceState.fontSize, chatPresentationContext: controllerInteraction.presentationContext) panel.interfaceInteraction = interfaceInteraction - panel.updateResults(commands) + panel.updateResults(commands.commands, accountPeer: commands.accountPeer, hasShortcuts: commands.hasShortcuts, query: commands.query) return panel } } else { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift index ead219146a..002df47b9a 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift @@ -199,25 +199,59 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee var signal: Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, ChatContextQueryError> = .complete() if let previousQuery = previousQuery { switch previousQuery { - case .command: - break - default: - signal = .single({ _ in return .commands([]) }) + case .command: + break + default: + signal = .single({ _ in return .commands(ChatInputQueryCommandsResult( + commands: [], + accountPeer: nil, + hasShortcuts: false, + query: "" + )) }) } } else { - signal = .single({ _ in return .commands([]) }) + signal = .single({ _ in return .commands(ChatInputQueryCommandsResult( + commands: [], + accountPeer: nil, + hasShortcuts: false, + query: "" + )) }) + } + + var shortcuts: Signal<[QuickReplyMessageShortcut], NoError> = .single([]) + if peer is TelegramUser { + shortcuts = context.engine.accountData.shortcutMessages() + |> map { shortcuts -> [QuickReplyMessageShortcut] in + return shortcuts.shortcuts.filter { item in + return item.shortcut.hasPrefix(normalizedQuery) + } + } } - let commands = context.engine.peers.peerCommands(id: peer.id) - |> map { commands -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in + let commands = combineLatest( + context.engine.peers.peerCommands(id: peer.id), + shortcuts, + context.engine.data.subscribe( + TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId) + ) + ) + |> map { commands, shortcuts, accountPeer -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in let filteredCommands = commands.commands.filter { command in if command.command.text.hasPrefix(normalizedQuery) { return true } return false } - let sortedCommands = filteredCommands - return { _ in return .commands(sortedCommands) } + var sortedCommands = filteredCommands.map(ChatInputTextCommand.command) + for shortcut in shortcuts { + sortedCommands.append(.shortcut(shortcut)) + } + return { _ in return .commands(ChatInputQueryCommandsResult( + commands: sortedCommands, + accountPeer: accountPeer, + hasShortcuts: !shortcuts.isEmpty, + query: normalizedQuery + )) } } |> castError(ChatContextQueryError.self) return signal |> then(commands) diff --git a/submodules/TelegramUI/Sources/CommandChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/CommandChatInputContextPanelNode.swift index 1e5fd7f7f6..fbb61217d9 100644 --- a/submodules/TelegramUI/Sources/CommandChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/CommandChatInputContextPanelNode.swift @@ -13,34 +13,223 @@ import ChatControllerInteraction import ItemListUI import ChatContextQuery import ChatInputContextPanelNode +import ChatListUI +import ComponentFlow -private struct CommandChatInputContextPanelEntryStableId: Hashable { - let command: PeerCommand +private enum CommandChatInputContextPanelEntryStableId: Hashable { + case editShortcuts + case command(PeerCommand) + case shortcut(Int32) } private struct CommandChatInputContextPanelEntry: Comparable, Identifiable { - let index: Int - let command: PeerCommand - let theme: PresentationTheme - - var stableId: CommandChatInputContextPanelEntryStableId { - return CommandChatInputContextPanelEntryStableId(command: self.command) + struct Command: Equatable { + let command: ChatInputTextCommand + let accountPeer: EnginePeer? + let searchQuery: String? + + static func ==(lhs: Command, rhs: Command) -> Bool { + return lhs.command == rhs.command && lhs.accountPeer == rhs.accountPeer && lhs.searchQuery == rhs.searchQuery + } } - func withUpdatedTheme(_ theme: PresentationTheme) -> CommandChatInputContextPanelEntry { - return CommandChatInputContextPanelEntry(index: self.index, command: self.command, theme: theme) + enum Content: Equatable { + case editShortcuts + case command(Command) + } + + let content: Content + let index: Int + let theme: PresentationTheme + + init(index: Int, content: Content, theme: PresentationTheme) { + self.content = content + self.index = index + self.theme = theme } static func ==(lhs: CommandChatInputContextPanelEntry, rhs: CommandChatInputContextPanelEntry) -> Bool { - return lhs.index == rhs.index && lhs.command == rhs.command && lhs.theme === rhs.theme + return lhs.index == rhs.index && lhs.content == rhs.content && lhs.theme === rhs.theme } static func <(lhs: CommandChatInputContextPanelEntry, rhs: CommandChatInputContextPanelEntry) -> Bool { return lhs.index < rhs.index } - func item(context: AccountContext, presentationData: PresentationData, commandSelected: @escaping (PeerCommand, Bool) -> Void) -> ListViewItem { - return CommandChatInputPanelItem(context: context, presentationData: ItemListPresentationData(presentationData), command: self.command, commandSelected: commandSelected) + var stableId: CommandChatInputContextPanelEntryStableId { + switch self.content { + case .editShortcuts: + return .editShortcuts + case let .command(command): + switch command.command { + case let .command(command): + return .command(command) + case let .shortcut(shortcut): + return .shortcut(shortcut.id) + } + } + } + + func withUpdatedTheme(_ theme: PresentationTheme) -> CommandChatInputContextPanelEntry { + return CommandChatInputContextPanelEntry(index: self.index, content: self.content, theme: theme) + } + + func item(context: AccountContext, presentationData: PresentationData, commandSelected: @escaping (ChatInputTextCommand, Bool) -> Void, openEditShortcuts: @escaping () -> Void) -> ListViewItem { + switch self.content { + case .editShortcuts: + //TODO:localzie + return VerticalListContextResultsChatInputPanelButtonItem(theme: presentationData.theme, style: .round, title: "Edit Quick Replies", pressed: { + openEditShortcuts() + }) + case let .command(command): + switch command.command { + case let .command(command): + return CommandChatInputPanelItem(context: context, presentationData: ItemListPresentationData(presentationData), command: command, commandSelected: { value, sendImmediately in + commandSelected(.command(value), sendImmediately) + }) + case let .shortcut(shortcut): + let chatListNodeInteraction = ChatListNodeInteraction( + context: context, + animationCache: context.animationCache, + animationRenderer: context.animationRenderer, + activateSearch: { + }, + peerSelected: { _, _, _, _ in + commandSelected(.shortcut(shortcut), true) + }, + disabledPeerSelected: { _, _, _ in + }, + togglePeerSelected: { _, _ in + }, + togglePeersSelection: { _, _ in + }, + additionalCategorySelected: { _ in + }, + messageSelected: { _, _, _, _ in + commandSelected(.shortcut(shortcut), true) + }, + groupSelected: { _ in + }, + addContact: { _ in + }, + setPeerIdWithRevealedOptions: { _, _ in + }, + setItemPinned: { _, _ in + }, + setPeerMuted: { _, _ in + }, + setPeerThreadMuted: { _, _, _ in + }, + deletePeer: { _, _ in + }, + deletePeerThread: { _, _ in + }, + setPeerThreadStopped: { _, _, _ in + }, + setPeerThreadPinned: { _, _, _ in + }, + setPeerThreadHidden: { _, _, _ in + }, + updatePeerGrouping: { _, _ in + }, + togglePeerMarkedUnread: { _, _ in + }, + toggleArchivedFolderHiddenByDefault: { + }, + toggleThreadsSelection: { _, _ in + }, + hidePsa: { _ in + }, + activateChatPreview: { _, _, _, _, _ in + }, + present: { _ in + }, + openForumThread: { _, _ in + }, + openStorageManagement: { + }, + openPasswordSetup: { + }, + openPremiumIntro: { + }, + openPremiumGift: { + }, + openActiveSessions: { + }, + performActiveSessionAction: { _, _ in + }, + openChatFolderUpdates: { + }, + hideChatFolderUpdates: { + }, + openStories: { _, _ in + }, + dismissNotice: { _ in + } + ) + + let chatListPresentationData = ChatListPresentationData( + theme: presentationData.theme, + fontSize: presentationData.listsFontSize, + strings: presentationData.strings, + dateTimeFormat: presentationData.dateTimeFormat, + nameSortOrder: presentationData.nameSortOrder, + nameDisplayOrder: presentationData.nameDisplayOrder, + disableAnimations: false + ) + + let renderedPeer: EngineRenderedPeer + if let accountPeer = command.accountPeer { + renderedPeer = EngineRenderedPeer(peer: accountPeer) + } else { + renderedPeer = EngineRenderedPeer(peerId: context.account.peerId, peers: [:], associatedMedia: [:]) + } + + return ChatListItem( + presentationData: chatListPresentationData, + context: context, + chatListLocation: .chatList(groupId: .root), + filterData: nil, + index: EngineChatList.Item.Index.chatList(ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: context.account.peerId, namespace: 0, id: 0), timestamp: 0))), + content: .peer(ChatListItemContent.PeerData( + messages: shortcut.messages.first.flatMap({ [$0] }) ?? [], + peer: renderedPeer, + threadInfo: nil, + combinedReadState: nil, + isRemovedFromTotalUnreadCount: false, + presence: nil, + hasUnseenMentions: false, + hasUnseenReactions: false, + draftState: nil, + mediaDraftContentType: nil, + inputActivities: nil, + promoInfo: nil, + ignoreUnreadBadge: false, + displayAsMessage: false, + hasFailedMessages: false, + forumTopicData: nil, + topForumTopicItems: [], + autoremoveTimeout: nil, + storyState: nil, + requiresPremiumForMessaging: false, + displayAsTopicList: false, + tags: [], + customMessageListData: ChatListItemContent.CustomMessageListData( + commandPrefix: "/\(shortcut.shortcut)", + searchQuery: command.searchQuery.flatMap { "/\($0)"}, + messageCount: nil + ) + )), + editing: false, + hasActiveRevealControls: false, + selected: false, + header: nil, + enableContextActions: false, + hiddenOffset: false, + interaction: chatListNodeInteraction + ) + } + } } } @@ -48,21 +237,33 @@ private struct CommandChatInputContextPanelTransition { let deletions: [ListViewDeleteItem] let insertions: [ListViewInsertItem] let updates: [ListViewUpdateItem] + let hasShortcuts: Bool + let itemCountChanged: Bool } -private func preparedTransition(from fromEntries: [CommandChatInputContextPanelEntry], to toEntries: [CommandChatInputContextPanelEntry], context: AccountContext, presentationData: PresentationData, commandSelected: @escaping (PeerCommand, Bool) -> Void) -> CommandChatInputContextPanelTransition { +private func preparedTransition(from fromEntries: [CommandChatInputContextPanelEntry], to toEntries: [CommandChatInputContextPanelEntry], context: AccountContext, presentationData: PresentationData, commandSelected: @escaping (ChatInputTextCommand, Bool) -> Void, openEditShortcuts: @escaping () -> Void) -> CommandChatInputContextPanelTransition { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } - let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, commandSelected: commandSelected), directionHint: nil) } - let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, commandSelected: commandSelected), directionHint: nil) } + let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, commandSelected: commandSelected, openEditShortcuts: openEditShortcuts), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, commandSelected: commandSelected, openEditShortcuts: openEditShortcuts), directionHint: nil) } - return CommandChatInputContextPanelTransition(deletions: deletions, insertions: insertions, updates: updates) + let itemCountChanged = fromEntries.count != toEntries.count + + return CommandChatInputContextPanelTransition(deletions: deletions, insertions: insertions, updates: updates, hasShortcuts: toEntries.contains(where: { entry in + if case .editShortcuts = entry.content { + return true + } + return false + }), itemCountChanged: itemCountChanged) } final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { private let listView: ListView + private let listBackgroundView: UIView private var currentEntries: [CommandChatInputContextPanelEntry]? + private var contentOffsetChangeTransition: Transition? + private var isAnimatingOut: Bool = false private var enqueuedTransitions: [(CommandChatInputContextPanelTransition, Bool)] = [] private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat)? @@ -78,20 +279,54 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { return strings.VoiceOver_ScrollStatus(row, count).string } + self.listBackgroundView = UIView() + self.listBackgroundView.backgroundColor = theme.list.plainBackgroundColor + self.listBackgroundView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] + self.listBackgroundView.layer.cornerRadius = 10.0 + super.init(context: context, theme: theme, strings: strings, fontSize: fontSize, chatPresentationContext: chatPresentationContext) self.isOpaque = false self.clipsToBounds = true + self.view.addSubview(self.listBackgroundView) self.addSubnode(self.listView) + + self.listView.visibleContentOffsetChanged = { [weak self] offset in + guard let self else { + return + } + + if self.isAnimatingOut { + return + } + + var topItemOffset: CGFloat = self.listView.bounds.height + var isFirst = true + self.listView.forEachItemNode { itemNode in + if isFirst { + isFirst = false + topItemOffset = itemNode.frame.minY + } + } + + let transition: Transition = self.contentOffsetChangeTransition ?? .immediate + transition.setFrame(view: self.listBackgroundView, frame: CGRect(origin: CGPoint(x: 0.0, y: topItemOffset), size: CGSize(width: self.listView.bounds.width, height: self.listView.bounds.height + 1000.0))) + } } - func updateResults(_ results: [PeerCommand]) { + func updateResults(_ results: [ChatInputTextCommand], accountPeer: EnginePeer?, hasShortcuts: Bool, query: String?) { var entries: [CommandChatInputContextPanelEntry] = [] var index = 0 var stableIds = Set() + if hasShortcuts { + let entry = CommandChatInputContextPanelEntry(index: index, content: .editShortcuts, theme: self.theme) + stableIds.insert(entry.stableId) + entries.append(entry) + index += 1 + } for command in results { - let entry = CommandChatInputContextPanelEntry(index: index, command: command, theme: self.theme) + let entry = CommandChatInputContextPanelEntry(index: index, content: .command(CommandChatInputContextPanelEntry.Command(command: command, accountPeer: accountPeer, searchQuery: query)), theme: self.theme) if stableIds.contains(entry.stableId) { continue } @@ -106,7 +341,11 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { let firstTime = self.currentEntries == nil let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } let transition = preparedTransition(from: from ?? [], to: to, context: self.context, presentationData: presentationData, commandSelected: { [weak self] command, sendImmediately in - if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction { + guard let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction else { + return + } + switch command { + case let .command(command): if sendImmediately { interfaceInteraction.sendBotCommand(command.peer, "/" + command.command.text) } else { @@ -132,7 +371,14 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { return (textInputState, inputMode) } } + case let .shortcut(shortcut): + interfaceInteraction.sendShortcut(shortcut) } + }, openEditShortcuts: { [weak self] in + guard let self, let interfaceInteraction = self.interfaceInteraction else { + return + } + interfaceInteraction.openEditShortcuts() }) self.currentEntries = to self.enqueueTransition(transition, firstTime: firstTime) @@ -153,16 +399,23 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { self.enqueuedTransitions.remove(at: 0) var options = ListViewDeleteAndInsertOptions() + options.insert(.Synchronous) + options.insert(.LowLatency) if firstTime { - //options.insert(.Synchronous) - //options.insert(.LowLatency) + self.contentOffsetChangeTransition = .spring(duration: 0.4) + + self.listBackgroundView.frame = CGRect(origin: CGPoint(x: 0.0, y: self.listView.bounds.height), size: CGSize(width: self.listView.bounds.width, height: self.listView.bounds.height + 1000.0)) } else { - options.insert(.AnimateTopItemPosition) - options.insert(.AnimateCrossfade) + if transition.itemCountChanged { + options.insert(.AnimateTopItemPosition) + options.insert(.AnimateCrossfade) + } + + self.contentOffsetChangeTransition = .spring(duration: 0.4) } var insets = UIEdgeInsets() - insets.top = topInsetForLayout(size: validLayout.0) + insets.top = topInsetForLayout(size: validLayout.0, hasShortcuts: transition.hasShortcuts) insets.left = validLayout.1 insets.right = validLayout.2 @@ -178,19 +431,28 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { } if let topItemOffset = topItemOffset { + let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring) + let position = strongSelf.listView.layer.position strongSelf.listView.position = CGPoint(x: position.x, y: position.y + (strongSelf.listView.bounds.size.height - topItemOffset)) - ContainedViewLayoutTransition.animated(duration: 0.3, curve: .spring).animateView { + transition.animateView { strongSelf.listView.position = position } + //transition.animatePositionAdditive(layer: strongSelf.listBackgroundView.layer, offset: CGPoint(x: 0.0, y: strongSelf.listView.bounds.size.height - topItemOffset)) } } }) + + self.contentOffsetChangeTransition = nil } } - private func topInsetForLayout(size: CGSize) -> CGFloat { - let minimumItemHeights: CGFloat = floor(MentionChatInputPanelItemNode.itemHeight * 3.5) + private func topInsetForLayout(size: CGSize, hasShortcuts: Bool) -> CGFloat { + var minimumItemHeights: CGFloat = floor(MentionChatInputPanelItemNode.itemHeight * 3.5) + if hasShortcuts { + minimumItemHeights += VerticalListContextResultsChatInputPanelButtonItemNode.itemHeight(style: .round) + } + return max(size.height - minimumItemHeights, 0.0) } @@ -199,7 +461,16 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { self.validLayout = (size, leftInset, rightInset, bottomInset) var insets = UIEdgeInsets() - insets.top = self.topInsetForLayout(size: size) + var hasShortcuts = false + if let currentEntries = self.currentEntries { + hasShortcuts = currentEntries.contains(where: { entry in + if case .editShortcuts = entry.content { + return true + } + return false + }) + } + insets.top = self.topInsetForLayout(size: size, hasShortcuts: hasShortcuts) insets.left = leftInset insets.right = rightInset @@ -226,6 +497,8 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { } override func animateOut(completion: @escaping () -> Void) { + self.isAnimatingOut = true + var topItemOffset: CGFloat? self.listView.forEachItemNode { itemNode in if topItemOffset == nil { @@ -235,9 +508,12 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode { if let topItemOffset = topItemOffset { let position = self.listView.layer.position - self.listView.layer.animatePosition(from: position, to: CGPoint(x: position.x, y: position.y + (self.listView.bounds.size.height - topItemOffset)), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in + let offset = (self.listView.bounds.size.height - topItemOffset) + self.listView.layer.animatePosition(from: position, to: CGPoint(x: position.x, y: position.y + offset), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in completion() }) + self.listBackgroundView.layer.animatePosition(from: self.listBackgroundView.layer.position, to: CGPoint(x: self.listBackgroundView.layer.position.x, y: self.listBackgroundView.layer.position.y + offset), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in + }) } else { completion() } diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index d9cb825dd6..4b32e7ddb2 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -55,7 +55,7 @@ import BusinessSetupScreen import ChatbotSetupScreen import BusinessLocationSetupScreen import BusinessHoursSetupScreen -import GreetingMessageSetupScreen +import AutomaticBusinessMessageSetupScreen private final class AccountUserInterfaceInUseContext { let subscribers = Bag<(Bool) -> Void>() @@ -1891,20 +1891,24 @@ public final class SharedAccountContextImpl: SharedAccountContext { return ChatbotSetupScreen(context: context) } - public func makeBusinessLocationSetupScreen(context: AccountContext) -> ViewController { - return BusinessLocationSetupScreen(context: context) + public func makeBusinessLocationSetupScreen(context: AccountContext, initialValue: TelegramBusinessLocation?, completion: @escaping (TelegramBusinessLocation?) -> Void) -> ViewController { + return BusinessLocationSetupScreen(context: context, initialValue: initialValue, completion: completion) } - public func makeBusinessHoursSetupScreen(context: AccountContext) -> ViewController { - return BusinessHoursSetupScreen(context: context) + public func makeBusinessHoursSetupScreen(context: AccountContext, initialValue: TelegramBusinessHours?, completion: @escaping (TelegramBusinessHours?) -> Void) -> ViewController { + return BusinessHoursSetupScreen(context: context, initialValue: initialValue, completion: completion) } - public func makeGreetingMessageSetupScreen(context: AccountContext, isAwayMode: Bool) -> ViewController { - return GreetingMessageSetupScreen(context: context, mode: isAwayMode ? .away : .greeting) + public func makeAutomaticBusinessMessageSetupScreen(context: AccountContext, isAwayMode: Bool) -> ViewController { + return AutomaticBusinessMessageSetupScreen(context: context, mode: isAwayMode ? .away : .greeting) } - public func makeQuickReplySetupScreen(context: AccountContext) -> ViewController { - return QuickReplySetupScreen(context: context) + public func makeQuickReplySetupScreen(context: AccountContext, initialData: QuickReplySetupScreenInitialData) -> ViewController { + return QuickReplySetupScreen(context: context, initialData: initialData as! QuickReplySetupScreen.InitialData) + } + + public func makeQuickReplySetupScreenInitialData(context: AccountContext) -> Signal { + return QuickReplySetupScreen.initialData(context: context) } public func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController { diff --git a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputContextPanelNode.swift index d26978cc54..e8dba3fc2f 100644 --- a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputContextPanelNode.swift @@ -287,7 +287,7 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex private func topInsetForLayout(size: CGSize, hasSwitchPeer: Bool) -> CGFloat { var minimumItemHeights: CGFloat = floor(VerticalListContextResultsChatInputPanelItemNode.itemHeight * 3.5) if hasSwitchPeer { - minimumItemHeights += VerticalListContextResultsChatInputPanelButtonItemNode.itemHeight + minimumItemHeights += VerticalListContextResultsChatInputPanelButtonItemNode.itemHeight(style: .regular) } return max(size.height - minimumItemHeights, 0.0) diff --git a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelButtonItem.swift b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelButtonItem.swift index 89b9d2cb20..515c8e8188 100644 --- a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelButtonItem.swift +++ b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelButtonItem.swift @@ -7,12 +7,19 @@ import SwiftSignalKit import TelegramPresentationData final class VerticalListContextResultsChatInputPanelButtonItem: ListViewItem { + enum Style { + case regular + case round + } + fileprivate let theme: PresentationTheme + fileprivate let style: Style fileprivate let title: String fileprivate let pressed: () -> Void - public init(theme: PresentationTheme, title: String, pressed: @escaping () -> Void) { + public init(theme: PresentationTheme, style: Style = .regular, title: String, pressed: @escaping () -> Void) { self.theme = theme + self.style = style self.title = title self.pressed = pressed } @@ -65,10 +72,15 @@ final class VerticalListContextResultsChatInputPanelButtonItem: ListViewItem { } } -private let titleFont = Font.regular(15.0) - final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItemNode { - static let itemHeight: CGFloat = 32.0 + static func itemHeight(style: VerticalListContextResultsChatInputPanelButtonItem.Style) -> CGFloat { + switch style { + case .regular: + return 32.0 + case .round: + return 42.0 + } + } private let buttonNode: HighlightTrackingButtonNode private let titleNode: TextNode @@ -125,11 +137,19 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem let makeTitleLayout = TextNode.asyncLayout(self.titleNode) return { [weak self] item, params, mergedTop, mergedBottom in + let titleFont: UIFont + switch item.style { + case .regular: + titleFont = Font.regular(15.0) + case .round: + titleFont = Font.regular(17.0) + } + let titleString = NSAttributedString(string: item.title, font: titleFont, textColor: item.theme.list.itemAccentColor) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 16.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) - let nodeLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: VerticalListContextResultsChatInputPanelButtonItemNode.itemHeight), insets: UIEdgeInsets()) + let nodeLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: VerticalListContextResultsChatInputPanelButtonItemNode.itemHeight(style: item.style)), insets: UIEdgeInsets()) return (nodeLayout, { _ in if let strongSelf = self { @@ -137,7 +157,13 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem strongSelf.separatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor strongSelf.topSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor - strongSelf.backgroundColor = item.theme.list.plainBackgroundColor + + switch item.style { + case .regular: + strongSelf.backgroundColor = item.theme.list.plainBackgroundColor + case .round: + strongSelf.backgroundColor = nil + } let _ = titleApply()