From 682672862e753036bd5fa44942a304e4ce5df8c2 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 15 Dec 2020 18:23:58 +0400 Subject: [PATCH 1/5] Use immediate thumbnails in sticker packs roll and settings --- submodules/ItemListStickerPackItem/BUILD | 1 + .../Sources/ItemListStickerPackItem.swift | 58 +++++++++++++++- .../Sources/StickerShimmerEffectNode.swift | 4 +- .../Sources/StickerPackCollectionInfo.swift | 15 ++++- .../TelegramCore/Sources/StickerPack.swift | 66 +++++++++++-------- .../StickerPackInteractiveOperations.swift | 2 +- .../Sources/ChatMediaInputNode.swift | 6 +- .../ChatMediaInputStickerPackItem.swift | 40 ++--------- 8 files changed, 120 insertions(+), 72 deletions(-) diff --git a/submodules/ItemListStickerPackItem/BUILD b/submodules/ItemListStickerPackItem/BUILD index a53501ed9c..83a4ae4d6e 100644 --- a/submodules/ItemListStickerPackItem/BUILD +++ b/submodules/ItemListStickerPackItem/BUILD @@ -19,6 +19,7 @@ swift_library( "//submodules/AnimatedStickerNode:AnimatedStickerNode", "//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode", "//submodules/PresentationDataUtils:PresentationDataUtils", + "//submodules/ShimmerEffect:ShimmerEffect", ], visibility = [ "//visibility:public", diff --git a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift index 6a691bd2bb..beb238b11d 100644 --- a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift +++ b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift @@ -12,6 +12,7 @@ import PresentationDataUtils import StickerResources import AnimatedStickerNode import TelegramAnimatedStickerNode +import ShimmerEffect public struct ItemListStickerPackItemEditing: Equatable { public var editable: Bool @@ -149,6 +150,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { fileprivate let imageNode: TransformImageNode private var animationNode: AnimatedStickerNode? + private var placeholderNode: StickerShimmerEffectNode? private let unreadNode: ASImageNode private let titleNode: TextNode private let statusNode: TextNode @@ -200,6 +202,9 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { self.imageNode = TransformImageNode() self.imageNode.isLayerBacked = !smartInvertColorsEnabled() + self.placeholderNode = StickerShimmerEffectNode() + self.placeholderNode?.isUserInteractionEnabled = false + self.titleNode = TextNode() self.titleNode.isUserInteractionEnabled = false self.titleNode.contentMode = .left @@ -231,7 +236,11 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) + if let placeholderNode = self.placeholderNode { + self.addSubnode(placeholderNode) + } self.addSubnode(self.imageNode) + self.addSubnode(self.titleNode) self.addSubnode(self.statusNode) self.addSubnode(self.unreadNode) @@ -251,12 +260,50 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { } } } + + var firstTime = true + self.imageNode.imageUpdated = { [weak self] image in + guard let strongSelf = self else { + return + } + if image != nil { + strongSelf.removePlaceholder(animated: !firstTime) + if firstTime { + strongSelf.imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + } + firstTime = false + } } deinit { self.fetchDisposable.dispose() } + private func removePlaceholder(animated: Bool) { + if let placeholderNode = self.placeholderNode { + self.placeholderNode = nil + if !animated { + placeholderNode.removeFromSupernode() + } else { + placeholderNode.allowsGroupOpacity = true + placeholderNode.alpha = 0.0 + placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak placeholderNode] _ in + placeholderNode?.removeFromSupernode() + placeholderNode?.allowsGroupOpacity = false + }) + } + } + } + + private var absoluteLocation: (CGRect, CGSize)? + override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { + self.absoluteLocation = (rect, containerSize) + if let placeholderNode = placeholderNode { + placeholderNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: rect.minX + placeholderNode.frame.minX, y: rect.minY + placeholderNode.frame.minY), size: placeholderNode.frame.size), within: containerSize) + } + } + func asyncLayout() -> (_ item: ItemListStickerPackItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool) -> Void) { let makeImageLayout = self.imageNode.asyncLayout() let makeTitleLayout = TextNode.asyncLayout(self.titleNode) @@ -397,14 +444,14 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { if fileUpdated { imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: stillImageSize, boundingSize: stillImageSize, intrinsicInsets: UIEdgeInsets())) - updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: representation.resource) + updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: representation.resource, nilIfEmpty: true) } case let .animated(resource): imageSize = imageBoundingSize if fileUpdated { imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageBoundingSize, boundingSize: imageBoundingSize, intrinsicInsets: UIEdgeInsets())) - updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: resource, animated: true) + updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: resource, animated: true, nilIfEmpty: true) } } if fileUpdated, let resourceReference = resourceReference { @@ -610,6 +657,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { animationNode = AnimatedStickerNode() strongSelf.animationNode = animationNode strongSelf.addSubnode(animationNode) + animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource), width: 80, height: 80, mode: .cached) } animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers @@ -619,6 +667,12 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { transition.updateFrame(node: animationNode, frame: imageFrame) } } + + if let placeholderNode = strongSelf.placeholderNode { + placeholderNode.frame = imageFrame + + placeholderNode.update(backgroundColor: nil, foregroundColor: item.presentationData.theme.list.disclosureArrowColor.blitOver(item.presentationData.theme.list.itemBlocksBackgroundColor, alpha: 0.55), shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: item.packInfo.immediateThumbnailData, size: imageFrame.size, small: true) + } } if let updatedImageSignal = updatedImageSignal { diff --git a/submodules/ShimmerEffect/Sources/StickerShimmerEffectNode.swift b/submodules/ShimmerEffect/Sources/StickerShimmerEffectNode.swift index 54ab7d6fdf..49f41c65b3 100644 --- a/submodules/ShimmerEffect/Sources/StickerShimmerEffectNode.swift +++ b/submodules/ShimmerEffect/Sources/StickerShimmerEffectNode.swift @@ -168,7 +168,7 @@ public class StickerShimmerEffectNode: ASDisplayNode { self.effectNode.updateAbsoluteRect(rect, within: containerSize) } - public func update(backgroundColor: UIColor?, foregroundColor: UIColor, shimmeringColor: UIColor, data: Data?, size: CGSize) { + public func update(backgroundColor: UIColor?, foregroundColor: UIColor, shimmeringColor: UIColor, data: Data?, size: CGSize, small: Bool = false) { if data == nil { return } @@ -205,7 +205,7 @@ public class StickerShimmerEffectNode: ASDisplayNode { let reader = PathDataReader(input: path) let segments = reader.read() - let scale = size.width / 512.0 + let scale = size.width / (small ? 100.0 : 512.0) context.scaleBy(x: scale, y: scale) renderPath(segments, context: context) } else { diff --git a/submodules/SyncCore/Sources/StickerPackCollectionInfo.swift b/submodules/SyncCore/Sources/StickerPackCollectionInfo.swift index 912192cb1a..c39c2dd528 100644 --- a/submodules/SyncCore/Sources/StickerPackCollectionInfo.swift +++ b/submodules/SyncCore/Sources/StickerPackCollectionInfo.swift @@ -1,3 +1,4 @@ +import Foundation import Postbox public struct StickerPackCollectionInfoFlags: OptionSet { @@ -40,16 +41,18 @@ public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable { public let title: String public let shortName: String public let thumbnail: TelegramMediaImageRepresentation? + public let immediateThumbnailData: Data? public let hash: Int32 public let count: Int32 - public init(id: ItemCollectionId, flags: StickerPackCollectionInfoFlags, accessHash: Int64, title: String, shortName: String, thumbnail: TelegramMediaImageRepresentation?, hash: Int32, count: Int32) { + public init(id: ItemCollectionId, flags: StickerPackCollectionInfoFlags, accessHash: Int64, title: String, shortName: String, thumbnail: TelegramMediaImageRepresentation?, immediateThumbnailData: Data?, hash: Int32, count: Int32) { self.id = id self.flags = flags self.accessHash = accessHash self.title = title self.shortName = shortName self.thumbnail = thumbnail + self.immediateThumbnailData = immediateThumbnailData self.hash = hash self.count = count } @@ -60,6 +63,7 @@ public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable { self.title = decoder.decodeStringForKey("t", orElse: "") self.shortName = decoder.decodeStringForKey("s", orElse: "") self.thumbnail = decoder.decodeObjectForKey("th", decoder: { TelegramMediaImageRepresentation(decoder: $0) }) as? TelegramMediaImageRepresentation + self.immediateThumbnailData = decoder.decodeDataForKey("itd") self.hash = decoder.decodeInt32ForKey("h", orElse: 0) self.flags = StickerPackCollectionInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) self.count = decoder.decodeInt32ForKey("n", orElse: 0) @@ -76,6 +80,11 @@ public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable { } else { encoder.encodeNil(forKey: "th") } + if let immediateThumbnailData = self.immediateThumbnailData { + encoder.encodeData(immediateThumbnailData, forKey: "itd") + } else { + encoder.encodeNil(forKey: "itd") + } encoder.encodeInt32(self.hash, forKey: "h") encoder.encodeInt32(self.flags.rawValue, forKey: "f") encoder.encodeInt32(self.count, forKey: "n") @@ -98,6 +107,10 @@ public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable { return false } + if lhs.immediateThumbnailData != rhs.immediateThumbnailData { + return false + } + if lhs.flags != rhs.flags { return false } diff --git a/submodules/TelegramCore/Sources/StickerPack.swift b/submodules/TelegramCore/Sources/StickerPack.swift index f1812d322d..1c50f6fa9e 100644 --- a/submodules/TelegramCore/Sources/StickerPack.swift +++ b/submodules/TelegramCore/Sources/StickerPack.swift @@ -5,33 +5,38 @@ import SwiftSignalKit import SyncCore import MtProtoKit -func telegramStickerPackThumbnailRepresentationFromApiSize(datacenterId: Int32, size: Api.PhotoSize) -> TelegramMediaImageRepresentation? { - switch size { - case let .photoCachedSize(_, location, w, h, _): - switch location { - case let .fileLocationToBeDeprecated(volumeId, localId): - let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) - return TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource, progressiveSizes: []) - } - case let .photoSize(_, location, w, h, _): - switch location { - case let .fileLocationToBeDeprecated(volumeId, localId): - let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) - return TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource, progressiveSizes: []) - } - case let .photoSizeProgressive(_, location, w, h, sizes): - switch location { - case let .fileLocationToBeDeprecated(volumeId, localId): - let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) - return TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource, progressiveSizes: sizes) - } - case let .photoPathSize(_, data): - return nil - case .photoStrippedSize: - return nil - case .photoSizeEmpty: - return nil +func telegramStickerPackThumbnailRepresentationFromApiSizes(datacenterId: Int32, sizes: [Api.PhotoSize]) -> (immediateThumbnail: Data?, representations: [TelegramMediaImageRepresentation]) { + var immediateThumbnailData: Data? + var representations: [TelegramMediaImageRepresentation] = [] + for size in sizes { + switch size { + case let .photoCachedSize(_, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) + representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource, progressiveSizes: [])) + } + case let .photoSize(_, location, w, h, _): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) + representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource, progressiveSizes: [])) + } + case let .photoSizeProgressive(_, location, w, h, sizes): + switch location { + case let .fileLocationToBeDeprecated(volumeId, localId): + let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) + representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource, progressiveSizes: sizes)) + } + case let .photoPathSize(_, data): + immediateThumbnailData = data.makeData() + case .photoStrippedSize: + break + case .photoSizeEmpty: + break + } } + return (immediateThumbnailData, representations) } extension StickerPackCollectionInfo { @@ -50,11 +55,14 @@ extension StickerPackCollectionInfo { } var thumbnailRepresentation: TelegramMediaImageRepresentation? - if let thumb = thumbs?.first, let thumbDcId = thumbDcId { - thumbnailRepresentation = telegramStickerPackThumbnailRepresentationFromApiSize(datacenterId: thumbDcId, size: thumb) + var immediateThumbnailData: Data? + if let thumbs = thumbs, let thumbDcId = thumbDcId { + let (data, representations) = telegramStickerPackThumbnailRepresentationFromApiSizes(datacenterId: thumbDcId, sizes: thumbs) + thumbnailRepresentation = representations.first + immediateThumbnailData = data } - self.init(id: ItemCollectionId(namespace: namespace, id: id), flags: setFlags, accessHash: accessHash, title: title, shortName: shortName, thumbnail: thumbnailRepresentation, hash: nHash, count: count) + self.init(id: ItemCollectionId(namespace: namespace, id: id), flags: setFlags, accessHash: accessHash, title: title, shortName: shortName, thumbnail: thumbnailRepresentation, immediateThumbnailData: immediateThumbnailData, hash: nHash, count: count) } } } diff --git a/submodules/TelegramCore/Sources/StickerPackInteractiveOperations.swift b/submodules/TelegramCore/Sources/StickerPackInteractiveOperations.swift index 14b0b46ffa..bc360ef827 100644 --- a/submodules/TelegramCore/Sources/StickerPackInteractiveOperations.swift +++ b/submodules/TelegramCore/Sources/StickerPackInteractiveOperations.swift @@ -18,7 +18,7 @@ public func addStickerPackInteractively(postbox: Postbox, info: StickerPackColle if let namespace = namespace { var mappedInfo = info if items.isEmpty { - mappedInfo = StickerPackCollectionInfo(id: info.id, flags: info.flags, accessHash: info.accessHash, title: info.title, shortName: info.shortName, thumbnail: info.thumbnail, hash: Int32(bitPattern: arc4random()), count: info.count) + mappedInfo = StickerPackCollectionInfo(id: info.id, flags: info.flags, accessHash: info.accessHash, title: info.title, shortName: info.shortName, thumbnail: info.thumbnail, immediateThumbnailData: info.immediateThumbnailData, hash: Int32(bitPattern: arc4random()), count: info.count) } addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: namespace, content: .add([mappedInfo.id]), noDelay: items.isEmpty) var updatedInfos = transaction.getItemCollectionsInfos(namespace: mappedInfo.id.namespace).map { $0.1 as! StickerPackCollectionInfo } diff --git a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift index 3db7dff3f3..473bad97bd 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift @@ -238,7 +238,7 @@ func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: Ordered if view.lower == nil { var savedStickerIds = Set() if let savedStickers = savedStickers, !savedStickers.items.isEmpty { - let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.savedStickers.rawValue, id: 0), flags: [], accessHash: 0, title: strings.Stickers_FavoriteStickers.uppercased(), shortName: "", thumbnail: nil, hash: 0, count: 0) + let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.savedStickers.rawValue, id: 0), flags: [], accessHash: 0, title: strings.Stickers_FavoriteStickers.uppercased(), shortName: "", thumbnail: nil, immediateThumbnailData: nil, hash: 0, count: 0) for i in 0 ..< savedStickers.items.count { if let item = savedStickers.items[i].contents as? SavedStickerItem { savedStickerIds.insert(item.file.fileId.id) @@ -250,7 +250,7 @@ func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: Ordered } if let recentStickers = recentStickers, !recentStickers.items.isEmpty { - let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.recentStickers.rawValue, id: 0), flags: [], accessHash: 0, title: strings.Stickers_FrequentlyUsed.uppercased(), shortName: "", thumbnail: nil, hash: 0, count: 0) + let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.recentStickers.rawValue, id: 0), flags: [], accessHash: 0, title: strings.Stickers_FrequentlyUsed.uppercased(), shortName: "", thumbnail: nil, immediateThumbnailData: nil, hash: 0, count: 0) var addedCount = 0 for i in 0 ..< recentStickers.items.count { if addedCount >= 20 { @@ -278,7 +278,7 @@ func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: Ordered if let peerSpecificPack = peerSpecificPack { for i in 0 ..< peerSpecificPack.items.count { - let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.peerSpecific.rawValue, id: 0), flags: [], accessHash: 0, title: strings.Stickers_GroupStickers, shortName: "", thumbnail: nil, hash: 0, count: 0) + let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.peerSpecific.rawValue, id: 0), flags: [], accessHash: 0, title: strings.Stickers_GroupStickers, shortName: "", thumbnail: nil, immediateThumbnailData: nil, hash: 0, count: 0) if let item = peerSpecificPack.items[i] as? StickerPackItem { let index = ItemCollectionItemIndex(index: Int32(i), id: item.file.fileId.id) diff --git a/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift b/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift index e71e34f069..8691407568 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift @@ -76,8 +76,7 @@ private let verticalOffset: CGFloat = 3.0 final class ChatMediaInputStickerPackItemNode: ListViewItemNode { private let imageNode: TransformImageNode private var animatedStickerNode: AnimatedStickerNode? - private var placeholderNode: ShimmerEffectNode? - private var placeholderImageNode: ASImageNode? + private var placeholderNode: StickerShimmerEffectNode? private let highlightNode: ASImageNode var inputNodeInteraction: ChatMediaInputNodeInteraction? @@ -109,11 +108,8 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { self.imageNode = TransformImageNode() self.imageNode.isLayerBacked = !smartInvertColorsEnabled() - - self.placeholderImageNode = ASImageNode() - self.placeholderImageNode?.isUserInteractionEnabled = false - - //self.placeholderNode = ShimmerEffectNode() + + self.placeholderNode = StickerShimmerEffectNode() self.highlightNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - highlightSize.width) / 2.0) + verticalOffset - UIScreenPixel, y: floor((boundingSize.height - highlightSize.height) / 2.0) - UIScreenPixel), size: highlightSize) @@ -124,9 +120,6 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { self.addSubnode(self.highlightNode) self.addSubnode(self.imageNode) - if let placeholderImageNode = self.placeholderImageNode { - self.addSubnode(placeholderImageNode) - } if let placeholderNode = self.placeholderNode { self.addSubnode(placeholderNode) } @@ -159,17 +152,6 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { }) } } - if let placeholderImageNode = self.placeholderImageNode { - self.placeholderImageNode = nil - if !animated { - placeholderImageNode.removeFromSupernode() - } else { - placeholderImageNode.alpha = 0.0 - placeholderImageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak placeholderImageNode] _ in - placeholderImageNode?.removeFromSupernode() - }) - } - } } func updateStickerPackItem(account: Account, info: StickerPackCollectionInfo, item: StickerPackItem?, collectionId: ItemCollectionId, theme: PresentationTheme) { @@ -244,24 +226,14 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: resourceReference).start()) } } - - if let placeholderImageNode = self.placeholderImageNode { - if placeholderImageNode.image == nil { - placeholderImageNode.image = generateStretchableFilledCircleImage(diameter: 10.0, color: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.3)) - } - let size = boundingSize - let imageSize = boundingImageSize - let placeholderFrame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize) - placeholderImageNode.frame = placeholderFrame - } - + if let placeholderNode = self.placeholderNode { let size = boundingSize let imageSize = boundingImageSize let placeholderFrame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize) placeholderNode.frame = CGRect(origin: CGPoint(), size: size) - placeholderNode.update(backgroundColor: theme.chat.inputPanel.panelBackgroundColor, foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputPanel.panelBackgroundColor, alpha: 0.4), shimmeringColor: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.2), shapes: [.roundedRect(rect: placeholderFrame, cornerRadius: 5.0)], size: bounds.size) + placeholderNode.update(backgroundColor: theme.chat.inputPanel.panelBackgroundColor, foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputPanel.panelBackgroundColor, alpha: 0.4), shimmeringColor: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.2), data: info.immediateThumbnailData, size: bounds.size, small: true) } self.updateIsHighlighted() @@ -270,7 +242,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { if let placeholderNode = self.placeholderNode { - //placeholderNode.updateAbsoluteRect(rect, within: containerSize) + placeholderNode.updateAbsoluteRect(rect, within: containerSize) } } From 5488caa22fbf16872a828dffb15f65c13ecd1440 Mon Sep 17 00:00:00 2001 From: overtake Date: Tue, 15 Dec 2020 18:37:40 +0400 Subject: [PATCH 2/5] fix event log --- submodules/TelegramCore/Sources/ChannelAdminEventLogs.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/TelegramCore/Sources/ChannelAdminEventLogs.swift b/submodules/TelegramCore/Sources/ChannelAdminEventLogs.swift index c159d53cd6..61e071d4af 100644 --- a/submodules/TelegramCore/Sources/ChannelAdminEventLogs.swift +++ b/submodules/TelegramCore/Sources/ChannelAdminEventLogs.swift @@ -224,10 +224,10 @@ public func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: Pe action = .endGroupCall case let .channelAdminLogEventActionParticipantMute(participant): let parsedParticipant = GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate(participant) - action = .groupCallUpdateParticipantMuteStatus(peerId: parsedParticipant.peerId, isMuted: parsedParticipant.muteState != nil) + action = .groupCallUpdateParticipantMuteStatus(peerId: parsedParticipant.peerId, isMuted: true) case let .channelAdminLogEventActionParticipantUnmute(participant): let parsedParticipant = GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate(participant) - action = .groupCallUpdateParticipantMuteStatus(peerId: parsedParticipant.peerId, isMuted: parsedParticipant.muteState != nil) + action = .groupCallUpdateParticipantMuteStatus(peerId: parsedParticipant.peerId, isMuted: false) case let .channelAdminLogEventActionToggleGroupCallSetting(joinMuted): action = .updateGroupCallSettings(joinMuted: joinMuted == .boolTrue) } From 61a3e836b475220248b63c7ce1d2c60a1ef84123 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 15 Dec 2020 18:49:44 +0400 Subject: [PATCH 3/5] Fix placeholder dimensions --- .../Sources/ChatMediaInputStickerPackItem.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift b/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift index 8691407568..974fa82321 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputStickerPackItem.swift @@ -110,6 +110,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { self.imageNode.isLayerBacked = !smartInvertColorsEnabled() self.placeholderNode = StickerShimmerEffectNode() + self.placeholderNode?.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0) self.highlightNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - highlightSize.width) / 2.0) + verticalOffset - UIScreenPixel, y: floor((boundingSize.height - highlightSize.height) / 2.0) - UIScreenPixel), size: highlightSize) @@ -131,6 +132,9 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { } if image != nil { strongSelf.removePlaceholder(animated: !firstTime) + if firstTime { + strongSelf.imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } } firstTime = false } @@ -228,12 +232,11 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { } if let placeholderNode = self.placeholderNode { - let size = boundingSize let imageSize = boundingImageSize let placeholderFrame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize) - placeholderNode.frame = CGRect(origin: CGPoint(), size: size) + placeholderNode.frame = placeholderFrame - placeholderNode.update(backgroundColor: theme.chat.inputPanel.panelBackgroundColor, foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputPanel.panelBackgroundColor, alpha: 0.4), shimmeringColor: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.2), data: info.immediateThumbnailData, size: bounds.size, small: true) + placeholderNode.update(backgroundColor: nil, foregroundColor: theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(theme.chat.inputPanel.panelBackgroundColor, alpha: 0.4), shimmeringColor: theme.chat.inputMediaPanel.panelHighlightedIconBackgroundColor.withMultipliedAlpha(0.2), data: info.immediateThumbnailData, size: imageSize, small: true) } self.updateIsHighlighted() From 667fab2fd50565eae21734e9f5e82297d1d970f0 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 15 Dec 2020 19:24:50 +0400 Subject: [PATCH 4/5] Update Xcode version --- buildbox/build-telegram.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildbox/build-telegram.sh b/buildbox/build-telegram.sh index 0bcdd57801..38a7bf6fd8 100644 --- a/buildbox/build-telegram.sh +++ b/buildbox/build-telegram.sh @@ -5,7 +5,7 @@ set -e BUILD_TELEGRAM_VERSION="1" MACOS_VERSION="10.15" -XCODE_VERSION="12.1" +XCODE_VERSION="12.2" GUEST_SHELL="bash" VM_BASE_NAME="macos$(echo $MACOS_VERSION | sed -e 's/\.'/_/g)_Xcode$(echo $XCODE_VERSION | sed -e 's/\.'/_/g)" From 53b762dab07fa9d2c752582686bd84d5b5f2d04f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 15 Dec 2020 20:22:47 +0400 Subject: [PATCH 5/5] UI fixes --- .../Sources/Node/ChatListItem.swift | 2 +- .../ChannelMembersSearchControllerNode.swift | 10 +++++++ .../Sources/PresentationGroupCall.swift | 28 ++++++++++++++----- .../Sources/VoiceChatController.swift | 19 +++++++++---- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index d989df2a68..dda4cb7325 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -1319,7 +1319,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } badgeSize = max(badgeSize, reorderInset) - let (authorLayout, authorApply) = authorLayout(TextNodeLayoutArguments(attributedString: hideAuthor ? nil : authorAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: rawContentWidth - badgeSize, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 1.0, bottom: 2.0, right: 1.0))) + let (authorLayout, authorApply) = authorLayout(TextNodeLayoutArguments(attributedString: (hideAuthor && !hasDraft) ? nil : authorAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: rawContentWidth - badgeSize, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 1.0, bottom: 2.0, right: 1.0))) var textCutout: TextNodeCutout? if !textLeftCutout.isZero { diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift index 70dd623548..6722f996b2 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift @@ -263,6 +263,16 @@ class ChannelMembersSearchControllerNode: ASDisplayNode { } var entries: [ChannelMembersSearchEntry] = [] + if case .inviteToCall = mode, !filters.contains(where: { filter in + if case .excludeNonMembers = filter { + return true + } else { + return false + } + }) { + entries.append(.copyInviteLink) + } + var index = 0 for participant in participants.participants { guard let peer = peerView.peers[participant.peerId] else { diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 3430b1924e..1d805f9554 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -1114,13 +1114,27 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { self._canBeRemoved.set(.single(true)) if self.didConnectOnce { - let toneRenderer = PresentationCallToneRenderer(tone: .groupLeft) - self.toneRenderer = toneRenderer - toneRenderer.setAudioSessionActive(self.isAudioSessionActive) - - Queue.mainQueue().after(1.0, { - self.wasRemoved.set(.single(true)) - }) + if let callManager = self.accountContext.sharedContext.callManager { + let _ = (callManager.currentGroupCallSignal + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] call in + guard let strongSelf = self else { + return + } + if let call = call, call !== strongSelf { + strongSelf.wasRemoved.set(.single(true)) + return + } + + let toneRenderer = PresentationCallToneRenderer(tone: .groupLeft) + strongSelf.toneRenderer = toneRenderer + toneRenderer.setAudioSessionActive(strongSelf.isAudioSessionActive) + + Queue.mainQueue().after(1.0, { + strongSelf.wasRemoved.set(.single(true)) + }) + }) + } } } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index a66eed1ac5..878cac44fd 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -575,7 +575,7 @@ public final class VoiceChatController: ViewController { filters.append(.excludeNonMembers) } } else if let groupPeer = groupPeer as? TelegramGroup { - if !groupPeer.hasBannedPermission(.banAddMembers) { + if groupPeer.hasBannedPermission(.banAddMembers) { filters.append(.excludeNonMembers) } } @@ -984,11 +984,20 @@ public final class VoiceChatController: ViewController { strongSelf.accountPeer = accountPeer strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set()) - if let peer = peerViewMainPeer(view), let channel = peer as? TelegramChannel { - let addressName = channel.addressName ?? "" - if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) { - if addressName.isEmpty { + if let peer = peerViewMainPeer(view) { + if let channel = peer as? TelegramChannel { + let addressName = channel.addressName ?? "" + if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) { + if addressName.isEmpty { + let _ = ensuredExistingPeerExportedInvitation(account: strongSelf.context.account, peerId: call.peerId).start() + } + } + } else if let group = peer as? TelegramGroup { + switch group.role { + case .creator, .admin: let _ = ensuredExistingPeerExportedInvitation(account: strongSelf.context.account, peerId: call.peerId).start() + default: + break } } }