From 571fb8f0331b5976a32214e42b26122903c4f740 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 20 Nov 2021 17:20:37 +0400 Subject: [PATCH 01/14] Optimize bezier tesselation --- Tests/LottieMesh/Sources/ViewController.swift | 10 ++- .../LottieMeshBinding/LottieMeshBinding.h | 2 +- .../Sources/LottieMeshBinding.mm | 78 ++++++++++++------- .../Sources/MeshAnimation.swift | 31 +++----- 4 files changed, 71 insertions(+), 50 deletions(-) diff --git a/Tests/LottieMesh/Sources/ViewController.swift b/Tests/LottieMesh/Sources/ViewController.swift index 40d86d5d76..b69daa6e7d 100644 --- a/Tests/LottieMesh/Sources/ViewController.swift +++ b/Tests/LottieMesh/Sources/ViewController.swift @@ -2,11 +2,14 @@ import Foundation import UIKit import LottieMeshSwift +import Postbox public final class ViewController: UIViewController { override public func viewDidLoad() { super.viewDidLoad() + TempBox.initializeShared(basePath: NSTemporaryDirectory(), processType: "test", launchSpecificId: Int64.random(in: Int64.min ..< Int64.max)) + self.view.backgroundColor = .black let path = Bundle.main.path(forResource: "Fireworks", ofType: "json")! @@ -16,7 +19,12 @@ public final class ViewController: UIViewController { }*/ if #available(iOS 13.0, *) { - let animation = generateMeshAnimation(data: try! Data(contentsOf: URL(fileURLWithPath: path)))! + let startTime = CFAbsoluteTimeGetCurrent() + let animationFile = generateMeshAnimation(data: try! Data(contentsOf: URL(fileURLWithPath: path)))! + print("Time: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0)") + let buffer = MeshReadBuffer(data: try! Data(contentsOf: URL(fileURLWithPath: animationFile.path))) + let animation = MeshAnimation.read(buffer: buffer) + let renderer = MeshRenderer(wireframe: true)! renderer.frame = CGRect(origin: CGPoint(x: 0.0, y: 50.0), size: CGSize(width: 300.0, height: 300.0)) diff --git a/submodules/LottieMeshSwift/LottieMeshBinding/PublicHeaders/LottieMeshBinding/LottieMeshBinding.h b/submodules/LottieMeshSwift/LottieMeshBinding/PublicHeaders/LottieMeshBinding/LottieMeshBinding.h index 8b2a1b15e4..18d6073a22 100644 --- a/submodules/LottieMeshSwift/LottieMeshBinding/PublicHeaders/LottieMeshBinding/LottieMeshBinding.h +++ b/submodules/LottieMeshSwift/LottieMeshBinding/PublicHeaders/LottieMeshBinding/LottieMeshBinding.h @@ -34,7 +34,7 @@ typedef NS_CLOSED_ENUM(NSInteger, LottieMeshFillRule) { - (void)getVertexAt:(NSInteger)index x:(float * _Nullable)x y:(float * _Nullable)y; - (NSInteger)triangleCount; -- (void)getTriangleAt:(NSInteger)index v0:(NSInteger * _Nullable)v0 v1:(NSInteger * _Nullable)v1 v2:(NSInteger * _Nullable)v2; +- (void * _Nonnull)getTriangles; + (LottieMeshData * _Nullable)generateWithPath:(UIBezierPath * _Nonnull)path fill:(LottieMeshFill * _Nullable)fill stroke:(LottieMeshStroke * _Nullable)stroke; diff --git a/submodules/LottieMeshSwift/LottieMeshBinding/Sources/LottieMeshBinding.mm b/submodules/LottieMeshSwift/LottieMeshBinding/Sources/LottieMeshBinding.mm index e76e7d974c..75a24b6bcd 100644 --- a/submodules/LottieMeshSwift/LottieMeshBinding/Sources/LottieMeshBinding.mm +++ b/submodules/LottieMeshSwift/LottieMeshBinding/Sources/LottieMeshBinding.mm @@ -10,12 +10,6 @@ MeshGenerator::Point bezierQuadraticPointAt(MeshGenerator::Point const &p0, Mesh return MeshGenerator::Point(x, y); } -MeshGenerator::Point bezierQubicPointAt(MeshGenerator::Point const &p0, MeshGenerator::Point const &p1, MeshGenerator::Point const &p2, MeshGenerator::Point const &p3, float t) { - float x = powf((1.0 - t), 3.0) * p0.x + 3.0 * powf((1.0 - t), 2.0) * t * p1.x + 3.0 * (1.0 - t) * powf(t, 2.0) * p2.x + powf(t, 3.0) * p3.x; - float y = powf((1.0 - t), 3.0) * p0.y + 3.0 * powf((1.0 - t), 2.0) * t * p1.y + 3.0 * (1.0 - t) * powf(t, 2.0) * p2.y + powf(t, 3.0) * p3.y; - return MeshGenerator::Point(x, y); -} - float approximateBezierQuadraticLength(MeshGenerator::Point const &p0, MeshGenerator::Point const &p1, MeshGenerator::Point const &p2) { float length = 0.0f; float t = 0.1; @@ -29,17 +23,51 @@ float approximateBezierQuadraticLength(MeshGenerator::Point const &p0, MeshGener return length; } -float approximateBezierQubicLength(MeshGenerator::Point const &p0, MeshGenerator::Point const &p1, MeshGenerator::Point const &p2, MeshGenerator::Point const &p3) { - float length = 0.0f; - float t = 0.1; - MeshGenerator::Point last = p0; - while (t < 1.01) { - auto point = bezierQubicPointAt(p0, p1, p2, p3, t); - length += last.distance(point); - last = point; - t += 0.1; +void tesselateBezier(MeshGenerator::Path &path, MeshGenerator::Point const &p1, MeshGenerator::Point const &p2, MeshGenerator::Point const &p3, MeshGenerator::Point const &p4, int level) { + const float tessTol = 0.25f / 0.5f; + + float x1 = p1.x; + float y1 = p1.y; + float x2 = p2.x; + float y2 = p2.y; + float x3 = p3.x; + float y3 = p3.y; + float x4 = p4.x; + float y4 = p4.y; + + float x12, y12, x23, y23, x34, y34, x123, y123, x234, y234, x1234, y1234; + float dx, dy, d2, d3; + + if (level > 10) { + return; } - return length; + + x12 = (x1 + x2) * 0.5f; + y12 = (y1 + y2) * 0.5f; + x23 = (x2 + x3) * 0.5f; + y23 = (y2 + y3) * 0.5f; + x34 = (x3 + x4) * 0.5f; + y34 = (y3 + y4) * 0.5f; + x123 = (x12 + x23) * 0.5f; + y123 = (y12 + y23) * 0.5f; + + dx = x4 - x1; + dy = y4 - y1; + d2 = std::abs(((x2 - x4) * dy - (y2 - y4) * dx)); + d3 = std::abs(((x3 - x4) * dy - (y3 - y4) * dx)); + + if ((d2 + d3) * (d2 + d3) < tessTol * (dx * dx + dy * dy)) { + path.points.emplace_back(x4, y4); + return; + } + + x234 = (x23+x34) * 0.5f; + y234 = (y23+y34) * 0.5f; + x1234 = (x123 + x234) * 0.5f; + y1234 = (y123 + y234) * 0.5f; + + tesselateBezier(path, MeshGenerator::Point(x1, y1), MeshGenerator::Point(x12, y12), MeshGenerator::Point(x123, y123), MeshGenerator::Point(x1234, y1234), level + 1); + tesselateBezier(path, MeshGenerator::Point(x1234, y1234), MeshGenerator::Point(x234, y234), MeshGenerator::Point(x34, y34), MeshGenerator::Point(x4, y4), level + 1); } } @@ -80,7 +108,11 @@ float approximateBezierQubicLength(MeshGenerator::Point const &p0, MeshGenerator return (NSInteger)(_mesh->triangles.size() / 3); } -- (void)getTriangleAt:(NSInteger)index v0:(NSInteger * _Nullable)v0 v1:(NSInteger * _Nullable)v1 v2:(NSInteger * _Nullable)v2 { +- (void * _Nonnull)getTriangles { + return _mesh->triangles.data(); +} + +/*- (void)getTriangleAt:(NSInteger)index v0:(NSInteger * _Nullable)v0 v1:(NSInteger * _Nullable)v1 v2:(NSInteger * _Nullable)v2 { if (v0) { *v0 = (NSInteger)_mesh->triangles[index * 3 + 0]; } @@ -90,7 +122,7 @@ float approximateBezierQubicLength(MeshGenerator::Point const &p0, MeshGenerator if (v2) { *v2 = (NSInteger)_mesh->triangles[index * 3 + 2]; } -} +}*/ + (LottieMeshData * _Nullable)generateWithPath:(UIBezierPath * _Nonnull)path fill: (LottieMeshFill * _Nullable)fill stroke:(LottieMeshStroke * _Nullable)stroke { float scale = 1.0f; @@ -173,14 +205,8 @@ float approximateBezierQubicLength(MeshGenerator::Point const &p0, MeshGenerator MeshGenerator::Point p1(element->points[0].x * scale, element->points[0].y * scale); MeshGenerator::Point p2(element->points[1].x * scale, element->points[1].y * scale); MeshGenerator::Point p3(element->points[2].x * scale, element->points[2].y * scale); - - float step = 10.0f * flatness / approximateBezierQubicLength(p0, p1, p2, p3); - while (t < 1.0f) { - auto point = bezierQubicPointAt(p0, p1, p2, p3, t); - paths[paths.size() - 1].points.push_back(point); - t += step; - } - paths[paths.size() - 1].points.push_back(p3); + + tesselateBezier(paths[paths.size() - 1], p0, p1, p2, p3, 0); } break; } diff --git a/submodules/LottieMeshSwift/Sources/MeshAnimation.swift b/submodules/LottieMeshSwift/Sources/MeshAnimation.swift index a7710444df..b145a96a6d 100644 --- a/submodules/LottieMeshSwift/Sources/MeshAnimation.swift +++ b/submodules/LottieMeshSwift/Sources/MeshAnimation.swift @@ -573,13 +573,13 @@ public final class MeshRenderer: MTKView { } } -private func generateSegments(geometry: CapturedGeometryNode, superAlpha: CGFloat, superTransform: CGAffineTransform, writeSegment: (MeshAnimation.Frame.Segment) -> Void) { +private func generateSegments(writeBuffer: MeshWriteBuffer, segmentCount: inout Int, geometry: CapturedGeometryNode, superAlpha: CGFloat, superTransform: CGAffineTransform) { if geometry.isHidden || geometry.alpha.isZero { return } for i in 0 ..< geometry.subnodes.count { - generateSegments(geometry: geometry.subnodes[i], superAlpha: superAlpha * geometry.alpha, superTransform: CATransform3DGetAffineTransform(geometry.transform).concatenating(superTransform), writeSegment: writeSegment) + generateSegments(writeBuffer: writeBuffer, segmentCount: &segmentCount, geometry: geometry.subnodes[i], superAlpha: superAlpha * geometry.alpha, superTransform: CATransform3DGetAffineTransform(geometry.transform).concatenating(superTransform)) } if let displayItem = geometry.displayItem { @@ -617,17 +617,6 @@ private func generateSegments(geometry: CapturedGeometryNode, superAlpha: CGFloa meshData = LottieMeshData.generate(with: UIBezierPath(cgPath: displayItem.path), fill: nil, stroke: LottieMeshStroke(lineWidth: stroke.lineWidth, lineJoin: stroke.lineJoin, lineCap: stroke.lineCap, miterLimit: stroke.miterLimit)) } if let meshData = meshData, meshData.triangleCount() != 0 { - let mappedTriangles = WriteBuffer() - for i in 0 ..< meshData.triangleCount() { - var v0: Int = 0 - var v1: Int = 0 - var v2: Int = 0 - meshData.getTriangleAt(i, v0: &v0, v1: &v1, v2: &v2) - mappedTriangles.writeInt32(Int32(v0)) - mappedTriangles.writeInt32(Int32(v1)) - mappedTriangles.writeInt32(Int32(v2)) - } - let mappedVertices = WriteBuffer() for i in 0 ..< meshData.vertexCount() { var x: Float = 0.0 @@ -636,13 +625,15 @@ private func generateSegments(geometry: CapturedGeometryNode, superAlpha: CGFloa mappedVertices.writeFloat(x) mappedVertices.writeFloat(y) } + + let trianglesData = Data(bytes: meshData.getTriangles(), count: meshData.triangleCount() * 3 * 4) let verticesData = mappedVertices.makeData() - let trianglesData = mappedTriangles.makeData() let segment = MeshAnimation.Frame.Segment(vertices: DataRange(data: verticesData, range: 0 ..< verticesData.count), triangles: DataRange(data: trianglesData, range: 0 ..< trianglesData.count), fill: triangleFill, transform: CATransform3DGetAffineTransform(geometry.transform).concatenating(superTransform)) - writeSegment(segment) + segment.write(buffer: writeBuffer) + segmentCount += 1 } } } @@ -666,9 +657,9 @@ public func generateMeshAnimation(data: Data) -> TempBoxFile? { for i in 0 ..< Int(animation.endFrame) { container.setFrame(frame: CGFloat(i)) - #if DEBUG + //#if DEBUG print("Frame \(i) / \(Int(animation.endFrame))") - #endif + //#endif let segmentCountOffset = writeBuffer.offset writeBuffer.writeInt32(0) @@ -677,11 +668,7 @@ public func generateMeshAnimation(data: Data) -> TempBoxFile? { let geometry = container.captureGeometry() geometry.transform = CATransform3DMakeTranslation(256.0, 256.0, 0.0) - generateSegments(geometry: geometry, superAlpha: 1.0, superTransform: .identity, writeSegment: { segment in - segment.write(buffer: writeBuffer) - - segmentCount += 1 - }) + generateSegments(writeBuffer: writeBuffer, segmentCount: &segmentCount, geometry: geometry, superAlpha: 1.0, superTransform: .identity) let currentOffset = writeBuffer.offset writeBuffer.seek(offset: segmentCountOffset) From 68986f9e5bd39b0de09538d64df2762d2402baaa Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 20 Nov 2021 17:58:30 +0400 Subject: [PATCH 02/14] Fix spring animation --- submodules/ContextUI/Sources/ContextController.swift | 9 +++++---- submodules/Display/Source/CAAnimationUtils.swift | 4 ++-- .../Sources/ReactionContextNode.swift | 9 +++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index ea74e730f7..ec062da935 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -1135,6 +1135,11 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi } self.reactionContextNodeIsAnimatingOut = true + reactionContextNode.willAnimateOutToReaction(value: value) + self.animateOut(result: .default, completion: { + contentCompleted = true + intermediateCompletion() + }) reactionContextNode.animateOutToReaction(value: value, targetEmptyNode: targetEmptyNode, targetFilledNode: targetFilledNode, hideNode: hideNode, completion: { [weak self] in guard let strongSelf = self else { return @@ -1144,10 +1149,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi reactionCompleted = true intermediateCompletion() }) - self.animateOut(result: .default, completion: { - contentCompleted = true - intermediateCompletion() - }) self.isUserInteractionEnabled = false } diff --git a/submodules/Display/Source/CAAnimationUtils.swift b/submodules/Display/Source/CAAnimationUtils.swift index 9c51d016d1..5fc052945d 100644 --- a/submodules/Display/Source/CAAnimationUtils.swift +++ b/submodules/Display/Source/CAAnimationUtils.swift @@ -151,7 +151,7 @@ public extension CALayer { let animationGroup = CAAnimationGroup() var timeOffset = 0.0 for animation in animations { - animation.beginTime = animation.beginTime + timeOffset + animation.beginTime = self.convertTime(animation.beginTime, from: nil) + timeOffset timeOffset += animation.duration / Double(animation.speed) } animationGroup.animations = animations @@ -217,7 +217,7 @@ public extension CALayer { } if !delay.isZero { - animation.beginTime = CACurrentMediaTime() + delay * UIView.animationDurationFactor() + animation.beginTime = self.convertTime(CACurrentMediaTime(), from: nil) + delay * UIView.animationDurationFactor() animation.fillMode = .both } diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index 9f59509492..2b2a94536f 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -528,6 +528,15 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { itemNode.layer.animateScale(from: 1.0, to: (targetSnapshotView.bounds.width * 0.5) / itemNode.bounds.width, duration: duration, removeOnCompletion: false) } + public func willAnimateOutToReaction(value: String) { + for itemNode in self.itemNodes { + if itemNode.item.reaction.rawValue != value { + continue + } + itemNode.isExtracted = true + } + } + public func animateOutToReaction(value: String, targetEmptyNode: ASDisplayNode, targetFilledNode: ASDisplayNode, hideNode: Bool, completion: @escaping () -> Void) { for itemNode in self.itemNodes { if itemNode.item.reaction.rawValue != value { From c041da85e07f9a9b30e9aed30cb7b31eb7fcc898 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 20 Nov 2021 20:26:53 +0400 Subject: [PATCH 03/14] Various Fixes --- .../CallListUI/Sources/CallListCallItem.swift | 20 +++++++++---- .../ChatListFilterPresetListItem.swift | 15 ++++++++-- .../Sources/ItemListPeerItem.swift | 3 ++ .../Sources/ItemListStickerPackItem.swift | 30 ++++++++++++------- .../LocalizationListItem.swift | 20 +++++++++---- .../RecentSessionsController.swift | 12 ++++---- .../Sources/PeerInfo/PeerInfoScreen.swift | 8 ++++- 7 files changed, 77 insertions(+), 31 deletions(-) diff --git a/submodules/CallListUI/Sources/CallListCallItem.swift b/submodules/CallListUI/Sources/CallListCallItem.swift index 7dfee591ca..7cc33f906f 100644 --- a/submodules/CallListUI/Sources/CallListCallItem.swift +++ b/submodules/CallListUI/Sources/CallListCallItem.swift @@ -190,6 +190,11 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { private let highlightedBackgroundNode: ASDisplayNode private let maskNode: ASImageNode + private let containerNode: ASDisplayNode + override var controlsContainer: ASDisplayNode { + return self.containerNode + } + private let avatarNode: AvatarNode private let titleNode: TextNode private let statusNode: TextNode @@ -207,6 +212,8 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { self.backgroundNode = ASDisplayNode() self.backgroundNode.isLayerBacked = true + self.containerNode = ASDisplayNode() + self.maskNode = ASImageNode() self.maskNode.isUserInteractionEnabled = false @@ -239,12 +246,12 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) self.addSubnode(self.backgroundNode) - self.addSubnode(self.avatarNode) - self.addSubnode(self.typeIconNode) - self.addSubnode(self.titleNode) - self.addSubnode(self.statusNode) - self.addSubnode(self.dateNode) - self.addSubnode(self.infoButtonNode) + self.containerNode.addSubnode(self.avatarNode) + self.containerNode.addSubnode(self.typeIconNode) + self.containerNode.addSubnode(self.titleNode) + self.containerNode.addSubnode(self.statusNode) + self.containerNode.addSubnode(self.dateNode) + self.containerNode.addSubnode(self.infoButtonNode) self.addSubnode(self.accessibilityArea) self.infoButtonNode.addTarget(self, action: #selector(self.infoPressed), forControlEvents: .touchUpInside) @@ -631,6 +638,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { let topHighlightInset: CGFloat = (first || !nodeLayout.insets.top.isZero) ? 0.0 : separatorHeight strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: nodeLayout.contentSize.width, height: nodeLayout.contentSize.height)) + strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: strongSelf.backgroundNode.frame.size) strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top - topHighlightInset), size: CGSize(width: nodeLayout.size.width, height: nodeLayout.size.height + topHighlightInset)) strongSelf.updateLayout(size: nodeLayout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift index 7fddedcea1..7dd627e4c8 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift @@ -109,6 +109,11 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN private let highlightedBackgroundNode: ASDisplayNode private let maskNode: ASImageNode + private let containerNode: ASDisplayNode + override var controlsContainer: ASDisplayNode { + return self.containerNode + } + private let titleNode: TextNode private let labelNode: TextNode private let arrowNode: ASImageNode @@ -138,6 +143,8 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN self.bottomStripeNode = ASDisplayNode() self.bottomStripeNode.isLayerBacked = true + self.containerNode = ASDisplayNode() + self.maskNode = ASImageNode() self.maskNode.isUserInteractionEnabled = false @@ -161,9 +168,10 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) - self.addSubnode(self.titleNode) - self.addSubnode(self.labelNode) - self.addSubnode(self.arrowNode) + self.addSubnode(self.containerNode) + self.containerNode.addSubnode(self.titleNode) + self.containerNode.addSubnode(self.labelNode) + self.containerNode.addSubnode(self.arrowNode) self.addSubnode(self.activateArea) self.activateArea.activate = { [weak self] in @@ -345,6 +353,7 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: strongSelf.backgroundNode.frame.size) strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) transition.updateFrame(node: strongSelf.topStripeNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))) transition.updateFrame(node: strongSelf.bottomStripeNode, frame: CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))) diff --git a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift index dc4d38f2c5..12d2e57962 100644 --- a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift +++ b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift @@ -449,6 +449,9 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo private let maskNode: ASImageNode private let containerNode: ContextControllerSourceNode + public override var controlsContainer: ASDisplayNode { + return self.containerNode + } fileprivate let avatarNode: AvatarNode private let titleNode: TextNode diff --git a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift index 335a1e2c04..53cc020bfe 100644 --- a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift +++ b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift @@ -151,6 +151,11 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { private var disabledOverlayNode: ASDisplayNode? private let maskNode: ASImageNode + private let containerNode: ASDisplayNode + override var controlsContainer: ASDisplayNode { + return self.containerNode + } + fileprivate let imageNode: TransformImageNode private var animationNode: AnimatedStickerNode? private var placeholderNode: StickerShimmerEffectNode? @@ -203,6 +208,8 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { self.bottomStripeNode = ASDisplayNode() self.bottomStripeNode.isLayerBacked = true + self.containerNode = ASDisplayNode() + self.maskNode = ASImageNode() self.maskNode.isUserInteractionEnabled = false @@ -245,17 +252,19 @@ 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.containerNode) - self.addSubnode(self.titleNode) - self.addSubnode(self.statusNode) - self.addSubnode(self.unreadNode) - self.addSubnode(self.installationActionImageNode) - self.addSubnode(self.installationActionNode) - self.addSubnode(self.selectionIconNode) + if let placeholderNode = self.placeholderNode { + self.containerNode.addSubnode(placeholderNode) + } + + self.containerNode.addSubnode(self.imageNode) + self.containerNode.addSubnode(self.titleNode) + self.containerNode.addSubnode(self.statusNode) + self.containerNode.addSubnode(self.unreadNode) + self.containerNode.addSubnode(self.installationActionImageNode) + self.containerNode.addSubnode(self.installationActionNode) + self.containerNode.addSubnode(self.selectionIconNode) self.addSubnode(self.activateArea) self.installationActionNode.addTarget(self, action: #selector(self.installationActionPressed), forControlEvents: .touchUpInside) @@ -689,6 +698,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: strongSelf.backgroundNode.frame.size) strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) transition.updateFrame(node: strongSelf.topStripeNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))) transition.updateFrame(node: strongSelf.bottomStripeNode, frame: CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))) diff --git a/submodules/SettingsUI/Sources/Language Selection/LocalizationListItem.swift b/submodules/SettingsUI/Sources/Language Selection/LocalizationListItem.swift index 8739c2307c..cc0eb02266 100644 --- a/submodules/SettingsUI/Sources/Language Selection/LocalizationListItem.swift +++ b/submodules/SettingsUI/Sources/Language Selection/LocalizationListItem.swift @@ -120,6 +120,11 @@ class LocalizationListItemNode: ItemListRevealOptionsItemNode { private let activateArea: AccessibilityAreaNode + private let containerNode: ASDisplayNode + override var controlsContainer: ASDisplayNode { + return self.containerNode + } + override var canBeSelected: Bool { if self.editableControlNode != nil { return false @@ -144,6 +149,8 @@ class LocalizationListItemNode: ItemListRevealOptionsItemNode { self.maskNode = ASImageNode() self.maskNode.isUserInteractionEnabled = false + self.containerNode = ASDisplayNode() + self.iconNode = ASImageNode() self.iconNode.isLayerBacked = true self.iconNode.displayWithoutProcessing = true @@ -169,10 +176,12 @@ class LocalizationListItemNode: ItemListRevealOptionsItemNode { super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) - self.addSubnode(self.iconNode) - self.addSubnode(self.activityNode) - self.addSubnode(self.titleNode) - self.addSubnode(self.subtitleNode) + self.addSubnode(self.containerNode) + + self.containerNode.addSubnode(self.iconNode) + self.containerNode.addSubnode(self.activityNode) + self.containerNode.addSubnode(self.titleNode) + self.containerNode.addSubnode(self.subtitleNode) self.addSubnode(self.activateArea) } @@ -282,7 +291,7 @@ class LocalizationListItemNode: ItemListRevealOptionsItemNode { strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) } if strongSelf.maskNode.supernode == nil { - strongSelf.insertSubnode(strongSelf.maskNode, at: 3) + strongSelf.addSubnode(strongSelf.maskNode) } let hasCorners = itemListHasRoundedBlockLayout(params) var hasTopCorners = false @@ -307,6 +316,7 @@ class LocalizationListItemNode: ItemListRevealOptionsItemNode { strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: strongSelf.backgroundNode.frame.size) strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight)) strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight)) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift index 23a83f0e00..5ce9e6415a 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift @@ -829,12 +829,12 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont } } - let emptyStateItem: ItemListControllerEmptyStateItem? - if sessionsState.sessions.count == 1 && mode == .sessions { - emptyStateItem = RecentSessionsEmptyStateItem(theme: presentationData.theme, strings: presentationData.strings) - } else { - emptyStateItem = nil - } + let emptyStateItem: ItemListControllerEmptyStateItem? = nil +// if sessionsState.sessions.count == 1 && mode == .sessions { +// emptyStateItem = RecentSessionsEmptyStateItem(theme: presentationData.theme, strings: presentationData.strings) +// } else { +// emptyStateItem = nil +// } let title: ItemListControllerTitle let entries: [RecentSessionsEntry] diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 47bed354b0..2d0353aaba 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -6115,7 +6115,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate var testView: UIView? = localResult while true { if let testViewValue = testView { - if let node = testViewValue.asyncdisplaykit_node as? PeerInfoVisualMediaPaneNode { + if let node = testViewValue.asyncdisplaykit_node as? PeerInfoHeaderNavigationButton { + node.isUserInteractionEnabled = false + DispatchQueue.main.async { + node.isUserInteractionEnabled = true + } + return .dismiss(consume: false, result: nil) + } else if let node = testViewValue.asyncdisplaykit_node as? PeerInfoVisualMediaPaneNode { node.brieflyDisableTouchActions() return .dismiss(consume: false, result: nil) } else { From 477d3c2c4225eccea4590d41d6c611830b679dad Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 20 Nov 2021 20:53:50 +0400 Subject: [PATCH 04/14] Fix call list --- submodules/CallListUI/Sources/CallListCallItem.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/submodules/CallListUI/Sources/CallListCallItem.swift b/submodules/CallListUI/Sources/CallListCallItem.swift index 7cc33f906f..f4014e2638 100644 --- a/submodules/CallListUI/Sources/CallListCallItem.swift +++ b/submodules/CallListUI/Sources/CallListCallItem.swift @@ -246,6 +246,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) self.addSubnode(self.backgroundNode) + self.addSubnode(self.containerNode) self.containerNode.addSubnode(self.avatarNode) self.containerNode.addSubnode(self.typeIconNode) self.containerNode.addSubnode(self.titleNode) From 1f0f7bbac7d15a3111745381fdd562204d0ae454 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 20 Nov 2021 22:00:20 +0400 Subject: [PATCH 05/14] Various Fixes --- .../Sources/ChatItemGalleryFooterContentNode.swift | 2 +- .../ItemListVenueItem/Sources/ItemListVenueItem.swift | 2 +- submodules/PeerAvatarGalleryUI/BUILD | 1 + .../Sources/PeerAvatarImageGalleryItem.swift | 10 ++++++++++ submodules/TelegramUI/Sources/ChatController.swift | 2 ++ .../TelegramUI/Sources/ChatControllerInteraction.swift | 5 ++++- .../Sources/ChatInterfaceStateContextMenus.swift | 2 +- .../Sources/ChatRecentActionsControllerNode.swift | 1 + .../TelegramUI/Sources/DrawingStickersScreen.swift | 4 +++- .../Sources/OverlayAudioPlayerControllerNode.swift | 1 + .../TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift | 2 ++ .../TelegramUI/Sources/SharedAccountContext.swift | 4 +++- 12 files changed, 30 insertions(+), 6 deletions(-) diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index 12cfe1b43e..91d87491da 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -1192,7 +1192,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll shareController.actionCompleted = { [weak self] in if let strongSelf = self, let actionCompletionText = actionCompletionText { let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: actionCompletionText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) + strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: actionCompletionText), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return true }), nil) } } shareController.completed = { [weak self] peerIds in diff --git a/submodules/ItemListVenueItem/Sources/ItemListVenueItem.swift b/submodules/ItemListVenueItem/Sources/ItemListVenueItem.swift index ad47572947..aa1a05bfc5 100644 --- a/submodules/ItemListVenueItem/Sources/ItemListVenueItem.swift +++ b/submodules/ItemListVenueItem/Sources/ItemListVenueItem.swift @@ -301,7 +301,7 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode { strongSelf.topStripeNode.removeFromSupernode() } if strongSelf.bottomStripeNode.supernode == nil { - strongSelf.addSubnode(strongSelf.bottomStripeNode) + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) } if strongSelf.maskNode.supernode != nil { strongSelf.maskNode.removeFromSupernode() diff --git a/submodules/PeerAvatarGalleryUI/BUILD b/submodules/PeerAvatarGalleryUI/BUILD index 40dbe21520..9e7b1b5a5f 100644 --- a/submodules/PeerAvatarGalleryUI/BUILD +++ b/submodules/PeerAvatarGalleryUI/BUILD @@ -27,6 +27,7 @@ swift_library( "//submodules/LegacyComponents:LegacyComponents", "//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI", "//submodules/SaveToCameraRoll:SaveToCameraRoll", + "//submodules/UndoUI:UndoUI", ], visibility = [ "//visibility:public", diff --git a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift index 7c878bf1f2..c4a392a311 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift @@ -12,6 +12,7 @@ import ShareController import PhotoResources import GalleryUI import TelegramUniversalVideoContent +import UndoUI private struct PeerAvatarImageGalleryThumbnailItem: GalleryThumbnailItem { let account: Account @@ -185,13 +186,22 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { self.footerContentNode.share = { [weak self] interaction in if let strongSelf = self, let entry = strongSelf.entry, !entry.representations.isEmpty { let subject: ShareControllerSubject + var actionCompletionText: String? if let video = entry.videoRepresentations.last, let peerReference = PeerReference(peer) { let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.representation.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.representation.dimensions, flags: [])])) subject = .media(videoFileReference.abstract) + actionCompletionText = strongSelf.presentationData.strings.Gallery_VideoSaved } else { subject = .image(entry.representations) + actionCompletionText = strongSelf.presentationData.strings.Gallery_ImageSaved } let shareController = ShareController(context: strongSelf.context, subject: subject, preferredAction: .saveToCameraRoll) + shareController.actionCompleted = { [weak self] in + if let strongSelf = self, let actionCompletionText = actionCompletionText { + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + interaction.presentController(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: actionCompletionText), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return true }), nil) + } + } interaction.presentController(shareController, nil) } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index e2d2bf5bde..e004128565 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -1883,6 +1883,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }, presentController: { [weak self] controller, arguments in self?.present(controller, in: .window(.root), with: arguments) + }, presentControllerInCurrent: { [weak self] controller, arguments in + self?.present(controller, in: .current, with: arguments) }, navigationController: { [weak self] in return self?.navigationController as? NavigationController }, chatControllerNode: { [weak self] in diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index 3390b51634..f7fe5294b8 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -79,6 +79,7 @@ public final class ChatControllerInteraction { let updateInputMode: ((ChatInputMode) -> ChatInputMode) -> Void let openMessageShareMenu: (MessageId) -> Void let presentController: (ViewController, Any?) -> Void + let presentControllerInCurrent: (ViewController, Any?) -> Void let navigationController: () -> NavigationController? let chatControllerNode: () -> ASDisplayNode? let presentGlobalOverlayController: (ViewController, Any?) -> Void @@ -174,6 +175,7 @@ public final class ChatControllerInteraction { updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, + presentControllerInCurrent: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, @@ -255,6 +257,7 @@ public final class ChatControllerInteraction { self.updateInputMode = updateInputMode self.openMessageShareMenu = openMessageShareMenu self.presentController = presentController + self.presentControllerInCurrent = presentControllerInCurrent self.navigationController = navigationController self.chatControllerNode = chatControllerNode self.presentGlobalOverlayController = presentGlobalOverlayController @@ -311,7 +314,7 @@ public final class ChatControllerInteraction { static var `default`: ChatControllerInteraction { return ChatControllerInteraction(openMessage: { _, _ in return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, updateMessageReaction: { _ in }, activateMessagePinch: { _ in }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in }, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _ in return false }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in - }, presentController: { _, _ in }, navigationController: { + }, presentController: { _, _ in }, presentControllerInCurrent: { _, _ in }, navigationController: { return nil }, chatControllerNode: { return nil diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index b3e2babb50..f51039a1e5 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -786,7 +786,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState let _ = (saveToCameraRoll(context: context, postbox: context.account.postbox, mediaReference: mediaReference) |> deliverOnMainQueue).start(completed: { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - controllerInteraction.presentController(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: isVideo ? presentationData.strings.Gallery_VideoSaved : presentationData.strings.Gallery_ImageSaved), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) + controllerInteraction.presentControllerInCurrent(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: isVideo ? presentationData.strings.Gallery_VideoSaved : presentationData.strings.Gallery_ImageSaved), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return true }), nil) }) f(.default) }))) diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 6316ad6c64..1b841cee2e 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -295,6 +295,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { })) }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in }, presentController: { _, _ in + }, presentControllerInCurrent: { _, _ in }, navigationController: { [weak self] in return self?.getNavigationController() }, chatControllerNode: { [weak self] in diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index d28e65617b..3a5d0d7850 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -111,7 +111,9 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, updateMessageReaction: { _ in }, activateMessagePinch: { _ in }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in }, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { fileReference, _, _, _, _, node, rect in return selectStickerImpl?(fileReference, node, rect) ?? false }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in - }, presentController: { _, _ in }, navigationController: { + }, presentController: { _, _ in + }, presentControllerInCurrent: { _, _ in + }, navigationController: { return nil }, chatControllerNode: { return nil diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 11f692a83d..9c22d09ff8 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -99,6 +99,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, updateInputMode: { _ in }, openMessageShareMenu: { _ in }, presentController: { _, _ in + }, presentControllerInCurrent: { _, _ in }, navigationController: { return nil }, chatControllerNode: { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 2d0353aaba..b3b3b8b101 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -2039,6 +2039,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }, openMessageShareMenu: { _ in }, presentController: { [weak self] c, a in self?.controller?.present(c, in: .window(.root), with: a) + }, presentControllerInCurrent: { [weak self] c, a in + self?.controller?.present(c, in: .current, with: a) }, navigationController: { [weak self] in return self?.controller?.navigationController as? NavigationController }, chatControllerNode: { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 2f7ca8737d..d118725be3 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1248,7 +1248,9 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _ in return false }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in - }, presentController: { _, _ in }, navigationController: { + }, presentController: { _, _ in + }, presentControllerInCurrent: { _, _ in + }, navigationController: { return nil }, chatControllerNode: { return nil From 96629b3d375c512622b69c49c2969e81a319679f Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 20 Nov 2021 22:53:39 +0400 Subject: [PATCH 06/14] Fix sticker packs list --- .../Sources/ChatMediaInputNode.swift | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift index 05c826988d..0f925b1b93 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift @@ -1339,7 +1339,7 @@ final class ChatMediaInputNode: ChatInputNode { self.panelFocusTimer?.invalidate() } - private func updateIsExpanded(_ isExpanded: Bool) { + private func updateIsFocused(_ isExpanded: Bool) { guard self.panelIsFocused != isExpanded else { return } @@ -2054,7 +2054,7 @@ final class ChatMediaInputNode: ChatInputNode { panelHeight = standardInputHeight } - self.updateIsExpanded(isFocused) + self.updateIsFocused(isFocused) if displaySearch { if let searchContainerNode = self.searchContainerNode { @@ -2490,12 +2490,14 @@ final class ChatMediaInputNode: ChatInputNode { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if self.panelIsFocused { - let convertedPoint = CGPoint(x: max(0.0, point.y), y: point.x) - if let result = self.listView.hitTest(convertedPoint, with: event) { - return result - } - if let result = self.gifListView.hitTest(convertedPoint, with: event) { - return result + if point.y > -41.0 && point.y < 38.0 { + let convertedPoint = CGPoint(x: max(0.0, point.y), y: point.x) + if let result = self.listView.hitTest(convertedPoint, with: event) { + return result + } + if let result = self.gifListView.hitTest(convertedPoint, with: event) { + return result + } } } if let searchContainerNode = self.searchContainerNode { From 26b0b4021cbca449b3be506c04361eb5e17ff0c9 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 20 Nov 2021 23:37:24 +0400 Subject: [PATCH 07/14] Various Fixes --- .../Display/Source/ActionSheetControllerNode.swift | 9 ++++++++- .../Source/ActionSheetItemGroupsContainerNode.swift | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/submodules/Display/Source/ActionSheetControllerNode.swift b/submodules/Display/Source/ActionSheetControllerNode.swift index 403290a334..b53bb2ba1f 100644 --- a/submodules/Display/Source/ActionSheetControllerNode.swift +++ b/submodules/Display/Source/ActionSheetControllerNode.swift @@ -1,5 +1,6 @@ import UIKit import AsyncDisplayKit +import SwiftSignalKit private let containerInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0) @@ -59,6 +60,7 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate { self.bottomDimView.isUserInteractionEnabled = false self.itemGroupsContainerNode = ActionSheetItemGroupsContainerNode(theme: self.theme) + self.itemGroupsContainerNode.isUserInteractionEnabled = false super.init() @@ -128,6 +130,7 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate { self.updateScrollDimViews(size: layout.size, insets: insets, transition: transition) } + func animateIn(completion: @escaping () -> Void) { let tempDimView = UIView() tempDimView.backgroundColor = self.theme.dimColor @@ -144,6 +147,10 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate { tempDimView?.removeFromSuperview() completion() }) + + Queue.mainQueue().after(0.3, { + self.itemGroupsContainerNode.isUserInteractionEnabled = true + }) } func animateOut(cancelled: Bool) { @@ -170,7 +177,7 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate { } @objc func dimNodeTap(_ recognizer: UITapGestureRecognizer) { - if case .ended = recognizer.state { + if case .ended = recognizer.state, self.itemGroupsContainerNode.isUserInteractionEnabled { self.view.window?.endEditing(true) self.animateOut(cancelled: true) } diff --git a/submodules/Display/Source/ActionSheetItemGroupsContainerNode.swift b/submodules/Display/Source/ActionSheetItemGroupsContainerNode.swift index 35746efc72..966abcc311 100644 --- a/submodules/Display/Source/ActionSheetItemGroupsContainerNode.swift +++ b/submodules/Display/Source/ActionSheetItemGroupsContainerNode.swift @@ -84,6 +84,9 @@ final class ActionSheetItemGroupsContainerNode: ASDisplayNode { } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + guard self.isUserInteractionEnabled else { + return nil + } for groupNode in self.groupNodes { if groupNode.frame.contains(point) { return groupNode.hitTest(self.convert(point, to: groupNode), with: event) From b9ebdea4ca07f74b1ee86fc1bbeb02e1570bc067 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sun, 21 Nov 2021 00:30:43 +0400 Subject: [PATCH 08/14] Fix context reaction animation --- .../ContextUI/Sources/ContextController.swift | 17 +++++++++++------ .../Sources/ReactionContextNode.swift | 4 +++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index ec062da935..e1d07222db 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -843,8 +843,13 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi updatedContentAreaInScreenSpace.size.width = self.bounds.width self.clippingNode.view.mask = putBackInfo.maskView - self.clippingNode.layer.animateFrame(from: self.clippingNode.frame, to: updatedContentAreaInScreenSpace, duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false) - self.clippingNode.layer.animateBoundsOriginYAdditive(from: 0.0, to: updatedContentAreaInScreenSpace.minY, duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false) + let previousFrame = self.clippingNode.frame + self.clippingNode.position = updatedContentAreaInScreenSpace.center + self.clippingNode.bounds = CGRect(origin: CGPoint(), size: updatedContentAreaInScreenSpace.size) + self.clippingNode.layer.animatePosition(from: previousFrame.center, to: updatedContentAreaInScreenSpace.center, duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: true) + self.clippingNode.layer.animateBounds(from: CGRect(origin: CGPoint(), size: previousFrame.size), to: CGRect(origin: CGPoint(), size: updatedContentAreaInScreenSpace.size), duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: true) + //self.clippingNode.layer.animateFrame(from: previousFrame, to: updatedContentAreaInScreenSpace, duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false) + //self.clippingNode.layer.animateBoundsOriginYAdditive(from: 0.0, to: updatedContentAreaInScreenSpace.minY, duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false) } let intermediateCompletion: () -> Void = { [weak self, weak contentParentNode] in @@ -1136,10 +1141,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi self.reactionContextNodeIsAnimatingOut = true reactionContextNode.willAnimateOutToReaction(value: value) - self.animateOut(result: .default, completion: { - contentCompleted = true - intermediateCompletion() - }) reactionContextNode.animateOutToReaction(value: value, targetEmptyNode: targetEmptyNode, targetFilledNode: targetFilledNode, hideNode: hideNode, completion: { [weak self] in guard let strongSelf = self else { return @@ -1149,6 +1150,10 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi reactionCompleted = true intermediateCompletion() }) + self.animateOut(result: .default, completion: { + contentCompleted = true + intermediateCompletion() + }) self.isUserInteractionEnabled = false } diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index 2b2a94536f..c0622a10b7 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -379,7 +379,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { } else if let animateOutToAnchorRect = animateOutToAnchorRect { let targetBackgroundFrame = self.calculateBackgroundFrame(containerSize: size, insets: insets, anchorRect: animateOutToAnchorRect, contentSize: CGSize(width: visibleContentWidth, height: contentHeight)).0 - self.layer.animatePosition(from: CGPoint(), to: CGPoint(x: targetBackgroundFrame.minX - backgroundFrame.minX, y: targetBackgroundFrame.minY - backgroundFrame.minY), duration: 0.2, removeOnCompletion: false, additive: true) + let offset = CGPoint(x: -(targetBackgroundFrame.minX - backgroundFrame.minX), y: -(targetBackgroundFrame.minY - backgroundFrame.minY)) + self.position = CGPoint(x: self.position.x - offset.x, y: self.position.y - offset.y) + self.layer.animatePosition(from: offset, to: CGPoint(), duration: 0.2, removeOnCompletion: true, additive: true) } } From a92a444c057e700626a6233e607a1b16ae8091e6 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 21 Nov 2021 01:49:56 +0400 Subject: [PATCH 09/14] Various Fixes --- .../TGModernConversationInputMicButton.h | 1 + .../TGModernConversationInputMicButton.m | 5 +++++ .../Sources/ChatHistoryListNode.swift | 13 +++++++++--- .../ChatTextInputMediaRecordingButton.swift | 20 ++++++++++++++++++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGModernConversationInputMicButton.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGModernConversationInputMicButton.h index 271e7c16b7..9e94a8da14 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGModernConversationInputMicButton.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGModernConversationInputMicButton.h @@ -81,6 +81,7 @@ - (void)animateOut:(BOOL)toSmallSize; - (void)addMicLevel:(CGFloat)level; - (void)dismiss; +- (void)reset; - (void)updateOverlay; diff --git a/submodules/LegacyComponents/Sources/TGModernConversationInputMicButton.m b/submodules/LegacyComponents/Sources/TGModernConversationInputMicButton.m index 0b7799d810..b2ff07f07d 100644 --- a/submodules/LegacyComponents/Sources/TGModernConversationInputMicButton.m +++ b/submodules/LegacyComponents/Sources/TGModernConversationInputMicButton.m @@ -869,6 +869,11 @@ static const CGFloat outerCircleMinScale = innerCircleRadius / outerCircleRadius } } +- (void)reset { + _targetTranslation = 0.0; + [self updateOverlay]; +} + - (void)addMicLevel:(CGFloat)level { _inputLevel = level; [_decoration updateLevel:level]; diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 5f73ba2cd1..e751b4a129 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -1167,9 +1167,16 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } var scrollAnimationCurve: ListViewAnimationCurve? = nil - if let strongSelf = self, strongSelf.appliedPlayingMessageId != currentlyPlayingMessageId, let currentlyPlayingMessageId = currentlyPlayingMessageId { - updatedScrollPosition = .index(index: .message(currentlyPlayingMessageId), position: .center(.bottom), directionHint: .Down, animated: true, highlight: true) - scrollAnimationCurve = .Spring(duration: 0.4) + if let strongSelf = self, case .default = source { + if strongSelf.appliedPlayingMessageId != currentlyPlayingMessageId, let currentlyPlayingMessageId = currentlyPlayingMessageId { + if isFirstTime { + } else if case let .peer(peerId) = chatLocation, currentlyPlayingMessageId.id.peerId != peerId { + } else { + updatedScrollPosition = .index(index: .message(currentlyPlayingMessageId), position: .center(.bottom), directionHint: .Up, animated: true, highlight: true) + scrollAnimationCurve = .Spring(duration: 0.4) + } + } + isFirstTime = false } var disableAnimations = false diff --git a/submodules/TelegramUI/Sources/ChatTextInputMediaRecordingButton.swift b/submodules/TelegramUI/Sources/ChatTextInputMediaRecordingButton.swift index 50df9ac3d0..56868447d4 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputMediaRecordingButton.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputMediaRecordingButton.swift @@ -98,6 +98,8 @@ private final class ChatTextInputMediaRecordingButtonPresenter : NSObject, TGMod private let presentController: (ViewController) -> Void let container: ChatTextInputMediaRecordingButtonPresenterContainer private var presentationController: ChatTextInputMediaRecordingButtonPresenterController? + private var timer: SwiftSignalKit.Timer? + fileprivate weak var button: ChatTextInputMediaRecordingButton? init(account: Account, presentController: @escaping (ViewController) -> Void) { self.account = account @@ -111,6 +113,7 @@ private final class ChatTextInputMediaRecordingButtonPresenter : NSObject, TGMod presentationController.presentingViewController?.dismiss(animated: false, completion: {}) self.presentationController = nil } + self.timer?.invalidate() } func view() -> UIView! { @@ -124,6 +127,14 @@ private final class ChatTextInputMediaRecordingButtonPresenter : NSObject, TGMod func present() { if let keyboardWindow = LegacyComponentsGlobals.provider().applicationKeyboardWindow(), !keyboardWindow.isHidden { keyboardWindow.addSubview(self.container) + + self.timer = SwiftSignalKit.Timer(timeout: 0.05, repeat: true, completion: { [weak self] in + if let keyboardWindow = LegacyComponentsGlobals.provider().applicationKeyboardWindow(), !keyboardWindow.isHidden { + } else { + self?.present() + } + }, queue: Queue.mainQueue()) + self.timer?.start() } else { var presentNow = false if self.presentationController == nil { @@ -137,10 +148,16 @@ private final class ChatTextInputMediaRecordingButtonPresenter : NSObject, TGMod if let presentationController = self.presentationController, presentNow { self.presentController(presentationController) } + + if let timer = self.timer { + self.button?.reset() + timer.invalidate() + } } } func dismiss() { + self.timer?.invalidate() self.container.removeFromSuperview() if let presentationController = self.presentationController { presentationController.presentingViewController?.dismiss(animated: false, completion: {}) @@ -171,7 +188,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto private var recordingOverlay: ChatTextInputAudioRecordingOverlay? private var startTouchLocation: CGPoint? - private(set) var controlsOffset: CGFloat = 0.0 + fileprivate var controlsOffset: CGFloat = 0.0 private(set) var cancelTranslation: CGFloat = 0.0 private var micLevelDisposable: MetaDisposable? @@ -426,6 +443,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto func micButtonPresenter() -> TGModernConversationInputMicButtonPresentation! { let presenter = ChatTextInputMediaRecordingButtonPresenter(account: self.account!, presentController: self.presentController) + presenter.button = self self.currentPresenter = presenter.view() return presenter } From d2015f33759c2de285148b07b7fcefa40f0e91d5 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 21 Nov 2021 18:11:11 +0400 Subject: [PATCH 10/14] Various Fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 5 ++ .../Sources/SharedMediaPlayer.swift | 9 ++-- .../Items/UniversalVideoGalleryItem.swift | 5 +- .../Sources/InstantPageMediaPlaylist.swift | 10 ++-- .../AvatarGalleryItemFooterContentNode.swift | 7 +++ .../RecentSessionsController.swift | 2 +- .../RecentSessionsHeaderItem.swift | 6 +-- .../ChatMessageAnimatedStickerItemNode.swift | 28 +++++----- .../Sources/ChatMessageBubbleItemNode.swift | 2 + .../Sources/ChatMessageDateHeader.swift | 6 ++- .../ChatMessageInstantVideoItemNode.swift | 28 +++++----- .../Sources/ChatMessageStickerItemNode.swift | 28 +++++----- .../Sources/ChatTextInputPanelNode.swift | 2 +- .../Sources/DocumentPreviewController.swift | 51 +++++++++++++++++-- .../TelegramUI/Sources/OpenChatMessage.swift | 2 +- .../Sources/OverlayPlayerControlsNode.swift | 8 ++- .../Sources/PeerMessagesMediaPlaylist.swift | 2 +- .../Sources/SharedMediaPlayer.swift | 8 +-- 18 files changed, 145 insertions(+), 64 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 478a802666..188dbc95c9 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7057,6 +7057,11 @@ Sorry for the inconvenience."; "Conversation.CopyProtectionInfoGroup" = "Admins restricted members to copy or forward content from this group."; "Conversation.CopyProtectionInfoChannel" = "Admins restricted members to copy or forward content from this channel."; +"Conversation.CopyProtectionForwardingDisabledGroup" = "Forwards from this group are restricted"; +"Conversation.CopyProtectionForwardingDisabledChannel" = "Forwards from this channel are restricted"; +"Conversation.CopyProtectionSavingDisabledGroup" = "Saving from this group is restricted"; +"Conversation.CopyProtectionSavingDisabledChannel" = "Saving from this channel is restricted"; + "Channel.AdminLog.MessageToggleNoForwardsOn" = "%@ restricted message forwarding"; "Channel.AdminLog.MessageToggleNoForwardsOff" = "%@ allowed message forwarding"; diff --git a/submodules/AccountContext/Sources/SharedMediaPlayer.swift b/submodules/AccountContext/Sources/SharedMediaPlayer.swift index 6217d6f815..584461a252 100644 --- a/submodules/AccountContext/Sources/SharedMediaPlayer.swift +++ b/submodules/AccountContext/Sources/SharedMediaPlayer.swift @@ -13,15 +13,18 @@ public enum SharedMediaPlaybackDataType { } public enum SharedMediaPlaybackDataSource: Equatable { - case telegramFile(FileMediaReference) + case telegramFile(reference: FileMediaReference, isCopyProtected: Bool) public static func ==(lhs: SharedMediaPlaybackDataSource, rhs: SharedMediaPlaybackDataSource) -> Bool { switch lhs { - case let .telegramFile(lhsFileReference): - if case let .telegramFile(rhsFileReference) = rhs { + case let .telegramFile(lhsFileReference, lhsIsCopyProtected): + if case let .telegramFile(rhsFileReference, rhsIsCopyProtected) = rhs { if !lhsFileReference.media.isEqual(to: rhsFileReference.media) { return false } + if lhsIsCopyProtected != rhsIsCopyProtected { + return false + } return true } else { return false diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 7da6c75921..1506aa3f98 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -2423,8 +2423,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { let url = content.url let item = OpenInItem.url(url: url) - let canOpenIn = availableOpenInOptions(context: strongSelf.context, item: item).count > 1 - let openText = canOpenIn ? strongSelf.presentationData.strings.Conversation_FileOpenIn : strongSelf.presentationData.strings.Conversation_LinkDialogOpen + let openText = strongSelf.presentationData.strings.Conversation_FileOpenIn items.append(.action(ContextMenuActionItem(text: openText, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { _, f in f(.default) @@ -2446,7 +2445,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } - if let (message, maybeFile, _) = strongSelf.contentInfo(), let file = maybeFile { + if let (message, maybeFile, _) = strongSelf.contentInfo(), let file = maybeFile, !message.isCopyProtected() { items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Gallery_SaveVideo, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in f(.default) diff --git a/submodules/InstantPageUI/Sources/InstantPageMediaPlaylist.swift b/submodules/InstantPageUI/Sources/InstantPageMediaPlaylist.swift index 25fdfb9d3c..c7e42e2916 100644 --- a/submodules/InstantPageUI/Sources/InstantPageMediaPlaylist.swift +++ b/submodules/InstantPageUI/Sources/InstantPageMediaPlaylist.swift @@ -46,13 +46,13 @@ final class InstantPageMediaPlaylistItem: SharedMediaPlaylistItem { switch attribute { case let .Audio(isVoice, _, _, _, _): if isVoice { - return SharedMediaPlaybackData(type: .voice, source: .telegramFile(.webPage(webPage: WebpageReference(self.webPage), media: file))) + return SharedMediaPlaybackData(type: .voice, source: .telegramFile(reference: .webPage(webPage: WebpageReference(self.webPage), media: file), isCopyProtected: false)) } else { - return SharedMediaPlaybackData(type: .music, source: .telegramFile(.webPage(webPage: WebpageReference(self.webPage), media: file))) + return SharedMediaPlaybackData(type: .music, source: .telegramFile(reference: .webPage(webPage: WebpageReference(self.webPage), media: file), isCopyProtected: false)) } case let .Video(_, _, flags): if flags.contains(.instantRoundVideo) { - return SharedMediaPlaybackData(type: .instantVideo, source: .telegramFile(.webPage(webPage: WebpageReference(self.webPage), media: file))) + return SharedMediaPlaybackData(type: .instantVideo, source: .telegramFile(reference: .webPage(webPage: WebpageReference(self.webPage), media: file), isCopyProtected: false)) } else { return nil } @@ -61,12 +61,12 @@ final class InstantPageMediaPlaylistItem: SharedMediaPlaylistItem { } } if file.mimeType.hasPrefix("audio/") { - return SharedMediaPlaybackData(type: .music, source: .telegramFile(.webPage(webPage: WebpageReference(self.webPage), media: file))) + return SharedMediaPlaybackData(type: .music, source: .telegramFile(reference: .webPage(webPage: WebpageReference(self.webPage), media: file), isCopyProtected: false)) } if let fileName = file.fileName { let ext = (fileName as NSString).pathExtension.lowercased() if ext == "wav" || ext == "opus" { - return SharedMediaPlaybackData(type: .music, source: .telegramFile(.webPage(webPage: WebpageReference(self.webPage), media: file))) + return SharedMediaPlaybackData(type: .music, source: .telegramFile(reference: .webPage(webPage: WebpageReference(self.webPage), media: file), isCopyProtected: false)) } } } diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift index c75cba79f5..2f36df53a5 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift @@ -105,6 +105,7 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode { var dateText: String? var typeText: String? var buttonText: String? + var canShare = true switch entry { case let .image(_, _, _, videoRepresentations, peer, date, _, _, _, _): nameText = peer.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "" @@ -119,6 +120,10 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode { typeText = self.strings.ProfilePhoto_MainPhoto buttonText = self.strings.ProfilePhoto_SetMainPhoto } + + if let peer = peer { + canShare = !peer.isCopyProtectionEnabled + } default: break } @@ -151,6 +156,8 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode { } } + self.actionButton.isHidden = !canShare + switch content { case .info: self.nameNode.isHidden = false diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift index 5ce9e6415a..01dece6d67 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift @@ -757,7 +757,7 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont pushControllerImpl?(AuthTransferScanScreen(context: context, activeSessionsContext: activeSessionsContext)) }) }, openOtherAppsUrl: { - context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: "https://desktop.telegram.org", forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {}) + context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: "https://getdesktop.telegram.org", forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {}) }, setupAuthorizationTTL: { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let controller = ActionSheetController(presentationData: presentationData) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsHeaderItem.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsHeaderItem.swift index 27d913d50b..aa61efb90e 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsHeaderItem.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsHeaderItem.swift @@ -131,7 +131,7 @@ class RecentSessionsHeaderItemNode: ListViewItemNode { let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) - let contentSize = CGSize(width: params.width, height: topInset + titleLayout.size.height + 85.0) + let contentSize = CGSize(width: params.width, height: topInset + titleLayout.size.height + 69.0) let insets = itemListNeighborsGroupedInsets(neighbors, params) let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) @@ -150,9 +150,9 @@ class RecentSessionsHeaderItemNode: ListViewItemNode { strongSelf.buttonNode.updateTheme(SolidRoundedButtonTheme(theme: item.theme)) } - let buttonWidth = contentSize.width - 32.0 + let buttonWidth = min(375, contentSize.width - params.leftInset - params.rightInset) let buttonHeight = strongSelf.buttonNode.updateLayout(width: buttonWidth, transition: .immediate) - let buttonFrame = CGRect(x: 16.0, y: contentSize.height - buttonHeight - 12.0, width: buttonWidth, height: buttonHeight) + let buttonFrame = CGRect(x: params.leftInset, y: contentSize.height - buttonHeight + 4.0, width: buttonWidth, height: buttonHeight) strongSelf.buttonNode.frame = buttonFrame strongSelf.accessibilityLabel = attributedText.string diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 974b32a0dc..620bc7c79a 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -782,15 +782,15 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp()) - var needShareButton = false + var needsShareButton = false if case .pinnedMessages = item.associatedData.subject { - needShareButton = true + needsShareButton = true } else if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) { - needShareButton = false + needsShareButton = false } else if item.message.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { for attribute in item.content.firstMessage.attributes { if let _ = attribute as? SourceReferenceMessageAttribute { - needShareButton = true + needsShareButton = true break } } @@ -798,31 +798,35 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let peer = item.message.peers[item.message.id.peerId] { if let channel = peer as? TelegramChannel { if case .broadcast = channel.info { - needShareButton = true + needsShareButton = true } } } - if !needShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty { - needShareButton = true + if !needsShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty { + needsShareButton = true } - if !needShareButton { + if !needsShareButton { loop: for media in item.message.media { if media is TelegramMediaGame || media is TelegramMediaInvoice { - needShareButton = true + needsShareButton = true break loop } else if let media = media as? TelegramMediaWebpage, case .Loaded = media.content { - needShareButton = true + needsShareButton = true break loop } } } else { loop: for media in item.message.media { if media is TelegramMediaAction { - needShareButton = false + needsShareButton = false break loop } } } + + if item.associatedData.isCopyProtectionEnabled { + needsShareButton = false + } } var layoutInsets = UIEdgeInsets(top: mergedTop.merged ? layoutConstants.bubble.mergedSpacing : layoutConstants.bubble.defaultSpacing, left: 0.0, bottom: mergedBottom.merged ? layoutConstants.bubble.mergedSpacing : layoutConstants.bubble.defaultSpacing, right: 0.0) @@ -955,7 +959,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } var updatedShareButtonNode: ChatMessageShareButton? - if needShareButton { + if needsShareButton { if let currentShareButtonNode = currentShareButtonNode { updatedShareButtonNode = currentShareButtonNode } else { diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 5596d847e6..1e6e68a410 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -1118,6 +1118,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode tmpWidth = baseWidth if needsShareButton || isAd { tmpWidth -= 38.0 + } else { + tmpWidth -= 4.0 } } else { tmpWidth = layoutConstants.bubble.maximumWidthFill.widthFor(baseWidth) diff --git a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift index 64f871ad5b..ac3c179125 100644 --- a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift +++ b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift @@ -501,7 +501,11 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode { if self.peerId.namespace == Namespaces.Peer.Empty, case let .message(_, id, _, _, _) = self.messageReference?.content { self.controllerInteraction.displayMessageTooltip(id, self.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, self.avatarNode.frame) } else { - self.controllerInteraction.openPeer(self.peerId, .info, nil) + if let channel = self.peer as? TelegramChannel, case .broadcast = channel.info { + self.controllerInteraction.openPeer(self.peerId, .chat(textInputState: nil, subject: nil, peekData: nil), nil) + } else { + self.controllerInteraction.openPeer(self.peerId, .info, nil) + } } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index 357d80fae9..2e84df6df2 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -306,16 +306,16 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp()) - var needShareButton = false + var needsShareButton = false if case .pinnedMessages = item.associatedData.subject { - needShareButton = true + needsShareButton = true } else if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) { - needShareButton = false + needsShareButton = false } else if item.message.id.peerId == item.context.account.peerId { for attribute in item.content.firstMessage.attributes { if let _ = attribute as? SourceReferenceMessageAttribute { - needShareButton = true + needsShareButton = true break } } @@ -323,31 +323,35 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD if let peer = item.message.peers[item.message.id.peerId] { if let channel = peer as? TelegramChannel { if case .broadcast = channel.info { - needShareButton = true + needsShareButton = true } } } - if !needShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty { - needShareButton = true + if !needsShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty { + needsShareButton = true } - if !needShareButton { + if !needsShareButton { loop: for media in item.message.media { if media is TelegramMediaGame || media is TelegramMediaInvoice { - needShareButton = true + needsShareButton = true break loop } else if let media = media as? TelegramMediaWebpage, case .Loaded = media.content { - needShareButton = true + needsShareButton = true break loop } } } else { loop: for media in item.message.media { if media is TelegramMediaAction { - needShareButton = false + needsShareButton = false break loop } } } + + if item.associatedData.isCopyProtectionEnabled { + needsShareButton = false + } } var layoutInsets = layoutConstants.instantVideo.insets @@ -472,7 +476,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD } var updatedShareButtonNode: ChatMessageShareButton? - if needShareButton { + if needsShareButton { if currentShareButtonNode != nil { updatedShareButtonNode = currentShareButtonNode } else { diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index 2fa451dd9b..244c5c0fc8 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -380,15 +380,15 @@ class ChatMessageStickerItemNode: ChatMessageItemView { let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp()) - var needShareButton = false + var needsShareButton = false if case .pinnedMessages = item.associatedData.subject { - needShareButton = true + needsShareButton = true } else if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) { - needShareButton = false + needsShareButton = false } else if item.message.id.peerId == item.context.account.peerId { for attribute in item.content.firstMessage.attributes { if let _ = attribute as? SourceReferenceMessageAttribute { - needShareButton = true + needsShareButton = true break } } @@ -396,31 +396,35 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if let peer = item.message.peers[item.message.id.peerId] { if let channel = peer as? TelegramChannel { if case .broadcast = channel.info { - needShareButton = true + needsShareButton = true } } } - if !needShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty { - needShareButton = true + if !needsShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty { + needsShareButton = true } - if !needShareButton { + if !needsShareButton { loop: for media in item.message.media { if media is TelegramMediaGame || media is TelegramMediaInvoice { - needShareButton = true + needsShareButton = true break loop } else if let media = media as? TelegramMediaWebpage, case .Loaded = media.content { - needShareButton = true + needsShareButton = true break loop } } } else { loop: for media in item.message.media { if media is TelegramMediaAction { - needShareButton = false + needsShareButton = false break loop } } } + + if item.associatedData.isCopyProtectionEnabled { + needsShareButton = false + } } var layoutInsets = UIEdgeInsets(top: mergedTop.merged ? layoutConstants.bubble.mergedSpacing : layoutConstants.bubble.defaultSpacing, left: 0.0, bottom: mergedBottom.merged ? layoutConstants.bubble.mergedSpacing : layoutConstants.bubble.defaultSpacing, right: 0.0) @@ -553,7 +557,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { } var updatedShareButtonNode: ChatMessageShareButton? - if needShareButton { + if needsShareButton { if let currentShareButtonNode = currentShareButtonNode { updatedShareButtonNode = currentShareButtonNode } else { diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index d36c5ecdb3..57e3745aad 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -1115,7 +1115,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { var hasMenuButton = false var menuButtonExpanded = false var isSendAsButton = false - if let sendAsPeers = interfaceState.sendAsPeers, !sendAsPeers.isEmpty { + if let sendAsPeers = interfaceState.sendAsPeers, !sendAsPeers.isEmpty && interfaceState.editMessageState == nil { hasMenuButton = true menuButtonExpanded = false isSendAsButton = true diff --git a/submodules/TelegramUI/Sources/DocumentPreviewController.swift b/submodules/TelegramUI/Sources/DocumentPreviewController.swift index 186561cdd0..04ba8eff94 100644 --- a/submodules/TelegramUI/Sources/DocumentPreviewController.swift +++ b/submodules/TelegramUI/Sources/DocumentPreviewController.swift @@ -111,14 +111,16 @@ final class DocumentPreviewController: UINavigationController, QLPreviewControll final class CompactDocumentPreviewController: QLPreviewController, QLPreviewControllerDelegate, QLPreviewControllerDataSource { private let postbox: Postbox private let file: TelegramMediaFile + private let canShare: Bool private var item: DocumentPreviewItem? private var tempFile: TempBoxFile? - init(theme: PresentationTheme, strings: PresentationStrings, postbox: Postbox, file: TelegramMediaFile) { + init(theme: PresentationTheme, strings: PresentationStrings, postbox: Postbox, file: TelegramMediaFile, canShare: Bool = true) { self.postbox = postbox self.file = file + self.canShare = canShare super.init(nibName: nil, bundle: nil) @@ -144,6 +146,7 @@ final class CompactDocumentPreviewController: QLPreviewController, QLPreviewCont if let tempFile = self.tempFile { TempBox.shared.dispose(tempFile) } + self.timer?.invalidate() } @objc private func cancelPressed() { @@ -174,9 +177,51 @@ final class CompactDocumentPreviewController: QLPreviewController, QLPreviewCont func previewControllerDidDismiss(_ controller: QLPreviewController) { //self.cancelPressed() } + + private var toolbars: [UIView] = [] + private var observations : [NSKeyValueObservation] = [] + + private var initialized = false + private var timer: SwiftSignalKit.Timer? + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if !self.canShare && !self.initialized { + self.initialized = true + + self.timer = SwiftSignalKit.Timer(timeout: 0.01, repeat: true, completion: { [weak self] in + self?.tick() + }, queue: Queue.mainQueue()) + self.timer?.start() + } + } + + private func tick() { + self.navigationItem.rightBarButtonItems?[0] = UIBarButtonItem() + self.navigationItem.setRightBarButton(UIBarButtonItem(), animated: false) + + self.navigationController?.toolbar.isHidden = true + + self.toolbars = self.toolbarsInSubviews(forView: self.view) + + for toolbar in self.toolbars { + toolbar.isHidden = true + } + } + + private func toolbarsInSubviews(forView view: UIView) -> [UIView] { + var toolbars: [UIView] = [] + for subview in view.subviews { + if subview is UIToolbar { + toolbars.append(subview) + } + toolbars.append(contentsOf: toolbarsInSubviews(forView: subview)) + } + return toolbars + } } -func presentDocumentPreviewController(rootController: UIViewController, theme: PresentationTheme, strings: PresentationStrings, postbox: Postbox, file: TelegramMediaFile) { +func presentDocumentPreviewController(rootController: UIViewController, theme: PresentationTheme, strings: PresentationStrings, postbox: Postbox, file: TelegramMediaFile, canShare: Bool) { if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { let navigationBar = UINavigationBar.appearance(whenContainedInInstancesOf: [QLPreviewController.self]) navigationBar.barTintColor = theme.rootController.navigationBar.opaqueBackgroundColor @@ -194,5 +239,5 @@ func presentDocumentPreviewController(rootController: UIViewController, theme: P navigationBar.titleTextAttributes = [NSAttributedString.Key.font: Font.semibold(17.0), NSAttributedString.Key.foregroundColor: theme.rootController.navigationBar.primaryTextColor] } - rootController.present(CompactDocumentPreviewController(theme: theme, strings: strings, postbox: postbox, file: file), animated: true, completion: nil) + rootController.present(CompactDocumentPreviewController(theme: theme, strings: strings, postbox: postbox, file: file, canShare: canShare), animated: true, completion: nil) } diff --git a/submodules/TelegramUI/Sources/OpenChatMessage.swift b/submodules/TelegramUI/Sources/OpenChatMessage.swift index dca61c8c93..94bdfdb06d 100644 --- a/submodules/TelegramUI/Sources/OpenChatMessage.swift +++ b/submodules/TelegramUI/Sources/OpenChatMessage.swift @@ -114,7 +114,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { params.present(controller, nil) } else if let rootController = params.navigationController?.view.window?.rootViewController { let proceed = { - presentDocumentPreviewController(rootController: rootController, theme: presentationData.theme, strings: presentationData.strings, postbox: params.context.account.postbox, file: file) + presentDocumentPreviewController(rootController: rootController, theme: presentationData.theme, strings: presentationData.strings, postbox: params.context.account.postbox, file: file, canShare: !params.message.isCopyProtected()) } if file.mimeType.contains("image/svg") { let presentationData = params.context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift b/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift index 9c1a301fc8..4a28ef7c0c 100644 --- a/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift +++ b/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift @@ -393,10 +393,12 @@ final class OverlayPlayerControlsNode: ASDisplayNode { if strongSelf.displayData != displayData { strongSelf.displayData = displayData - + + var canShare = true if let (_, valueOrLoading, _) = value, case let .state(value) = valueOrLoading, let source = value.item.playbackData?.source { switch source { - case let .telegramFile(fileReference): + case let .telegramFile(fileReference, isCopyProtected): + canShare = !isCopyProtected strongSelf.currentFileReference = fileReference if let size = fileReference.media.size { strongSelf.scrubberNode.bufferingStatus = strongSelf.postbox.mediaBox.resourceRangesStatus(fileReference.media.resource) @@ -411,6 +413,8 @@ final class OverlayPlayerControlsNode: ASDisplayNode { strongSelf.scrubberNode.bufferingStatus = nil } strongSelf.updateLabels(transition: .immediate) + + strongSelf.shareNode.isHidden = !canShare } }) diff --git a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift index a53e1eb2eb..6396344dc5 100644 --- a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift +++ b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift @@ -61,7 +61,7 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem { var playbackData: SharedMediaPlaybackData? { if let file = extractFileMedia(self.message) { let fileReference = FileMediaReference.message(message: MessageReference(self.message), media: file) - let source = SharedMediaPlaybackDataSource.telegramFile(fileReference) + let source = SharedMediaPlaybackDataSource.telegramFile(reference: fileReference, isCopyProtected: self.message.isCopyProtected()) for attribute in file.attributes { switch attribute { case let .Audio(isVoice, _, _, _, _): diff --git a/submodules/TelegramUI/Sources/SharedMediaPlayer.swift b/submodules/TelegramUI/Sources/SharedMediaPlayer.swift index d235274ce2..21c4e4bd4d 100644 --- a/submodules/TelegramUI/Sources/SharedMediaPlayer.swift +++ b/submodules/TelegramUI/Sources/SharedMediaPlayer.swift @@ -227,13 +227,13 @@ final class SharedMediaPlayer { switch playbackData.type { case .voice, .music: switch playbackData.source { - case let .telegramFile(fileReference): + case let .telegramFile(fileReference, _): strongSelf.playbackItem = .audio(MediaPlayer(audioSessionManager: strongSelf.audioSession, postbox: strongSelf.account.postbox, resourceReference: fileReference.resourceReference(fileReference.media.resource), streamable: playbackData.type == .music ? .conservative : .none, video: false, preferSoftwareDecoding: false, enableSound: true, baseRate: rateValue, fetchAutomatically: true, playAndRecord: controlPlaybackWithProximity)) } case .instantVideo: if let mediaManager = strongSelf.mediaManager, let item = item as? MessageMediaPlaylistItem { switch playbackData.source { - case let .telegramFile(fileReference): + case let .telegramFile(fileReference, _): let videoNode = OverlayInstantVideoNode(postbox: strongSelf.account.postbox, audioSession: strongSelf.audioSession, manager: mediaManager.universalVideoManager, content: NativeVideoContent(id: .message(item.message.stableId, fileReference.media.fileId), fileReference: fileReference, enableSound: false, baseRate: rateValue), close: { [weak mediaManager] in mediaManager?.setPlaylist(nil, type: .voice, control: .playback(.pause)) }) @@ -483,7 +483,7 @@ final class SharedMediaPlayer { let fetchedCurrentSignal: Signal let fetchedNextSignal: Signal switch current { - case let .telegramFile(file): + case let .telegramFile(file, _): fetchedCurrentSignal = self.account.postbox.mediaBox.resourceData(file.media.resource) |> mapToSignal { data -> Signal in if data.complete { @@ -496,7 +496,7 @@ final class SharedMediaPlayer { |> ignoreValues } switch next { - case let .telegramFile(file): + case let .telegramFile(file, _): fetchedNextSignal = fetchedMediaResource(mediaBox: self.account.postbox.mediaBox, reference: file.resourceReference(file.media.resource)) |> ignoreValues |> `catch` { _ -> Signal in From 2139caf562450b912781059a84a13f7d9e86d573 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 21 Nov 2021 21:22:33 +0400 Subject: [PATCH 11/14] Fix link device button --- .../Recent Sessions/RecentSessionsHeaderItem.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsHeaderItem.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsHeaderItem.swift index aa61efb90e..40964505c3 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsHeaderItem.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsHeaderItem.swift @@ -152,7 +152,7 @@ class RecentSessionsHeaderItemNode: ListViewItemNode { let buttonWidth = min(375, contentSize.width - params.leftInset - params.rightInset) let buttonHeight = strongSelf.buttonNode.updateLayout(width: buttonWidth, transition: .immediate) - let buttonFrame = CGRect(x: params.leftInset, y: contentSize.height - buttonHeight + 4.0, width: buttonWidth, height: buttonHeight) + let buttonFrame = CGRect(x: floorToScreenPixels((params.width - buttonWidth) / 2.0), y: contentSize.height - buttonHeight + 4.0, width: buttonWidth, height: buttonHeight) strongSelf.buttonNode.frame = buttonFrame strongSelf.accessibilityLabel = attributedText.string From 5a5bd780f9369e1afbd42f395b697f94794719af Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 21 Nov 2021 21:28:06 +0400 Subject: [PATCH 12/14] Fix share button in audio player --- submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift b/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift index 4a28ef7c0c..30c4063095 100644 --- a/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift +++ b/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift @@ -314,7 +314,6 @@ final class OverlayPlayerControlsNode: ASDisplayNode { } var rateButtonIsHidden = true - strongSelf.shareNode.isHidden = false var displayData: SharedMediaPlaybackDisplayData? if let (_, valueOrLoading, _) = value, case let .state(value) = valueOrLoading { var isPaused: Bool From 6fc891474ca7fcb053d0673a108b48afe39bfe26 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 22 Nov 2021 00:03:11 +0400 Subject: [PATCH 13/14] Increase grouped media max height --- submodules/TelegramUI/Sources/ChatMessageItemView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramUI/Sources/ChatMessageItemView.swift b/submodules/TelegramUI/Sources/ChatMessageItemView.swift index 9fa9fd2672..727641def8 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItemView.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItemView.swift @@ -86,7 +86,7 @@ struct ChatMessageItemLayoutConstants { fileprivate static var compact: ChatMessageItemLayoutConstants { let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)) let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0)) - let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 0.0, maxDimensions: CGSize(width: 300.0, height: 300.0), minDimensions: CGSize(width: 170.0, height: 74.0)) + let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 0.0, maxDimensions: CGSize(width: 300.0, height: 380.0), minDimensions: CGSize(width: 170.0, height: 74.0)) let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0) let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0)) let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 212.0, height: 212.0)) From eef0891e96773e00228681d6e2904c2044c80a48 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 22 Nov 2021 01:10:51 +0400 Subject: [PATCH 14/14] Enabled capture prevention in forward-restricted chats --- .../TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift index 22d17d348d..2d4a5a9e74 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift @@ -970,7 +970,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio } if let updateImageSignal = updateImageSignal { - strongSelf.imageNode.captureProtected = message.id.peerId.namespace == Namespaces.Peer.SecretChat + strongSelf.imageNode.captureProtected = message.id.peerId.namespace == Namespaces.Peer.SecretChat || message.isCopyProtected() strongSelf.imageNode.setSignal(updateImageSignal(synchronousLoads, false), attemptSynchronously: synchronousLoads) var imageDimensions: CGSize?