From 7af3fd0c8254dfac668895a97e450a5920a558d0 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 24 Mar 2021 20:54:09 +0500 Subject: [PATCH 1/2] Fix voice chat avatar expansion --- .../Sources/PeerInfoAvatarListNode.swift | 2 +- .../Sources/VoiceChatParticipantItem.swift | 79 ++++++++++++++----- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift b/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift index 46acc6547c..f4d8b1a3d4 100644 --- a/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift +++ b/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift @@ -340,7 +340,7 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode { if let video = videoRepresentations.last, let peerReference = PeerReference(self.peer) { let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.representation.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.representation.dimensions, flags: [])])) - let videoContent = NativeVideoContent(id: .profileVideo(id, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear) + let videoContent = NativeVideoContent(id: .profileVideo(id, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: fullSizeOnly, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear) if videoContent.id != self.videoContent?.id { self.videoContent = videoContent diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift index 307f96e8bc..bb977edca7 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift @@ -154,6 +154,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { let contextSourceNode: ContextExtractedContentContainingNode private let containerNode: ContextControllerSourceNode + private let backgroundImageNode: ASImageNode private let extractedBackgroundImageNode: ASImageNode private let offsetContainerNode: ASDisplayNode @@ -207,6 +208,11 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { self.contextSourceNode = ContextExtractedContentContainingNode() self.containerNode = ContextControllerSourceNode() + self.backgroundImageNode = ASImageNode() + self.backgroundImageNode.clipsToBounds = true + self.backgroundImageNode.displaysAsynchronously = false + self.backgroundImageNode.alpha = 0.0 + self.extractedBackgroundImageNode = ASImageNode() self.extractedBackgroundImageNode.clipsToBounds = true self.extractedBackgroundImageNode.displaysAsynchronously = false @@ -247,7 +253,8 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode self.addSubnode(self.containerNode) - self.contextSourceNode.contentNode.addSubnode(self.extractedBackgroundImageNode) + self.contextSourceNode.contentNode.addSubnode(self.backgroundImageNode) + self.backgroundImageNode.addSubnode(self.extractedBackgroundImageNode) self.contextSourceNode.contentNode.addSubnode(self.offsetContainerNode) self.offsetContainerNode.addSubnode(self.avatarNode) self.offsetContainerNode.addSubnode(self.titleNode) @@ -322,8 +329,16 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { let springDamping: CGFloat = isExtracted ? 104.0 : 1000.0 if !extractedVerticalOffset.isZero { - let radiusTransition = ContainedViewLayoutTransition.animated(duration: 0.15, curve: .easeInOut) + let radiusTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) if isExtracted { + strongSelf.backgroundImageNode.image = generateImage(CGSize(width: cornerRadius * 2.0, height: cornerRadius * 2.0), rotatedContext: { (size, context) in + let bounds = CGRect(origin: CGPoint(), size: size) + context.clear(bounds) + + context.setFillColor(UIColor(rgb: 0x2c2c2e).cgColor) + context.fillEllipse(in: bounds) + context.fill(CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height / 2.0)) + })?.stretchableImage(withLeftCapWidth: Int(cornerRadius), topCapHeight: Int(cornerRadius)) strongSelf.extractedBackgroundImageNode.image = generateImage(CGSize(width: cornerRadius * 2.0, height: cornerRadius * 2.0), rotatedContext: { (size, context) in let bounds = CGRect(origin: CGPoint(), size: size) context.clear(bounds) @@ -332,11 +347,11 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { context.fillEllipse(in: bounds) context.fill(CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height / 2.0)) })?.stretchableImage(withLeftCapWidth: Int(cornerRadius), topCapHeight: Int(cornerRadius)) - strongSelf.extractedBackgroundImageNode.cornerRadius = cornerRadius + strongSelf.backgroundImageNode.cornerRadius = cornerRadius var avatarInitialRect = strongSelf.avatarNode.view.convert(strongSelf.avatarNode.bounds, to: strongSelf.offsetContainerNode.supernode?.view) if strongSelf.avatarTransitionNode == nil { - transition.updateCornerRadius(node: strongSelf.extractedBackgroundImageNode, cornerRadius: 0.0) + transition.updateCornerRadius(node: strongSelf.backgroundImageNode, cornerRadius: 0.0) let targetRect = CGRect(x: extractedRect.minX, y: extractedRect.minY, width: extractedRect.width, height: extractedRect.width) let initialScale = avatarInitialRect.width / targetRect.width @@ -391,12 +406,14 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { avatarListNode.update(size: targetRect.size, peer: item.peer, isExpanded: true, transition: .immediate) strongSelf.offsetContainerNode.supernode?.addSubnode(avatarListWrapperNode) + strongSelf.audioLevelView?.alpha = 0.0 + strongSelf.avatarListWrapperNode = avatarListWrapperNode strongSelf.avatarListContainerNode = avatarListContainerNode strongSelf.avatarListNode = avatarListNode } } else if let transitionNode = strongSelf.avatarTransitionNode, let avatarListWrapperNode = strongSelf.avatarListWrapperNode, let avatarListContainerNode = strongSelf.avatarListContainerNode { - transition.updateCornerRadius(node: strongSelf.extractedBackgroundImageNode, cornerRadius: cornerRadius) + transition.updateCornerRadius(node: strongSelf.backgroundImageNode, cornerRadius: cornerRadius) var avatarInitialRect = CGRect(origin: strongSelf.avatarNode.frame.origin, size: strongSelf.avatarNode.frame.size) let targetScale = avatarInitialRect.width / avatarListContainerNode.frame.width @@ -415,15 +432,19 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { avatarListWrapperNode.layer.animate(from: NSValue(cgPoint: avatarListWrapperNode.position), to: NSValue(cgPoint: avatarInitialRect.center), keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2, removeOnCompletion: false, completion: { [weak transitionNode, weak self] _ in transitionNode?.removeFromSupernode() self?.avatarNode.isHidden = false + + self?.audioLevelView?.alpha = 1.0 + self?.audioLevelView?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) }) radiusTransition.updateCornerRadius(node: avatarListContainerNode, cornerRadius: avatarListContainerNode.frame.width / 2.0) radiusTransition.updateCornerRadius(node: transitionNode, cornerRadius: avatarListContainerNode.frame.width / 2.0) } - transition.updateAlpha(node: strongSelf.statusNode, alpha: isExtracted ? 0.0 : 1.0) - transition.updateAlpha(node: strongSelf.expandedStatusNode, alpha: isExtracted ? 1.0 : 0.0) - transition.updateAlpha(node: strongSelf.actionContainerNode, alpha: isExtracted ? 0.0 : 1.0) + let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) + alphaTransition.updateAlpha(node: strongSelf.statusNode, alpha: isExtracted ? 0.0 : 1.0) + alphaTransition.updateAlpha(node: strongSelf.expandedStatusNode, alpha: isExtracted ? 1.0 : 0.0) + alphaTransition.updateAlpha(node: strongSelf.actionContainerNode, alpha: isExtracted ? 0.0 : 1.0, delay: isExtracted ? 0.0 : 0.1) let offsetInitialSublayerTransform = strongSelf.offsetContainerNode.layer.sublayerTransform strongSelf.offsetContainerNode.layer.sublayerTransform = CATransform3DMakeTranslation(isExtracted ? -33 : 0.0, isExtracted ? extractedVerticalOffset : 0.0, 0.0) @@ -431,38 +452,50 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { let actionInitialSublayerTransform = strongSelf.actionContainerNode.layer.sublayerTransform strongSelf.actionContainerNode.layer.sublayerTransform = CATransform3DMakeTranslation(isExtracted ? 21.0 : 0.0, 0.0, 0.0) - let extractedInitialBackgroundPosition = strongSelf.extractedBackgroundImageNode.position - strongSelf.extractedBackgroundImageNode.layer.position = rect.center - let extractedInitialBackgroundBounds = strongSelf.extractedBackgroundImageNode.bounds - strongSelf.extractedBackgroundImageNode.layer.bounds = CGRect(origin: CGPoint(), size: rect.size) + let initialBackgroundPosition = strongSelf.backgroundImageNode.position + strongSelf.backgroundImageNode.layer.position = rect.center + let initialBackgroundBounds = strongSelf.backgroundImageNode.bounds + strongSelf.backgroundImageNode.layer.bounds = CGRect(origin: CGPoint(), size: rect.size) + + let initialExtractedBackgroundPosition = strongSelf.extractedBackgroundImageNode.position + strongSelf.extractedBackgroundImageNode.layer.position = CGPoint(x: rect.size.width / 2.0, y: rect.size.height / 2.0) + let initialExtractedBackgroundBounds = strongSelf.extractedBackgroundImageNode.bounds + strongSelf.extractedBackgroundImageNode.layer.bounds = strongSelf.backgroundImageNode.layer.bounds if isExtracted { strongSelf.offsetContainerNode.layer.animateSpring(from: NSValue(caTransform3D: offsetInitialSublayerTransform), to: NSValue(caTransform3D: strongSelf.offsetContainerNode.layer.sublayerTransform), keyPath: "sublayerTransform", duration: springDuration, delay: 0.0, initialVelocity: 0.0, damping: springDamping) strongSelf.actionContainerNode.layer.animateSpring(from: NSValue(caTransform3D: actionInitialSublayerTransform), to: NSValue(caTransform3D: strongSelf.actionContainerNode.layer.sublayerTransform), keyPath: "sublayerTransform", duration: springDuration, delay: 0.0, initialVelocity: 0.0, damping: springDamping) - strongSelf.extractedBackgroundImageNode.layer.animateSpring(from: NSValue(cgPoint: extractedInitialBackgroundPosition), to: NSValue(cgPoint: strongSelf.extractedBackgroundImageNode.position), keyPath: "position", duration: springDuration, delay: 0.0, initialVelocity: 0.0, damping: springDamping) - strongSelf.extractedBackgroundImageNode.layer.animateSpring(from: NSValue(cgRect: extractedInitialBackgroundBounds), to: NSValue(cgRect: strongSelf.extractedBackgroundImageNode.bounds), keyPath: "bounds", duration: springDuration, initialVelocity: 0.0, damping: springDamping) + strongSelf.backgroundImageNode.layer.animateSpring(from: NSValue(cgPoint: initialBackgroundPosition), to: NSValue(cgPoint: strongSelf.backgroundImageNode.position), keyPath: "position", duration: springDuration, delay: 0.0, initialVelocity: 0.0, damping: springDamping) + strongSelf.backgroundImageNode.layer.animateSpring(from: NSValue(cgRect: initialBackgroundBounds), to: NSValue(cgRect: strongSelf.backgroundImageNode.bounds), keyPath: "bounds", duration: springDuration, initialVelocity: 0.0, damping: springDamping) + strongSelf.extractedBackgroundImageNode.layer.animateSpring(from: NSValue(cgPoint: initialExtractedBackgroundPosition), to: NSValue(cgPoint: strongSelf.extractedBackgroundImageNode.position), keyPath: "position", duration: springDuration, delay: 0.0, initialVelocity: 0.0, damping: springDamping) + strongSelf.extractedBackgroundImageNode.layer.animateSpring(from: NSValue(cgRect: initialExtractedBackgroundBounds), to: NSValue(cgRect: strongSelf.extractedBackgroundImageNode.bounds), keyPath: "bounds", duration: springDuration, initialVelocity: 0.0, damping: springDamping) } else { strongSelf.offsetContainerNode.layer.animate(from: NSValue(caTransform3D: offsetInitialSublayerTransform), to: NSValue(caTransform3D: strongSelf.offsetContainerNode.layer.sublayerTransform), keyPath: "sublayerTransform", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2) strongSelf.actionContainerNode.layer.animate(from: NSValue(caTransform3D: actionInitialSublayerTransform), to: NSValue(caTransform3D: strongSelf.actionContainerNode.layer.sublayerTransform), keyPath: "sublayerTransform", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2) - strongSelf.extractedBackgroundImageNode.layer.animate(from: NSValue(cgPoint: extractedInitialBackgroundPosition), to: NSValue(cgPoint: strongSelf.extractedBackgroundImageNode.position), keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2) - strongSelf.extractedBackgroundImageNode.layer.animate(from: NSValue(cgRect: extractedInitialBackgroundBounds), to: NSValue(cgRect: strongSelf.extractedBackgroundImageNode.bounds), keyPath: "bounds", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2) + strongSelf.backgroundImageNode.layer.animate(from: NSValue(cgPoint: initialBackgroundPosition), to: NSValue(cgPoint: strongSelf.backgroundImageNode.position), keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2) + strongSelf.backgroundImageNode.layer.animate(from: NSValue(cgRect: initialBackgroundBounds), to: NSValue(cgRect: strongSelf.backgroundImageNode.bounds), keyPath: "bounds", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2) + strongSelf.extractedBackgroundImageNode.layer.animate(from: NSValue(cgPoint: initialExtractedBackgroundPosition), to: NSValue(cgPoint: strongSelf.extractedBackgroundImageNode.position), keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2) + strongSelf.extractedBackgroundImageNode.layer.animate(from: NSValue(cgRect: initialExtractedBackgroundBounds), to: NSValue(cgRect: strongSelf.extractedBackgroundImageNode.bounds), keyPath: "bounds", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2) } if isExtracted { + strongSelf.backgroundImageNode.alpha = 1.0 strongSelf.extractedBackgroundImageNode.alpha = 1.0 - strongSelf.extractedBackgroundImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.06, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) + strongSelf.extractedBackgroundImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1, delay: 0.1, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) } else { strongSelf.extractedBackgroundImageNode.alpha = 0.0 - strongSelf.extractedBackgroundImageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, delay: 0.1, removeOnCompletion: false, completion: { [weak self] _ in + strongSelf.extractedBackgroundImageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, delay: 0.0, removeOnCompletion: false, completion: { [weak self] _ in + self?.backgroundImageNode.image = nil self?.extractedBackgroundImageNode.image = nil self?.extractedBackgroundImageNode.layer.removeAllAnimations() }) } } else { if isExtracted { + strongSelf.backgroundImageNode.image = generateStretchableFilledCircleImage(diameter: cornerRadius * 2.0, color: UIColor(rgb: 0x2c2c2e)) strongSelf.extractedBackgroundImageNode.image = generateStretchableFilledCircleImage(diameter: cornerRadius * 2.0, color: item.presentationData.theme.list.itemBlocksBackgroundColor) } - transition.updateFrame(node: strongSelf.extractedBackgroundImageNode, frame: rect) + transition.updateFrame(node: strongSelf.backgroundImageNode, frame: rect) transition.updateAlpha(node: strongSelf.statusNode, alpha: isExtracted ? 0.0 : 1.0) transition.updateAlpha(node: strongSelf.expandedStatusNode, alpha: isExtracted ? 1.0 : 0.0) @@ -473,6 +506,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { transition.updateAlpha(node: strongSelf.extractedBackgroundImageNode, alpha: isExtracted ? 1.0 : 0.0, completion: { _ in if !isExtracted { + self?.backgroundImageNode.image = nil self?.extractedBackgroundImageNode.image = nil } }) @@ -714,10 +748,11 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { strongSelf.nonExtractedRect = nonExtractedRect if strongSelf.isExtracted { - strongSelf.extractedBackgroundImageNode.frame = extractedRect + strongSelf.backgroundImageNode.frame = extractedRect } else { - strongSelf.extractedBackgroundImageNode.frame = nonExtractedRect + strongSelf.backgroundImageNode.frame = nonExtractedRect } + strongSelf.extractedBackgroundImageNode.frame = strongSelf.backgroundImageNode.bounds strongSelf.contextSourceNode.contentRect = extractedRect strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize) @@ -855,6 +890,8 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { audioLevelView.layer.mask = playbackMaskLayer audioLevelView.setColor(wavesColor) + audioLevelView.alpha = strongSelf.isExtracted ? 0.0 : 1.0 + strongSelf.audioLevelView = audioLevelView strongSelf.offsetContainerNode.view.insertSubview(audioLevelView, at: 0) } From 7803f5604f5f08e09dba5e92c4f3dfdba6df03a0 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 24 Mar 2021 20:11:15 +0400 Subject: [PATCH 2/2] Fix API and clear join as cache on error --- submodules/TelegramApi/Sources/Api0.swift | 2 +- submodules/TelegramApi/Sources/Api2.swift | 20 +++---- .../Sources/PresentationGroupCall.swift | 1 + .../TelegramCore/Sources/GroupCalls.swift | 53 +++++++++++++++---- .../TelegramCore/Sources/Serialization.swift | 2 +- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 26778f64de..7e1902600a 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -142,7 +142,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[767652808] = { return Api.InputEncryptedFile.parse_inputEncryptedFileBigUploaded($0) } dict[1304052993] = { return Api.account.Takeout.parse_takeout($0) } dict[-1456996667] = { return Api.messages.InactiveChats.parse_inactiveChats($0) } - dict[-1184160274] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) } + dict[430815881] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) } dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) } dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) } dict[289586518] = { return Api.SavedContact.parse_savedPhoneContact($0) } diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 8ddcfa52dc..9466f52bb2 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -3604,13 +3604,13 @@ public extension Api { } public enum GroupCallParticipant: TypeConstructorDescription { - case groupCallParticipant(flags: Int32, peer: Api.Peer, date: Int32, activeDate: Int32?, source: Int32, volume: Int32?, about: String?, raiseHandRating: Int64?, params: Api.DataJSON?) + case groupCallParticipant(flags: Int32, peer: Api.Peer, date: Int32, activeDate: Int32?, source: Int32, volume: Int32?, about: String?, raiseHandRating: Int64?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating, let params): + case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating): if boxed { - buffer.appendInt32(-1184160274) + buffer.appendInt32(430815881) } serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) @@ -3620,15 +3620,14 @@ public extension Api { if Int(flags) & Int(1 << 7) != 0 {serializeInt32(volume!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 11) != 0 {serializeString(about!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 13) != 0 {serializeInt64(raiseHandRating!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 6) != 0 {params!.serialize(buffer, true)} break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating, let params): - return ("groupCallParticipant", [("flags", flags), ("peer", peer), ("date", date), ("activeDate", activeDate), ("source", source), ("volume", volume), ("about", about), ("raiseHandRating", raiseHandRating), ("params", params)]) + case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating): + return ("groupCallParticipant", [("flags", flags), ("peer", peer), ("date", date), ("activeDate", activeDate), ("source", source), ("volume", volume), ("about", about), ("raiseHandRating", raiseHandRating)]) } } @@ -3651,10 +3650,6 @@ public extension Api { if Int(_1!) & Int(1 << 11) != 0 {_7 = parseString(reader) } var _8: Int64? if Int(_1!) & Int(1 << 13) != 0 {_8 = reader.readInt64() } - var _9: Api.DataJSON? - if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() { - _9 = Api.parse(reader, signature: signature) as? Api.DataJSON - } } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -3663,9 +3658,8 @@ public extension Api { let _c6 = (Int(_1!) & Int(1 << 7) == 0) || _6 != nil let _c7 = (Int(_1!) & Int(1 << 11) == 0) || _7 != nil let _c8 = (Int(_1!) & Int(1 << 13) == 0) || _8 != nil - let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { - return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, peer: _2!, date: _3!, activeDate: _4, source: _5!, volume: _6, about: _7, raiseHandRating: _8, params: _9) + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, peer: _2!, date: _3!, activeDate: _4, source: _5!, volume: _6, about: _7, raiseHandRating: _8) } else { return nil diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index eceae9d0c4..99eff47079 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -1184,6 +1184,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { ]), on: .root, blockInteraction: false, completion: {}) } else if case .invalidJoinAsPeer = error { let peerId = strongSelf.peerId + let _ = clearCachedGroupCallDisplayAsAvailablePeers(account: strongSelf.accountContext.account, peerId: peerId).start() let _ = (strongSelf.accountContext.account.postbox.transaction { transaction -> Void in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in if let current = current as? CachedChannelData { diff --git a/submodules/TelegramCore/Sources/GroupCalls.swift b/submodules/TelegramCore/Sources/GroupCalls.swift index 7954809f98..f7b4c48da9 100644 --- a/submodules/TelegramCore/Sources/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/GroupCalls.swift @@ -110,7 +110,8 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int loop: for participant in participants { switch participant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/): + let params: Api.DataJSON? = nil let peerId: PeerId switch apiPeerId { case let .peerUser(userId): @@ -297,7 +298,8 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash loop: for participant in participants { switch participant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/): + let params: Api.DataJSON? = nil let peerId: PeerId switch apiPeerId { case let .peerUser(userId): @@ -404,15 +406,35 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal } let joinRequest = account.network.request(Api.functions.phone.joinGroupCall(flags: flags, call: .inputGroupCall(id: callId, accessHash: accessHash), joinAs: inputJoinAs, inviteHash: inviteHash, params: .dataJSON(data: joinPayload))) - |> mapError { error -> JoinGroupCallError in + |> `catch` { error -> Signal in if error.errorDescription == "GROUPCALL_ANONYMOUS_FORBIDDEN" { - return .anonymousNotAllowed + return .fail(.anonymousNotAllowed) } else if error.errorDescription == "GROUPCALL_PARTICIPANTS_TOO_MUCH" { - return .tooManyParticipants + return .fail(.tooManyParticipants) } else if error.errorDescription == "JOIN_AS_PEER_INVALID" { - return .invalidJoinAsPeer + return .fail(.invalidJoinAsPeer) + } else if error.errorDescription == "GROUPCALL_INVALID" { + return account.postbox.transaction { transaction -> Signal in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in + if let current = current as? CachedGroupData { + if current.activeCall?.id == callId { + return current.withUpdatedActiveCall(nil) + } + } else if let current = current as? CachedChannelData { + if current.activeCall?.id == callId { + return current.withUpdatedActiveCall(nil) + } + } + return current + }) + + return .fail(.generic) + } + |> castError(JoinGroupCallError.self) + |> switchToLatest + } else { + return .fail(.generic) } - return .generic } let getParticipantsRequest = getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, offset: "", ssrcs: [], limit: 100, sortAscending: true) @@ -525,7 +547,8 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal case let .updateGroupCallParticipants(_, participants, _): loop: for participant in participants { switch participant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/): + let params: Api.DataJSON? = nil let peerId: PeerId switch apiPeerId { case let .peerUser(userId): @@ -1731,7 +1754,8 @@ public final class GroupCallParticipantsContext { extension GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate { init(_ apiParticipant: Api.GroupCallParticipant) { switch apiParticipant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/): + let params: Api.DataJSON? = nil let peerId: PeerId switch apiPeerId { case let .peerUser(userId): @@ -1794,7 +1818,8 @@ extension GroupCallParticipantsContext.Update.StateUpdate { var participantUpdates: [GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate] = [] for participant in participants { switch participant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/): + let params: Api.DataJSON? = nil let peerId: PeerId switch apiPeerId { case let .peerUser(userId): @@ -2016,6 +2041,14 @@ public final class CachedDisplayAsPeers: PostboxCoding { } } +public func clearCachedGroupCallDisplayAsAvailablePeers(account: Account, peerId: PeerId) -> Signal { + return account.postbox.transaction { transaction -> Void in + let key = ValueBoxKey(length: 8) + key.setInt64(0, value: peerId.toInt64()) + transaction.removeItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedGroupCallDisplayAsPeers, key: key)) + } + |> ignoreValues +} public func cachedGroupCallDisplayAsAvailablePeers(account: Account, peerId: PeerId) -> Signal<[FoundPeer], NoError> { let key = ValueBoxKey(length: 8) diff --git a/submodules/TelegramCore/Sources/Serialization.swift b/submodules/TelegramCore/Sources/Serialization.swift index 9e06595675..8a525de035 100644 --- a/submodules/TelegramCore/Sources/Serialization.swift +++ b/submodules/TelegramCore/Sources/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 127 + return 126 } public func parseMessage(_ data: Data!) -> Any! {