diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAsset.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAsset.h index 2178a91e97..fc69fab2d0 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAsset.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAsset.h @@ -37,6 +37,7 @@ typedef enum @property (nonatomic, readonly) bool representsBurst; @property (nonatomic, readonly) NSString *uniformTypeIdentifier; @property (nonatomic, readonly) NSString *fileName; +@property (nonatomic, readonly) NSInteger fileSize; @property (nonatomic, readonly) TGMediaAssetType type; @property (nonatomic, readonly) TGMediaAssetSubtype subtypes; diff --git a/submodules/LegacyComponents/Sources/TGMediaAsset.m b/submodules/LegacyComponents/Sources/TGMediaAsset.m index 405b0657a9..ac9f4ca0b2 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAsset.m +++ b/submodules/LegacyComponents/Sources/TGMediaAsset.m @@ -64,6 +64,16 @@ return self.backingAsset.representsBurst; } +- (NSInteger)fileSize { + if (self.backingAsset != nil) { + PHAssetResource *resource = [PHAssetResource assetResourcesForAsset:self.backingAsset].firstObject; + if (resource != nil) { + return [[resource valueForKey:@"fileSize"] integerValue]; + } + } + return 0; +} + - (NSString *)uniformTypeIdentifier { if (self.backingAsset != nil) diff --git a/submodules/LegacyComponents/Sources/TGMediaAssetModernImageSignals.m b/submodules/LegacyComponents/Sources/TGMediaAssetModernImageSignals.m index 2abd400f16..8aed6ebb4c 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAssetModernImageSignals.m +++ b/submodules/LegacyComponents/Sources/TGMediaAssetModernImageSignals.m @@ -409,23 +409,17 @@ { SSignal *attributesSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { - PHImageRequestID token = [[PHImageManager defaultManager] requestImageDataForAsset:asset.backingAsset options:nil resultHandler:^(NSData *data, NSString *dataUTI, __unused UIImageOrientation orientation, NSDictionary *info) - { - NSURL *fileUrl = info[@"PHImageFileURLKey"]; - - TGMediaAssetImageFileAttributes *attributes = [[TGMediaAssetImageFileAttributes alloc] init]; - attributes.fileName = fileUrl.absoluteString.lastPathComponent; - attributes.fileUTI = dataUTI; - attributes.dimensions = asset.dimensions; - attributes.fileSize = data.length; - - [subscriber putNext:attributes]; - [subscriber putCompletion]; - }]; + TGMediaAssetImageFileAttributes *attributes = [[TGMediaAssetImageFileAttributes alloc] init]; + attributes.fileName = asset.fileName; + attributes.fileUTI = asset.uniformTypeIdentifier; + attributes.dimensions = asset.dimensions; + attributes.fileSize = asset.fileSize; + [subscriber putNext:attributes]; + [subscriber putCompletion]; + return [[SBlockDisposable alloc] initWithBlock:^ { - [[PHImageManager defaultManager] cancelImageRequest:token]; }]; }]; diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryPhotoItemView.m b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryPhotoItemView.m index 7a2e3403c7..aa8fb9d427 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryPhotoItemView.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryPhotoItemView.m @@ -256,7 +256,11 @@ NSString *fileSize = [TGStringUtils stringForFileSize:next.fileSize precision:2]; NSString *dimensions = [NSString stringWithFormat:@"%dx%d", (int)next.dimensions.width, (int)next.dimensions.height]; - strongSelf->_fileInfoLabel.text = [NSString stringWithFormat:@"%@ • %@ • %@", extension, fileSize, dimensions]; + if (next.fileSize > 0) { + strongSelf->_fileInfoLabel.text = [NSString stringWithFormat:@"%@ • %@ • %@", extension, fileSize, dimensions]; + } else { + strongSelf->_fileInfoLabel.text = dimensions; + } }]]; } } diff --git a/submodules/LocationUI/Sources/LocationAnnotation.swift b/submodules/LocationUI/Sources/LocationAnnotation.swift index 647b828fc1..c6f1bef1b0 100644 --- a/submodules/LocationUI/Sources/LocationAnnotation.swift +++ b/submodules/LocationUI/Sources/LocationAnnotation.swift @@ -122,8 +122,33 @@ class LocationPinAnnotationLayer: CALayer { } } +private func addPulseAnimations(layer: CALayer) { + let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale") + scaleAnimation.values = [0.0 as NSNumber, 0.72 as NSNumber, 1.0 as NSNumber, 1.0 as NSNumber] + scaleAnimation.keyTimes = [0.0 as NSNumber, 0.49 as NSNumber, 0.88 as NSNumber, 1.0 as NSNumber] + scaleAnimation.duration = 3.0 + scaleAnimation.repeatCount = Float.infinity + scaleAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) + scaleAnimation.beginTime = 1.0 + layer.add(scaleAnimation, forKey: "pulse-scale") + + let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity") + opacityAnimation.values = [1.0 as NSNumber, 0.2 as NSNumber, 0.0 as NSNumber, 0.0 as NSNumber] + opacityAnimation.keyTimes = [0.0 as NSNumber, 0.4 as NSNumber, 0.62 as NSNumber, 1.0 as NSNumber] + opacityAnimation.duration = 3.0 + opacityAnimation.repeatCount = Float.infinity + opacityAnimation.beginTime = 1.0 + layer.add(opacityAnimation, forKey: "pulse-opacity") +} + +private func removePulseAnimations(layer: CALayer) { + layer.removeAnimation(forKey: "pulse-scale") + layer.removeAnimation(forKey: "pulse-opacity") +} + class LocationPinAnnotationView: MKAnnotationView { let shadowNode: ASImageNode + let pulseNode: ASImageNode let backgroundNode: ASImageNode let arrowNode: ASImageNode let smallNode: ASImageNode @@ -138,6 +163,8 @@ class LocationPinAnnotationView: MKAnnotationView { var appeared = false var animating = false + var hasPulse = false + override class var layerClass: AnyClass { return LocationPinAnnotationLayer.self } @@ -155,6 +182,11 @@ class LocationPinAnnotationView: MKAnnotationView { self.shadowNode.bounds = CGRect(origin: CGPoint(), size: image.size) } + self.pulseNode = ASImageNode() + self.pulseNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 120.0, height: 120.0)) + self.pulseNode.image = generateFilledCircleImage(diameter: 120.0, color: UIColor(rgb: 0x007aff, alpha: 0.27)) + self.pulseNode.isHidden = true + self.arrowNode = ASImageNode() self.arrowNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 88.0, height: 88.0)) self.arrowNode.image = generateHeadingArrowImage() @@ -612,6 +644,8 @@ class LocationPinAnnotationView: MKAnnotationView { } self.dotNode.position = CGPoint() + self.pulseNode.position = CGPoint() + self.arrowNode.position = CGPoint() self.smallNode.position = CGPoint() self.shadowNode.position = CGPoint(x: UIScreenPixel, y: self.isRaised ? -66.0 : -36.0) self.backgroundNode.position = CGPoint(x: self.shadowNode.frame.width / 2.0, y: self.shadowNode.frame.height / 2.0) diff --git a/submodules/LocationUI/Sources/LocationViewControllerNode.swift b/submodules/LocationUI/Sources/LocationViewControllerNode.swift index f701a852f9..f205845a45 100644 --- a/submodules/LocationUI/Sources/LocationViewControllerNode.swift +++ b/submodules/LocationUI/Sources/LocationViewControllerNode.swift @@ -411,6 +411,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan index += 1 } + if subject.id.peerId.namespace != Namespaces.Peer.CloudUser { + proximityNotification = state.proximityRadius != nil + } + let previousEntries = previousEntries.swap(entries) let previousState = previousState.swap(state) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index d0fa27b7a2..4b00ae1660 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -7170,7 +7170,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let fileId = arc4random64() let mimeType = guessMimeTypeByFileExtension((item.fileName as NSString).pathExtension) var previewRepresentations: [TelegramMediaImageRepresentation] = [] - if mimeType == "application/pdf" { + if mimeType.hasPrefix("image/") || mimeType == "application/pdf" { previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 320, height: 320), resource: ICloudFileResource(urlData: item.urlData, thumbnail: true), progressiveSizes: [])) } var attributes: [TelegramMediaFileAttribute] = [] @@ -7183,7 +7183,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: replyMessageId, localGroupingKey: groupingKey) messages.append(message) } - if let _ = groupingKey, results.count % 10 == 0 { + if let _ = groupingKey, messages.count % 10 == 0 { groupingKey = arc4random64() } } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift index c7806221de..15f0570286 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift @@ -49,7 +49,7 @@ enum ChatMessageBubbleRelativePosition { enum NeighbourSpacing { case `default` case condensed - case overlap + case overlap(CGFloat) } case None(ChatMessageBubbleMergeStatus) diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 566c9dffe5..c1a3459e63 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -64,7 +64,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([ } else { var neighborSpacing: ChatMessageBubbleRelativePosition.NeighbourSpacing = .default if previousItemIsFile { - neighborSpacing = .overlap + neighborSpacing = .overlap(file.isMusic ? 14.0 : 5.0) } isFile = true hasFiles = true @@ -229,12 +229,15 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode func willUpdateIsExtractedToContextPreview(isExtractedToContextPreview: Bool, transition: ContainedViewLayoutTransition) { if isExtractedToContextPreview { var offset: CGFloat = 0.0 + var inset: CGFloat = 0.0 var type: ChatMessageBackgroundType if let currentParams = self.currentParams, case .incoming = currentParams.backgroundType { type = .incoming(.Extracted) - offset += 5.0 + offset = -5.0 + inset = 5.0 } else { type = .outgoing(.Extracted) + inset = 5.0 } if let _ = self.backgroundNode { @@ -250,7 +253,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode } if let currentParams = self.currentParams { - let backgroundFrame = CGRect(x: currentParams.contentOrigin.x - offset, y: 0.0, width: currentParams.size.width + offset, height: currentParams.size.height) + let backgroundFrame = CGRect(x: currentParams.contentOrigin.x + offset, y: 0.0, width: currentParams.size.width + inset, height: currentParams.size.height) self.backgroundNode?.updateLayout(size: backgroundFrame.size, transition: .immediate) self.backgroundNode?.frame = backgroundFrame } @@ -1783,13 +1786,20 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode var contentNodesHeight: CGFloat = 0.0 var totalContentNodesHeight: CGFloat = 0.0 - let smallContainerGroupOverlap: CGFloat = 5.0 - let largeContainerGroupOverlap: CGFloat = 14.0 - var nextContainerGroupOverlap = smallContainerGroupOverlap + var currentContainerGroupOverlap: CGFloat = 0.0 var mosaicStatusOrigin: CGPoint? for i in 0 ..< contentNodePropertiesAndFinalize.count { - let (properties, _, finalize, contentGroupId, itemSelection) = contentNodePropertiesAndFinalize[i] + let (properties, position, finalize, contentGroupId, itemSelection) = contentNodePropertiesAndFinalize[i] + + if let position = position, case let .linear(top, bottom) = position { + if case let .Neighbour(_, _, spacing) = top, case let .overlap(overlap) = spacing { + currentContainerGroupOverlap = overlap + } + if case let .Neighbour(_, _, spacing) = bottom, case let .overlap(overlap) = spacing { + currentContainerGroupOverlap = overlap + } + } if let mosaicRange = mosaicRange, mosaicRange.contains(i), let (framesAndPositions, size) = calculatedGroupFramesAndSize { let mosaicIndex = i - mosaicRange.lowerBound @@ -1823,11 +1833,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode if let containerGroupId = currentContainerGroupId { var overlapOffset: CGFloat = 0.0 if !contentContainerNodeFrames.isEmpty { - overlapOffset = smallContainerGroupOverlap + overlapOffset = currentContainerGroupOverlap } contentContainerNodeFrames.append((containerGroupId, CGRect(x: 0.0, y: headerSize.height + totalContentNodesHeight - contentNodesHeight - overlapOffset, width: maxContentWidth, height: contentNodesHeight), currentItemSelection)) if !overlapOffset.isZero { - totalContentNodesHeight -= smallContainerGroupOverlap + totalContentNodesHeight -= currentContainerGroupOverlap } if contentGroupId == nil { totalContentNodesHeight += 3.0 @@ -1849,11 +1859,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode if let containerGroupId = currentContainerGroupId { var overlapOffset: CGFloat = 0.0 if !contentContainerNodeFrames.isEmpty { - overlapOffset = smallContainerGroupOverlap + overlapOffset = currentContainerGroupOverlap } contentContainerNodeFrames.append((containerGroupId, CGRect(x: 0.0, y: headerSize.height + totalContentNodesHeight - contentNodesHeight - overlapOffset, width: maxContentWidth, height: contentNodesHeight), currentItemSelection)) if !overlapOffset.isZero { - totalContentNodesHeight -= smallContainerGroupOverlap + totalContentNodesHeight -= currentContainerGroupOverlap } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift index 7206b2460c..23e9778e05 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift @@ -993,7 +993,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { self.cutoutNode = cutoutNode self.insertSubnode(cutoutNode, aboveSubnode: statusNode) - cutoutNode.frame = streamingCacheStatusFrame.insetBy(dx: -1.5, dy: -1.5) + cutoutNode.frame = streamingCacheStatusFrame.insetBy(dx: -(1.0 + UIScreenPixel), dy: -(1.0 + UIScreenPixel)) if animated { cutoutNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2) diff --git a/submodules/TelegramUI/Sources/ICloudResources.swift b/submodules/TelegramUI/Sources/ICloudResources.swift index a4e00891fc..5cf472358a 100644 --- a/submodules/TelegramUI/Sources/ICloudResources.swift +++ b/submodules/TelegramUI/Sources/ICloudResources.swift @@ -230,7 +230,10 @@ func fetchICloudFileResource(resource: ICloudFileResource) -> Signal