diff --git a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift index 4c96fcfead..3f4fb21350 100644 --- a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift @@ -635,7 +635,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa } } - /* let joinToSend: CurrentChannelJoinToSend + let joinToSend: CurrentChannelJoinToSend if let current = state.joinToSend { joinToSend = current } else { @@ -656,7 +656,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa approveMembers = false } } - */ + let forwardingEnabled: Bool if let enabled = state.forwardingEnabled { forwardingEnabled = enabled @@ -817,7 +817,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo)) } } -/* + if isGroup && selectedType == .publicChannel { var isDiscussion = false if let cachedData = view.cachedData as? CachedChannelData, case .known = cachedData.linkedDiscussionPeerId { @@ -835,7 +835,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa entries.append(.approveMembersInfo(presentationData.theme, presentationData.strings.Group_Setup_ApproveNewMembersInfo)) } } -*/ + entries.append(.forwardingHeader(presentationData.theme, isGroup ? presentationData.strings.Group_Setup_ForwardingGroupTitle.uppercased() : presentationData.strings.Group_Setup_ForwardingChannelTitle.uppercased())) entries.append(.forwardingDisabled(presentationData.theme, presentationData.strings.Group_Setup_ForwardingDisabled, !forwardingEnabled)) entries.append(.forwardingInfo(presentationData.theme, forwardingEnabled ? (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfo : presentationData.strings.Group_Setup_ForwardingChannelInfo) : (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfoDisabled : presentationData.strings.Group_Setup_ForwardingChannelInfoDisabled))) diff --git a/submodules/ShareController/Sources/ShareControllerNode.swift b/submodules/ShareController/Sources/ShareControllerNode.swift index 8a004d6221..61bcd76f50 100644 --- a/submodules/ShareController/Sources/ShareControllerNode.swift +++ b/submodules/ShareController/Sources/ShareControllerNode.swift @@ -457,7 +457,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate if contentNode is ShareSearchContainerNode { self.setActionNodesHidden(true, inputField: true, actions: true) - } else if !(contentNode is ShareLoadingContainerNode) { + } else if !(contentNode is ShareLoadingContainer) { self.setActionNodesHidden(false, inputField: !self.controllerInteraction!.selectedPeers.isEmpty || self.presetText != nil, actions: true) } } else { @@ -649,7 +649,22 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate let timestamp = CACurrentMediaTime() let doneImpl: (Bool) -> Void = { [weak self] shouldDelay in let minDelay: Double = shouldDelay ? 0.9 : 0.6 - let delay = max(minDelay, (timestamp + minDelay) - CACurrentMediaTime()) + let delay: Double + if let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareProlongedLoadingContainerNode { + delay = contentNode.completionDuration + + if shouldDelay { + Queue.mainQueue().after(delay - 1.5, { + if strongSelf.hapticFeedback == nil { + strongSelf.hapticFeedback = HapticFeedback() + } + strongSelf.hapticFeedback?.success() + }) + } + } else { + delay = max(minDelay, (timestamp + minDelay) - CACurrentMediaTime()) + } + Queue.mainQueue().after(delay, { self?.animateOut(shared: true, completion: { self?.dismiss?(true) @@ -658,7 +673,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate }) } if self.fromForeignApp { - self.transitionToContentNode(ShareLoadingContainerNode(theme: self.presentationData.theme, forceNativeAppearance: true), fastOut: true) + self.transitionToContentNode(ShareProlongedLoadingContainerNode(theme: self.presentationData.theme, strings: self.presentationData.strings, forceNativeAppearance: true), fastOut: true) } else { self.animateOut(shared: true, completion: { }) @@ -683,7 +698,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate return } - guard let contentNode = strongSelf.contentNode as? ShareLoadingContainerNode else { + guard let contentNode = strongSelf.contentNode as? ShareLoadingContainer else { return } @@ -696,11 +711,6 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate contentNode.state = .done if fromForeignApp { if !wasDone { - if strongSelf.hapticFeedback == nil { - strongSelf.hapticFeedback = HapticFeedback() - } - strongSelf.hapticFeedback?.success() - wasDone = true doneImpl(true) } @@ -988,7 +998,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate transition.updateAlpha(node: self.actionSeparatorNode, alpha: 0.0) transition.updateAlpha(node: self.actionsBackgroundNode, alpha: 0.0) - self.transitionToContentNode(ShareLoadingContainerNode(theme: self.presentationData.theme, forceNativeAppearance: true), fastOut: true) + self.transitionToContentNode(ShareProlongedLoadingContainerNode(theme: self.presentationData.theme, strings: self.presentationData.strings, forceNativeAppearance: true), fastOut: true) let timestamp = CACurrentMediaTime() self.shareDisposable.set(signal.start(completed: { [weak self] in let minDelay = 0.6 @@ -1041,14 +1051,14 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate } self.shareDisposable.set((signal |> deliverOnMainQueue).start(next: { [weak self] status in - guard let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareLoadingContainerNode else { + guard let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareLoadingContainer else { return } if let status = status { contentNode.state = .progress(status) } }, completed: { [weak self] in - guard let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareLoadingContainerNode else { + guard let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareLoadingContainer else { return } contentNode.state = .done diff --git a/submodules/ShareController/Sources/ShareLoadingContainerNode.swift b/submodules/ShareController/Sources/ShareLoadingContainerNode.swift index 922e688829..7e915c21a0 100644 --- a/submodules/ShareController/Sources/ShareLoadingContainerNode.swift +++ b/submodules/ShareController/Sources/ShareLoadingContainerNode.swift @@ -7,6 +7,8 @@ import Postbox import TelegramPresentationData import ActivityIndicator import RadialStatusNode +import AnimatedStickerNode +import TelegramAnimatedStickerNode public enum ShareLoadingState { case preparing @@ -14,7 +16,11 @@ public enum ShareLoadingState { case done } -public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContainerNode { +protocol ShareLoadingContainer: ASDisplayNode { + var state: ShareLoadingState { get set } +} + +public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContainerNode, ShareLoadingContainer { private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)? private let theme: PresentationTheme @@ -84,3 +90,223 @@ public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContain public func updateSelectedPeers() { } } + +public final class ShareProlongedLoadingContainerNode: ASDisplayNode, ShareContentContainerNode, ShareLoadingContainer { + private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)? + + private let theme: PresentationTheme + private let strings: PresentationStrings + + private let animationNode: AnimatedStickerNode + private let doneAnimationNode: AnimatedStickerNode + private let progressTextNode: ImmediateTextNode + + private let progressBackgroundNode: ASDisplayNode + private let progressForegroundNode: ASDisplayNode + + private let animationStatusDisposable = MetaDisposable() + + private var progressValue: CGFloat = 0.0 + private var targetProgressValue: CGFloat = 0.0 + private var animator: ConstantDisplayLinkAnimator? + + private var randomCompletionStart: CGFloat = .random(in: 0.94...0.97) + private var isDone: Bool = false + + private var startTimestamp: Double? + + public var state: ShareLoadingState = .preparing { + didSet { + switch self.state { + case .preparing: + break + case let .progress(value): + let currentTimestamp = CACurrentMediaTime() + if self.startTimestamp == nil { + self.startTimestamp = currentTimestamp + } else if let startTimestamp = self.startTimestamp, currentTimestamp - startTimestamp < 1.0, value > 0.5 && value < 0.9 { + self.randomCompletionStart = 0.8 + } + + self.targetProgressValue = CGFloat(value) * self.randomCompletionStart + + if self.animator == nil { + self.animator = ConstantDisplayLinkAnimator(update: { [weak self] in + if let strongSelf = self, strongSelf.targetProgressValue > strongSelf.progressValue { + let updatedProgress = strongSelf.progressValue + 0.005 + strongSelf.progressValue = min(1.0, updatedProgress) + + if strongSelf.progressValue == 1.0 && !strongSelf.isDone { + strongSelf.isDone = true + strongSelf.animator?.invalidate() + + if let snapshotView = strongSelf.progressTextNode.view.snapshotContentTree() { + snapshotView.frame = strongSelf.progressTextNode.frame + strongSelf.view.addSubview(snapshotView) + + snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in + snapshotView?.removeFromSuperview() + }) + snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -20.0), duration: 0.25, removeOnCompletion: false, additive: true) + + strongSelf.progressTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + strongSelf.progressTextNode.layer.animatePosition(from: CGPoint(x: 0.0, y: 20.0), to: CGPoint(), duration: 0.25, additive: true) + } + } + + if let (size, isLandscape, bottomInset) = strongSelf.validLayout { + strongSelf.updateLayout(size: size, isLandscape: isLandscape, bottomInset: bottomInset, transition: .immediate) + } + } + }) + self.animator?.isPaused = false + } + case .done: + if let (size, isLandscape, bottomInset) = self.validLayout { + self.updateLayout(size: size, isLandscape: isLandscape, bottomInset: bottomInset, transition: .animated(duration: 0.2, curve: .easeInOut)) + } + self.animationNode.stopAtNearestLoop = true + self.animationNode.completed = { [weak self] _ in + if let strongSelf = self { + strongSelf.animationNode.visibility = false + strongSelf.doneAnimationNode.visibility = true + strongSelf.doneAnimationNode.isHidden = false + } + } + self.animationNode.frameUpdated = { [weak self] index, total in + if let strongSelf = self { + let progress = min(1.0, CGFloat(index) / CGFloat(total)) + let delta = 1.0 - strongSelf.randomCompletionStart + strongSelf.targetProgressValue = strongSelf.randomCompletionStart + delta * progress * 0.5 + } + } + self.doneAnimationNode.frameUpdated = { [weak self] index, total in + if let strongSelf = self { + let progress = min(1.0, CGFloat(index) / CGFloat(total) * 2.1) + let delta = 1.0 - strongSelf.randomCompletionStart + strongSelf.targetProgressValue = strongSelf.randomCompletionStart + delta * 0.5 + delta * progress * 0.5 + } + } + self.doneAnimationNode.started = { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.animationNode.isHidden = true + } + } + } + } + + private var elapsedTime: Double = 0.0 + public var completionDuration: Double { + return self.elapsedTime + 3.0 + 0.15 + } + + public init(theme: PresentationTheme, strings: PresentationStrings, forceNativeAppearance: Bool) { + self.theme = theme + self.strings = strings + + self.animationNode = AnimatedStickerNode() + self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "ShareProgress"), width: 384, height: 384, playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) + self.animationNode.visibility = true + + self.doneAnimationNode = AnimatedStickerNode() + self.doneAnimationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "ShareDone"), width: 384, height: 384, playbackMode: .once, mode: .direct(cachePathPrefix: nil)) + self.doneAnimationNode.visibility = false + self.doneAnimationNode.isHidden = true + + self.progressTextNode = ImmediateTextNode() + self.progressTextNode.textAlignment = .center + + self.progressBackgroundNode = ASDisplayNode() + self.progressBackgroundNode.backgroundColor = theme.actionSheet.controlAccentColor.withMultipliedAlpha(0.2) + self.progressBackgroundNode.cornerRadius = 3.0 + + self.progressForegroundNode = ASDisplayNode() + self.progressForegroundNode.backgroundColor = theme.actionSheet.controlAccentColor + self.progressForegroundNode.cornerRadius = 3.0 + + super.init() + + self.addSubnode(self.animationNode) + self.addSubnode(self.doneAnimationNode) + + self.addSubnode(self.progressTextNode) + + self.addSubnode(self.progressBackgroundNode) + self.addSubnode(self.progressForegroundNode) + + self.animationStatusDisposable.set((self.animationNode.status + |> deliverOnMainQueue).start(next: { [weak self] status in + if let strongSelf = self { + strongSelf.elapsedTime = status.duration - status.timestamp + } + })) + } + + deinit { + self.animationStatusDisposable.dispose() + } + + public func activate() { + } + + public func deactivate() { + } + + public func setEnsurePeerVisibleOnLayout(_ peerId: PeerId?) { + } + + public func setContentOffsetUpdated(_ f: ((CGFloat, ContainedViewLayoutTransition) -> Void)?) { + self.contentOffsetUpdated = f + } + + private var validLayout: (CGSize, Bool, CGFloat)? + public func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (size, isLandscape, bottomInset) + + let nodeHeight: CGFloat = 450.0 + + let inset: CGFloat = 24.0 + let progressHeight: CGFloat = 6.0 + let spacing: CGFloat = 16.0 + + let progress = self.progressValue + + let progressFrame = CGRect(x: inset, y: size.height - inset - progressHeight, width: size.width - inset * 2.0, height: progressHeight) + self.progressBackgroundNode.frame = progressFrame + let progressForegroundFrame = CGRect(x: progressFrame.minX, y: progressFrame.minY, width: floorToScreenPixels(progressFrame.width * progress), height: progressHeight) + if !self.progressForegroundNode.frame.origin.x.isZero { + transition.updateFrame(node: self.progressForegroundNode, frame: progressForegroundFrame, beginWithCurrentState: true) + } else { + self.progressForegroundNode.frame = progressForegroundFrame + } + + let progressText: String + if self.isDone { + progressText = self.strings.Share_UploadDone + } else { + progressText = self.strings.Share_UploadProgress(Int(progress * 100.0)).string + } + + self.progressTextNode.attributedText = NSAttributedString(string: progressText, font: Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers]), textColor: self.theme.actionSheet.primaryTextColor) + let progressTextSize = self.progressTextNode.updateLayout(size) + let progressTextFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - progressTextSize.width) / 2.0), y: progressFrame.minY - spacing - 9.0 - progressTextSize.height), size: progressTextSize) + self.progressTextNode.frame = progressTextFrame + + let imageSide: CGFloat = 160.0 + let imageSize = CGSize(width: imageSide, height: imageSide) + + let animationFrame = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: (progressTextFrame.minY - imageSize.height - 20.0)), size: imageSize) + self.animationNode.frame = animationFrame + self.animationNode.updateLayout(size: imageSize) + + self.doneAnimationNode.frame = animationFrame + self.doneAnimationNode.updateLayout(size: imageSize) + + self.contentOffsetUpdated?(-size.height + nodeHeight * 0.5, transition) + } + + public func updateSelectedPeers() { + } +} diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index f727327d25..896054be6f 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -68,7 +68,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1071145937] = { return Api.BotCommandScope.parse_botCommandScopePeerAdmins($0) } dict[169026035] = { return Api.BotCommandScope.parse_botCommandScopePeerUser($0) } dict[1011811544] = { return Api.BotCommandScope.parse_botCommandScopeUsers($0) } - dict[-468280483] = { return Api.BotInfo.parse_botInfo($0) } + dict[-1892676777] = { return Api.BotInfo.parse_botInfo($0) } dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) } dict[416402882] = { return Api.BotInlineMessage.parse_botInlineMessageMediaContact($0) } dict[85477117] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) } @@ -198,6 +198,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-317144808] = { return Api.EncryptedMessage.parse_encryptedMessage($0) } dict[594758406] = { return Api.EncryptedMessage.parse_encryptedMessageService($0) } dict[179611673] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) } + dict[-317687113] = { return Api.ExportedChatInvite.parse_chatInvitePublicJoinRequests($0) } dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) } dict[1648543603] = { return Api.FileHash.parse_fileHash($0) } dict[-11252123] = { return Api.Folder.parse_folder($0) } diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index a0cab703c5..e540e8f7ef 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -856,52 +856,68 @@ public extension Api { } public extension Api { enum BotInfo: TypeConstructorDescription { - case botInfo(userId: Int64, description: String, commands: [Api.BotCommand], menuButton: Api.BotMenuButton) + case botInfo(flags: Int32, userId: Int64?, description: String?, descriptionPhoto: Api.Photo?, descriptionDocument: Api.Document?, commands: [Api.BotCommand]?, menuButton: Api.BotMenuButton?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .botInfo(let userId, let description, let commands, let menuButton): + case .botInfo(let flags, let userId, let description, let descriptionPhoto, let descriptionDocument, let commands, let menuButton): if boxed { - buffer.appendInt32(-468280483) + buffer.appendInt32(-1892676777) } - serializeInt64(userId, buffer: buffer, boxed: false) - serializeString(description, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(commands.count)) - for item in commands { + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt64(userId!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 4) != 0 {descriptionPhoto!.serialize(buffer, true)} + if Int(flags) & Int(1 << 5) != 0 {descriptionDocument!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(commands!.count)) + for item in commands! { item.serialize(buffer, true) - } - menuButton.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 3) != 0 {menuButton!.serialize(buffer, true)} break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .botInfo(let userId, let description, let commands, let menuButton): - return ("botInfo", [("userId", String(describing: userId)), ("description", String(describing: description)), ("commands", String(describing: commands)), ("menuButton", String(describing: menuButton))]) + case .botInfo(let flags, let userId, let description, let descriptionPhoto, let descriptionDocument, let commands, let menuButton): + return ("botInfo", [("flags", String(describing: flags)), ("userId", String(describing: userId)), ("description", String(describing: description)), ("descriptionPhoto", String(describing: descriptionPhoto)), ("descriptionDocument", String(describing: descriptionDocument)), ("commands", String(describing: commands)), ("menuButton", String(describing: menuButton))]) } } public static func parse_botInfo(_ reader: BufferReader) -> BotInfo? { - var _1: Int64? - _1 = reader.readInt64() - var _2: String? - _2 = parseString(reader) - var _3: [Api.BotCommand]? - if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotCommand.self) - } - var _4: Api.BotMenuButton? - if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.BotMenuButton - } + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt64() } + var _3: String? + if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } + var _4: Api.Photo? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _5: Api.Document? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Document + } } + var _6: [Api.BotCommand]? + if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotCommand.self) + } } + var _7: Api.BotMenuButton? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.BotMenuButton + } } let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.BotInfo.botInfo(userId: _1!, description: _2!, commands: _3!, menuButton: _4!) + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 5) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.BotInfo.botInfo(flags: _1!, userId: _2, description: _3, descriptionPhoto: _4, descriptionDocument: _5, commands: _6, menuButton: _7) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index 17493c3b33..6bfe54fccb 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -2284,6 +2284,38 @@ public extension Api.functions.channels { }) } } +public extension Api.functions.channels { + static func toggleJoinRequest(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1277789622) + channel.serialize(buffer, true) + enabled.serialize(buffer, true) + return (FunctionDescription(name: "channels.toggleJoinRequest", parameters: [("channel", String(describing: channel)), ("enabled", String(describing: enabled))]), 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.channels { + static func toggleJoinToSend(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-456419968) + channel.serialize(buffer, true) + enabled.serialize(buffer, true) + return (FunctionDescription(name: "channels.toggleJoinToSend", parameters: [("channel", String(describing: channel)), ("enabled", String(describing: enabled))]), 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.channels { static func togglePreHistoryHidden(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramApi/Sources/Api5.swift b/submodules/TelegramApi/Sources/Api5.swift index 4b13aba8e2..099cbad071 100644 --- a/submodules/TelegramApi/Sources/Api5.swift +++ b/submodules/TelegramApi/Sources/Api5.swift @@ -541,6 +541,7 @@ public extension Api { public extension Api { enum ExportedChatInvite: TypeConstructorDescription { case chatInviteExported(flags: Int32, link: String, adminId: Int64, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, usage: Int32?, requested: Int32?, title: String?) + case chatInvitePublicJoinRequests public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -558,6 +559,12 @@ public extension Api { if Int(flags) & Int(1 << 3) != 0 {serializeInt32(usage!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 7) != 0 {serializeInt32(requested!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 8) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + break + case .chatInvitePublicJoinRequests: + if boxed { + buffer.appendInt32(-317687113) + } + break } } @@ -566,6 +573,8 @@ public extension Api { switch self { case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested, let title): return ("chatInviteExported", [("flags", String(describing: flags)), ("link", String(describing: link)), ("adminId", String(describing: adminId)), ("date", String(describing: date)), ("startDate", String(describing: startDate)), ("expireDate", String(describing: expireDate)), ("usageLimit", String(describing: usageLimit)), ("usage", String(describing: usage)), ("requested", String(describing: requested)), ("title", String(describing: title))]) + case .chatInvitePublicJoinRequests: + return ("chatInvitePublicJoinRequests", []) } } @@ -607,6 +616,9 @@ public extension Api { return nil } } + public static func parse_chatInvitePublicJoinRequests(_ reader: BufferReader) -> ExportedChatInvite? { + return Api.ExportedChatInvite.chatInvitePublicJoinRequests + } } } @@ -1370,43 +1382,3 @@ public extension Api { } } -public extension Api { - enum InlineBotSwitchPM: TypeConstructorDescription { - case inlineBotSwitchPM(text: String, startParam: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inlineBotSwitchPM(let text, let startParam): - if boxed { - buffer.appendInt32(1008755359) - } - serializeString(text, buffer: buffer, boxed: false) - serializeString(startParam, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inlineBotSwitchPM(let text, let startParam): - return ("inlineBotSwitchPM", [("text", String(describing: text)), ("startParam", String(describing: startParam))]) - } - } - - public static func parse_inlineBotSwitchPM(_ reader: BufferReader) -> InlineBotSwitchPM? { - var _1: String? - _1 = parseString(reader) - var _2: String? - _2 = parseString(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.InlineBotSwitchPM.inlineBotSwitchPM(text: _1!, startParam: _2!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api6.swift b/submodules/TelegramApi/Sources/Api6.swift index c4bf677552..2696ebe04e 100644 --- a/submodules/TelegramApi/Sources/Api6.swift +++ b/submodules/TelegramApi/Sources/Api6.swift @@ -1,3 +1,43 @@ +public extension Api { + enum InlineBotSwitchPM: TypeConstructorDescription { + case inlineBotSwitchPM(text: String, startParam: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inlineBotSwitchPM(let text, let startParam): + if boxed { + buffer.appendInt32(1008755359) + } + serializeString(text, buffer: buffer, boxed: false) + serializeString(startParam, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inlineBotSwitchPM(let text, let startParam): + return ("inlineBotSwitchPM", [("text", String(describing: text)), ("startParam", String(describing: startParam))]) + } + } + + public static func parse_inlineBotSwitchPM(_ reader: BufferReader) -> InlineBotSwitchPM? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InlineBotSwitchPM.inlineBotSwitchPM(text: _1!, startParam: _2!) + } + else { + return nil + } + } + + } +} public extension Api { enum InlineQueryPeerType: TypeConstructorDescription { case inlineQueryPeerTypeBroadcast @@ -1078,59 +1118,3 @@ public extension Api { } } -public extension Api { - enum InputDocument: TypeConstructorDescription { - case inputDocument(id: Int64, accessHash: Int64, fileReference: Buffer) - case inputDocumentEmpty - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inputDocument(let id, let accessHash, let fileReference): - if boxed { - buffer.appendInt32(448771445) - } - serializeInt64(id, buffer: buffer, boxed: false) - serializeInt64(accessHash, buffer: buffer, boxed: false) - serializeBytes(fileReference, buffer: buffer, boxed: false) - break - case .inputDocumentEmpty: - if boxed { - buffer.appendInt32(1928391342) - } - - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inputDocument(let id, let accessHash, let fileReference): - return ("inputDocument", [("id", String(describing: id)), ("accessHash", String(describing: accessHash)), ("fileReference", String(describing: fileReference))]) - case .inputDocumentEmpty: - return ("inputDocumentEmpty", []) - } - } - - public static func parse_inputDocument(_ reader: BufferReader) -> InputDocument? { - var _1: Int64? - _1 = reader.readInt64() - var _2: Int64? - _2 = reader.readInt64() - var _3: Buffer? - _3 = parseBytes(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.InputDocument.inputDocument(id: _1!, accessHash: _2!, fileReference: _3!) - } - else { - return nil - } - } - public static func parse_inputDocumentEmpty(_ reader: BufferReader) -> InputDocument? { - return Api.InputDocument.inputDocumentEmpty - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api7.swift b/submodules/TelegramApi/Sources/Api7.swift index 28a6505c30..7228fb0394 100644 --- a/submodules/TelegramApi/Sources/Api7.swift +++ b/submodules/TelegramApi/Sources/Api7.swift @@ -1,3 +1,59 @@ +public extension Api { + enum InputDocument: TypeConstructorDescription { + case inputDocument(id: Int64, accessHash: Int64, fileReference: Buffer) + case inputDocumentEmpty + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputDocument(let id, let accessHash, let fileReference): + if boxed { + buffer.appendInt32(448771445) + } + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + break + case .inputDocumentEmpty: + if boxed { + buffer.appendInt32(1928391342) + } + + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputDocument(let id, let accessHash, let fileReference): + return ("inputDocument", [("id", String(describing: id)), ("accessHash", String(describing: accessHash)), ("fileReference", String(describing: fileReference))]) + case .inputDocumentEmpty: + return ("inputDocumentEmpty", []) + } + } + + public static func parse_inputDocument(_ reader: BufferReader) -> InputDocument? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputDocument.inputDocument(id: _1!, accessHash: _2!, fileReference: _3!) + } + else { + return nil + } + } + public static func parse_inputDocumentEmpty(_ reader: BufferReader) -> InputDocument? { + return Api.InputDocument.inputDocumentEmpty + } + + } +} public extension Api { enum InputEncryptedChat: TypeConstructorDescription { case inputEncryptedChat(chatId: Int32, accessHash: Int64) diff --git a/submodules/TelegramCore/Sources/ApiUtils/BotInfo.swift b/submodules/TelegramCore/Sources/ApiUtils/BotInfo.swift index 6bfcd648d7..33a38190f7 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/BotInfo.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/BotInfo.swift @@ -16,13 +16,22 @@ extension BotMenuButton { extension BotInfo { convenience init(apiBotInfo: Api.BotInfo) { switch apiBotInfo { - case let .botInfo(_, description, commands, menuButton): - self.init(description: description, photo: nil, commands: commands.map { command in - switch command { - case let .botCommand(command, description): - return BotCommand(text: command, description: description) + case let .botInfo(_, _, description, descriptionPhoto, _, apiCommands, apiMenuButton): + let photo: TelegramMediaImage? = descriptionPhoto.flatMap(telegramMediaImageFromApiPhoto) + var commands: [BotCommand] = [] + if let apiCommands = apiCommands { + commands = apiCommands.map { command in + switch command { + case let .botCommand(command, description): + return BotCommand(text: command, description: description) + } } - }, menuButton: BotMenuButton(apiBotMenuButton: menuButton)) + } + var menuButton: BotMenuButton = .commands + if let apiMenuButton = apiMenuButton { + menuButton = BotMenuButton(apiBotMenuButton: apiMenuButton) + } + self.init(description: description ?? "", photo: photo, commands: commands, menuButton: menuButton) } } } diff --git a/submodules/TelegramCore/Sources/ApiUtils/ExportedInvitation.swift b/submodules/TelegramCore/Sources/ApiUtils/ExportedInvitation.swift index c87c74548b..3abfba2a48 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/ExportedInvitation.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/ExportedInvitation.swift @@ -8,9 +8,8 @@ extension ExportedInvitation { switch apiExportedInvite { case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, requested, title): self = .link(link: link, title: title, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, requestedCount: requested) -/* case .chatInvitePublicJoinRequests: + case .chatInvitePublicJoinRequests: self = .publicJoinRequest -*/ } } } diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index cee780af81..2a04777021 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 141 + return 142 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelSendRestriction.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelSendRestriction.swift index a12363b753..20f562dfe8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelSendRestriction.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelSendRestriction.swift @@ -2,14 +2,12 @@ import Postbox import TelegramApi import SwiftSignalKit - public enum UpdateChannelJoinToSendError { case generic } func _internal_toggleChannelJoinToSend(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, peerId: PeerId, enabled: Bool) -> Signal { - return .never() -/* return postbox.transaction { transaction -> Peer? in + return postbox.transaction { transaction -> Peer? in return transaction.getPeer(peerId) } |> castError(UpdateChannelJoinToSendError.self) @@ -26,7 +24,6 @@ func _internal_toggleChannelJoinToSend(postbox: Postbox, network: Network, accou return .complete() } } -*/ } public enum UpdateChannelJoinRequestError { @@ -34,8 +31,7 @@ public enum UpdateChannelJoinRequestError { } func _internal_toggleChannelJoinRequest(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, peerId: PeerId, enabled: Bool) -> Signal { - return .never() -/* return postbox.transaction { transaction -> Peer? in + return postbox.transaction { transaction -> Peer? in return transaction.getPeer(peerId) } |> castError(UpdateChannelJoinRequestError.self) @@ -52,5 +48,4 @@ func _internal_toggleChannelJoinRequest(postbox: Postbox, network: Network, acco return .complete() } } -*/ } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift index e303220dd3..fed43d2ada 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift @@ -278,10 +278,12 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee var botInfos: [CachedPeerBotInfo] = [] for botInfo in chatFullBotInfo ?? [] { switch botInfo { - case let .botInfo(userId, _, _, _): - let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) - let parsedBotInfo = BotInfo(apiBotInfo: botInfo) - botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo)) + case let .botInfo(_, userId, _, _, _, _, _): + if let userId = userId { + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) + let parsedBotInfo = BotInfo(apiBotInfo: botInfo) + botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo)) + } } } let participants = CachedGroupParticipants(apiParticipants: chatFullParticipants) @@ -449,10 +451,12 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee var botInfos: [CachedPeerBotInfo] = [] for botInfo in apiBotInfos { switch botInfo { - case let .botInfo(userId, _, _, _): - let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) - let parsedBotInfo = BotInfo(apiBotInfo: botInfo) - botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo)) + case let .botInfo(_, userId, _, _, _, _, _): + if let userId = userId { + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) + let parsedBotInfo = BotInfo(apiBotInfo: botInfo) + botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo)) + } } }