diff --git a/Display/CAAnimationUtils.swift b/Display/CAAnimationUtils.swift index 140dc121e6..1aa1688315 100644 --- a/Display/CAAnimationUtils.swift +++ b/Display/CAAnimationUtils.swift @@ -202,18 +202,18 @@ public extension CALayer { self.animate(from: NSNumber(value: Float(from)), to: NSNumber(value: Float(to)), keyPath: "opacity", timingFunction: timingFunction, duration: duration, delay: delay, removeOnCompletion: removeOnCompletion, completion: completion) } - public func animateScale(from: CGFloat, to: CGFloat, duration: Double, timingFunction: String = kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: Bool = true, completion: ((Bool) -> Void)? = nil) { - self.animate(from: NSNumber(value: Float(from)), to: NSNumber(value: Float(to)), keyPath: "transform.scale", timingFunction: timingFunction, duration: duration, removeOnCompletion: removeOnCompletion, completion: completion) + public func animateScale(from: CGFloat, to: CGFloat, duration: Double, delay: Double = 0.0, timingFunction: String = kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: Bool = true, completion: ((Bool) -> Void)? = nil) { + self.animate(from: NSNumber(value: Float(from)), to: NSNumber(value: Float(to)), keyPath: "transform.scale", timingFunction: timingFunction, duration: duration, delay: delay, removeOnCompletion: removeOnCompletion, completion: completion) } - func animatePosition(from: CGPoint, to: CGPoint, duration: Double, timingFunction: String = kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: Bool = true, additive: Bool = false, force: Bool = false, completion: ((Bool) -> Void)? = nil) { + func animatePosition(from: CGPoint, to: CGPoint, duration: Double, delay: Double = 0.0, timingFunction: String = kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: Bool = true, additive: Bool = false, force: Bool = false, completion: ((Bool) -> Void)? = nil) { if from == to && !force { if let completion = completion { completion(true) } return } - self.animate(from: NSValue(cgPoint: from), to: NSValue(cgPoint: to), keyPath: "position", timingFunction: timingFunction, duration: duration, removeOnCompletion: removeOnCompletion, additive: additive, completion: completion) + self.animate(from: NSValue(cgPoint: from), to: NSValue(cgPoint: to), keyPath: "position", timingFunction: timingFunction, duration: duration, delay: delay, removeOnCompletion: removeOnCompletion, additive: additive, completion: completion) } func animateBounds(from: CGRect, to: CGRect, duration: Double, timingFunction: String, removeOnCompletion: Bool = true, additive: Bool = false, force: Bool = false, completion: ((Bool) -> Void)? = nil) { diff --git a/Display/GridNode.swift b/Display/GridNode.swift index 290c0f9aa8..2dab6c4d8b 100644 --- a/Display/GridNode.swift +++ b/Display/GridNode.swift @@ -210,10 +210,13 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { public var visibleItemsUpdated: ((GridNodeVisibleItems) -> Void)? public var presentationLayoutUpdated: ((GridNodeCurrentPresentationLayout, ContainedViewLayoutTransition) -> Void)? + public var scrollingInitiated: (() -> Void)? public var scrollingCompleted: (() -> Void)? public final var floatingSections = false + public final var initialOffset: CGFloat = 0.0 + public var showVerticalScrollIndicator: Bool = false { didSet { self.scrollView.showsVerticalScrollIndicator = self.showVerticalScrollIndicator @@ -340,6 +343,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { self.updateItemNodeVisibilititesAndScrolling() + self.scrollingInitiated?() } public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { @@ -403,11 +407,6 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { var previousSection: GridSection? for item in self.items { var itemSize = defaultItemSize - if let height = item.fillsRowWithHeight { - nextItemOrigin.x = 0.0 - itemSize.width = gridLayout.size.width - itemSize.height = height - } let section = item.section var keepSection = true @@ -432,17 +431,21 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { } previousSection = section - if !incrementedCurrentRow { - incrementedCurrentRow = true - contentSize.height += itemSize.height + lineSpacing - } - - if index == 0 { + if let height = item.fillsRowWithHeight { + nextItemOrigin.x = 0.0 + itemSize.width = gridLayout.size.width + itemSize.height = height + } else if index == 0 { let itemsInRow = max(1, Int(effectiveWidth) / Int(itemSize.width)) let normalizedIndexOffset = self.firstIndexInSectionOffset % itemsInRow nextItemOrigin.x += (itemSize.width + itemSpacing) * CGFloat(normalizedIndexOffset) } + if !incrementedCurrentRow { + incrementedCurrentRow = true + contentSize.height += itemSize.height + lineSpacing + } + items.append(GridNodePresentationItem(index: index, frame: CGRect(origin: nextItemOrigin, size: itemSize))) index += 1 @@ -557,7 +560,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { if self.itemLayout.items.isEmpty { transitionDirectionHint = scrollToItem.directionHint transition = scrollToItem.transition - contentOffset = CGPoint(x: 0.0, y: -self.gridLayout.insets.top) + contentOffset = CGPoint(x: 0.0, y: -self.gridLayout.insets.top + self.initialOffset) } else { let itemFrame = self.itemLayout.items[scrollToItem.index] @@ -585,7 +588,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate { } if scrollToItem.adjustForTopInset { - additionalOffset += -gridLayout.insets.top + additionalOffset += -gridLayout.insets.top + self.initialOffset } } else if scrollToItem.adjustForTopInset { additionalOffset = -gridLayout.insets.top diff --git a/Display/ImmediateTextNode.swift b/Display/ImmediateTextNode.swift index 842eb7a01d..b6c2cdbc16 100644 --- a/Display/ImmediateTextNode.swift +++ b/Display/ImmediateTextNode.swift @@ -3,6 +3,7 @@ import Foundation public class ImmediateTextNode: TextNode { public var attributedText: NSAttributedString? public var textAlignment: NSTextAlignment = .natural + public var truncationType: CTLineTruncationType = .end public var maximumNumberOfLines: Int = 1 public var lineSpacing: CGFloat = 0.0 public var insets: UIEdgeInsets = UIEdgeInsets() @@ -24,7 +25,7 @@ public class ImmediateTextNode: TextNode { public func updateLayout(_ constrainedSize: CGSize) -> CGSize { let makeLayout = TextNode.asyncLayout(self) - let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: .end, constrainedSize: constrainedSize, alignment: self.textAlignment, lineSpacing: self.lineSpacing, cutout: nil, insets: self.insets)) + let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, lineSpacing: self.lineSpacing, cutout: nil, insets: self.insets)) let _ = apply() return layout.size } diff --git a/Display/NavigationBar.swift b/Display/NavigationBar.swift index 602098ce4d..905c1de1e5 100644 --- a/Display/NavigationBar.swift +++ b/Display/NavigationBar.swift @@ -271,6 +271,8 @@ open class NavigationBar: ASDisplayNode { } } + public var layoutSuspended: Bool = false + private let titleNode: ASTextNode var previousItemListenerKey: Int? @@ -701,6 +703,10 @@ open class NavigationBar: ASDisplayNode { } func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) { + if self.layoutSuspended { + return + } + self.validLayout = (size, leftInset, rightInset) let leftButtonInset: CGFloat = leftInset + 16.0 diff --git a/Display/TabBarController.swift b/Display/TabBarController.swift index 2117f752be..fec4d9e742 100644 --- a/Display/TabBarController.swift +++ b/Display/TabBarController.swift @@ -157,6 +157,7 @@ open class TabBarController: ViewController { self.addChildViewController(currentController) currentController.didMove(toParentViewController: self) + currentController.navigationBar?.layoutSuspended = true currentController.navigationItem.setTarget(self.navigationItem) displayNavigationBar = currentController.displayNavigationBar currentController.displayNode.recursivelyEnsureDisplaySynchronously(true) diff --git a/Display/UINavigationItem+Proxy.h b/Display/UINavigationItem+Proxy.h index 5d607cfb47..8a891d8a2f 100644 --- a/Display/UINavigationItem+Proxy.h +++ b/Display/UINavigationItem+Proxy.h @@ -10,6 +10,7 @@ typedef void (^UITabBarItemSetBadgeListener)(NSString * _Nullable); @interface UINavigationItem (Proxy) - (void)setTargetItem:(UINavigationItem * _Nullable)targetItem; +- (BOOL)hasTargetItem; - (void)setTitle:(NSString * _Nullable)title animated:(bool)animated; diff --git a/Display/UINavigationItem+Proxy.m b/Display/UINavigationItem+Proxy.m index 2682e8adfb..f52fcfa669 100644 --- a/Display/UINavigationItem+Proxy.m +++ b/Display/UINavigationItem+Proxy.m @@ -175,6 +175,10 @@ static const void *badgeKey = &badgeKey; } } +- (BOOL)hasTargetItem { + return [self associatedObjectForKey:targetItemKey] != nil; +} + - (NSInteger)addSetTitleListener:(UINavigationItemSetTitleListener)listener { NSBag *bag = [self associatedObjectForKey:setTitleListenerBagKey]; diff --git a/Display/WindowContent.swift b/Display/WindowContent.swift index 1803920f76..8f79c5605d 100644 --- a/Display/WindowContent.swift +++ b/Display/WindowContent.swift @@ -293,16 +293,6 @@ private final class KeyboardGestureRecognizerDelegate: NSObject, UIGestureRecogn } } -public final class StatusBarVolumeColors { - public let background: UIColor - public let foreground: UIColor - - public init(background: UIColor, foreground: UIColor) { - self.background = background - self.foreground = foreground - } -} - public class Window1 { public let hostView: WindowHostView @@ -331,7 +321,6 @@ public class Window1 { public var previewThemeAccentColor: UIColor = .blue public var previewThemeDarkBlur: Bool = false - public var statusBarVolumeColors: StatusBarVolumeColors = StatusBarVolumeColors(background: .lightGray, foreground: .black) public private(set) var forceInCallStatusBarText: String? = nil public var inCallNavigate: (() -> Void)? {