diff --git a/submodules/Display/Display/ContainedViewLayoutTransition.swift b/submodules/Display/Display/ContainedViewLayoutTransition.swift index 1177880c29..20818b87fe 100644 --- a/submodules/Display/Display/ContainedViewLayoutTransition.swift +++ b/submodules/Display/Display/ContainedViewLayoutTransition.swift @@ -6,6 +6,10 @@ public enum ContainedViewLayoutTransitionCurve { case easeInOut case spring case custom(Float, Float, Float, Float) + + public static var slide: ContainedViewLayoutTransitionCurve { + return .custom(0.33, 0.52, 0.25, 0.99) + } } public extension ContainedViewLayoutTransitionCurve { diff --git a/submodules/Display/Display/GridNode.swift b/submodules/Display/Display/GridNode.swift index e0f8c2e475..ce9b59319f 100644 --- a/submodules/Display/Display/GridNode.swift +++ b/submodules/Display/Display/GridNode.swift @@ -939,12 +939,13 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { if let offset = offset { let timingFunction = curve.timingFunction + let mediaTimingFunction = curve.mediaTimingFunction for (index, itemNode) in self.itemNodes where existingItemIndices.contains(index) { - itemNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: timingFunction, additive: true) + itemNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction, additive: true) } for (wrappedSection, sectionNode) in self.sectionNodes where existingSections.contains(wrappedSection) { - sectionNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: timingFunction, additive: true) + sectionNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction, additive: true) } for index in self.itemNodes.keys { @@ -953,7 +954,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { if let previousFrame = previousItemFrames[WrappedGridItemNode(node: itemNode)] { self.removeItemNodeWithIndex(index, removeNode: false) let position = CGPoint(x: previousFrame.midX, y: previousFrame.midY) - itemNode.layer.animatePosition(from: CGPoint(x: position.x, y: position.y + contentOffset.y - boundsOffset), to: CGPoint(x: position.x, y: position.y + contentOffset.y - boundsOffset - offset), duration: duration, timingFunction: timingFunction, removeOnCompletion: false, force: true, completion: { [weak itemNode] _ in + itemNode.layer.animatePosition(from: CGPoint(x: position.x, y: position.y + contentOffset.y - boundsOffset), to: CGPoint(x: position.x, y: position.y + contentOffset.y - boundsOffset - offset), duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction, removeOnCompletion: false, force: true, completion: { [weak itemNode] _ in itemNode?.removeFromSupernode() }) } else { @@ -965,7 +966,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { for itemNode in removedNodes { if let previousFrame = previousItemFrames[WrappedGridItemNode(node: itemNode)] { let position = CGPoint(x: previousFrame.midX, y: previousFrame.midY) - itemNode.layer.animatePosition(from: CGPoint(x: position.x, y: position.y + contentOffset.y), to: CGPoint(x: position.x, y: position.y + contentOffset.y - offset), duration: duration, timingFunction: timingFunction, removeOnCompletion: false, force: true, completion: { [weak itemNode] _ in + itemNode.layer.animatePosition(from: CGPoint(x: position.x, y: position.y + contentOffset.y), to: CGPoint(x: position.x, y: position.y + contentOffset.y - offset), duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction, removeOnCompletion: false, force: true, completion: { [weak itemNode] _ in itemNode?.removeFromSupernode() }) } else { @@ -979,7 +980,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { if let previousFrame = previousItemFrames[WrappedGridItemNode(node: sectionNode)] { self.removeSectionNodeWithSection(wrappedSection, removeNode: false) let position = CGPoint(x: previousFrame.midX, y: previousFrame.midY) - sectionNode.layer.animatePosition(from: CGPoint(x: position.x, y: position.y + contentOffset.y), to: CGPoint(x: position.x, y: position.y + contentOffset.y - offset), duration: duration, timingFunction: timingFunction, removeOnCompletion: false, force: true, completion: { [weak sectionNode] _ in + sectionNode.layer.animatePosition(from: CGPoint(x: position.x, y: position.y + contentOffset.y), to: CGPoint(x: position.x, y: position.y + contentOffset.y - offset), duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction, removeOnCompletion: false, force: true, completion: { [weak sectionNode] _ in sectionNode?.removeFromSupernode() }) } else { @@ -1006,6 +1007,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { } } else if let previousItemFrames = previousItemFrames, case let .animated(duration, curve) = itemTransition { let timingFunction = curve.timingFunction + let mediaTimingFunction = curve.mediaTimingFunction let contentOffset = self.scrollView.contentOffset for index in self.itemNodes.keys { @@ -1021,7 +1023,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { self.removeItemNodeWithIndex(index, removeNode: true) } } else if let previousFrame = previousItemFrames[WrappedGridItemNode(node: itemNode)] { - itemNode.layer.animatePosition(from: CGPoint(x: previousFrame.midX, y: previousFrame.midY + contentOffset.y), to: itemNode.layer.position, duration: duration, timingFunction: timingFunction) + itemNode.layer.animatePosition(from: CGPoint(x: previousFrame.midX, y: previousFrame.midY + contentOffset.y), to: itemNode.layer.position, duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction) } else { itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.12, timingFunction: kCAMediaTimingFunctionEaseIn) itemNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5) @@ -1051,7 +1053,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { self.removeSectionNodeWithSection(wrappedSection, removeNode: true) } } else if let previousFrame = previousItemFrames[WrappedGridItemNode(node: sectionNode)] { - sectionNode.layer.animatePosition(from: CGPoint(x: previousFrame.midX, y: previousFrame.midY + contentOffset.y), to: sectionNode.layer.position, duration: duration, timingFunction: timingFunction) + sectionNode.layer.animatePosition(from: CGPoint(x: previousFrame.midX, y: previousFrame.midY + contentOffset.y), to: sectionNode.layer.position, duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction) } else { sectionNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseIn) } diff --git a/submodules/Display/Display/ListView.swift b/submodules/Display/Display/ListView.swift index b1b42d9011..a7772d76cb 100644 --- a/submodules/Display/Display/ListView.swift +++ b/submodules/Display/Display/ListView.swift @@ -2789,7 +2789,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture reverseAnimation = reverseBasicAnimation } else { let basicAnimation = CABasicAnimation(keyPath: "sublayerTransform") - basicAnimation.timingFunction = CAMediaTimingFunction(controlPoints: 0.33, 0.52, 0.25, 0.99) + basicAnimation.timingFunction = ContainedViewLayoutTransitionCurve.slide.mediaTimingFunction basicAnimation.duration = (duration ?? 0.3) * UIView.animationDurationFactor() basicAnimation.fromValue = NSValue(caTransform3D: CATransform3DMakeTranslation(0.0, -offset, 0.0)) basicAnimation.toValue = NSValue(caTransform3D: CATransform3DIdentity) @@ -2797,7 +2797,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture basicAnimation.isAdditive = true let reverseBasicAnimation = CABasicAnimation(keyPath: "sublayerTransform") - reverseBasicAnimation.timingFunction = CAMediaTimingFunction(controlPoints: 0.33, 0.52, 0.25, 0.99) + reverseBasicAnimation.timingFunction = ContainedViewLayoutTransitionCurve.slide.mediaTimingFunction reverseBasicAnimation.duration = (duration ?? 0.3) * UIView.animationDurationFactor() reverseBasicAnimation.fromValue = NSValue(caTransform3D: CATransform3DMakeTranslation(0.0, offset, 0.0)) reverseBasicAnimation.toValue = NSValue(caTransform3D: CATransform3DIdentity) @@ -2966,7 +2966,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture headerNode.layer.animateBoundsOriginYAdditive(from: offset, to: 0.0, duration: duration, mediaTimingFunction: CAMediaTimingFunction(controlPoints: p1, p2, p3, p4)) case .easeInOut: if transition.1 { - headerNode.layer.animateBoundsOriginYAdditive(from: offset, to: 0.0, duration: duration, mediaTimingFunction: CAMediaTimingFunction(controlPoints: 0.33, 0.52, 0.25, 0.99)) + headerNode.layer.animateBoundsOriginYAdditive(from: offset, to: 0.0, duration: duration, mediaTimingFunction: ContainedViewLayoutTransitionCurve.slide.mediaTimingFunction) } else { headerNode.layer.animateBoundsOriginYAdditive(from: offset, to: 0.0, duration: duration, mediaTimingFunction: CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)) } diff --git a/submodules/TelegramUI/TelegramUI/NavigationBarSearchContentNode.swift b/submodules/TelegramUI/TelegramUI/NavigationBarSearchContentNode.swift index a1ff327a25..3f09c011ba 100644 --- a/submodules/TelegramUI/TelegramUI/NavigationBarSearchContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/NavigationBarSearchContentNode.swift @@ -78,8 +78,7 @@ class NavigationBarSearchContentNode: NavigationBarContentNode { if abs(newProgress - self.expansionProgress) > 0.0001 && (progress <= 1.0 || self.expansionProgress != 1.0) { self.expansionProgress = newProgress - let animationCurve: ContainedViewLayoutTransitionCurve = .custom(0.33, 0.52, 0.25, 0.99) - let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: animationCurve) : .immediate + let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: ContainedViewLayoutTransitionCurve.slide) : .immediate if let validLayout = self.validLayout, animated { self.updatePlaceholder(self.expansionProgress, size: validLayout.0, leftInset: validLayout.1, rightInset: validLayout.2, transition: transition) } @@ -130,7 +129,7 @@ class NavigationBarSearchContentNode: NavigationBarContentNode { let overscrollProgress = max(0.0, max(0.0, self.expansionProgress - 1.0 + fraction) / fraction - visibleProgress) let searchBarNodeLayout = self.placeholderNode.asyncLayout() - let (searchBarHeight, searchBarApply) = searchBarNodeLayout(NSAttributedString(string: self.placeholder, font: searchBarFont, textColor: self.theme?.rootController.activeNavigationSearchBar.inputPlaceholderTextColor ?? UIColor(rgb: 0x8e8e93)), CGSize(width: baseWidth, height: fieldHeight), visibleProgress, self.theme?.rootController.activeNavigationSearchBar.inputPlaceholderTextColor ?? UIColor(rgb: 0x8e8e93), self.theme?.rootController.activeNavigationSearchBar.inputFillColor ?? .clear, self.theme?.rootController.navigationBar.backgroundColor ?? .clear, transition) + let (searchBarHeight, searchBarApply) = searchBarNodeLayout(NSAttributedString(string: self.placeholder, font: searchBarFont, textColor: self.theme?.rootController.navigationSearchBar.inputPlaceholderTextColor ?? UIColor(rgb: 0x8e8e93)), CGSize(width: baseWidth, height: fieldHeight), visibleProgress, self.theme?.rootController.navigationSearchBar.inputPlaceholderTextColor ?? UIColor(rgb: 0x8e8e93), self.theme?.rootController.navigationSearchBar.inputFillColor ?? .clear, self.theme?.rootController.navigationBar.backgroundColor ?? .clear, transition) searchBarApply() let searchBarFrame = CGRect(origin: CGPoint(x: padding + leftInset, y: 8.0 + overscrollProgress * fieldHeight), size: CGSize(width: baseWidth, height: fieldHeight)) diff --git a/submodules/TelegramUI/TelegramUI/ThemeGridController.swift b/submodules/TelegramUI/TelegramUI/ThemeGridController.swift index 8214e2b8d9..b87f917baa 100644 --- a/submodules/TelegramUI/TelegramUI/ThemeGridController.swift +++ b/submodules/TelegramUI/TelegramUI/ThemeGridController.swift @@ -32,6 +32,10 @@ final class ThemeGridController: ViewController { private var validLayout: ContainerViewLayout? + override var navigationBarRequiresEntireLayoutUpdate: Bool { + return false + } + init(context: AccountContext) { self.context = context self.presentationData = context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/TelegramUI/TelegramUI/ThemeGridControllerNode.swift b/submodules/TelegramUI/TelegramUI/ThemeGridControllerNode.swift index 6eb1d77049..d2b758b5bb 100644 --- a/submodules/TelegramUI/TelegramUI/ThemeGridControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ThemeGridControllerNode.swift @@ -718,7 +718,10 @@ final class ThemeGridControllerNode: ASDisplayNode { let targetProgress: CGFloat let duration: Double = 0.3 - let transition: ContainedViewLayoutTransition = .animated(duration: duration, curve: .easeInOut) + let curve = ContainedViewLayoutTransitionCurve.slide + let transition: ContainedViewLayoutTransition = .animated(duration: duration, curve: curve) + let timingFunction = curve.timingFunction + let mediaTimingFunction = curve.mediaTimingFunction if searchNode.expansionProgress < 0.6 { scrollToItem = GridNodeScrollToItem(index: 0, position: .top(navigationBarSearchContentHeight), transition: transition, directionHint: .up, adjustForSection: true, adjustForTopInset: true) @@ -735,11 +738,11 @@ final class ThemeGridControllerNode: ASDisplayNode { let offset = (self.gridNode.scrollView.contentOffset.y + self.gridNode.scrollView.contentInset.top) - previousOffset - self.backgroundNode.layer.animatePosition(from: self.backgroundNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.backgroundNode.layer.position, duration: duration) - self.separatorNode.layer.animatePosition(from: self.separatorNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.separatorNode.layer.position, duration: duration) - self.colorItemNode.layer.animatePosition(from: self.colorItemNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.colorItemNode.layer.position, duration: duration) - self.galleryItemNode.layer.animatePosition(from: self.galleryItemNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.galleryItemNode.layer.position, duration: duration) - self.descriptionItemNode.layer.animatePosition(from: self.descriptionItemNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.descriptionItemNode.layer.position, duration: duration) + self.backgroundNode.layer.animatePosition(from: self.backgroundNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.backgroundNode.layer.position, duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction) + self.separatorNode.layer.animatePosition(from: self.separatorNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.separatorNode.layer.position, duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction) + self.colorItemNode.layer.animatePosition(from: self.colorItemNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.colorItemNode.layer.position, duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction) + self.galleryItemNode.layer.animatePosition(from: self.galleryItemNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.galleryItemNode.layer.position, duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction) + self.descriptionItemNode.layer.animatePosition(from: self.descriptionItemNode.layer.position.offsetBy(dx: 0.0, dy: offset), to: self.descriptionItemNode.layer.position, duration: duration, timingFunction: timingFunction, mediaTimingFunction: mediaTimingFunction) return true }