diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 2849fe73ad..9ccbc00ca3 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -746,7 +746,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if strongSelf.navigationItem.leftBarButtonItem?.accessibilityLabel != leftBarButtonItem.accessibilityLabel { strongSelf.navigationItem.setLeftBarButton(leftBarButtonItem, animated: true) } - } else if strongSelf.chatListDisplayNode.inlineStackContainerNode != nil { + } else if strongSelf.chatListDisplayNode.inlineStackContainerTransitionFraction != 0.0 { } else { let editItem: UIBarButtonItem if stateAndFilterId.state.editing { @@ -1280,7 +1280,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController editItem = self.moreBarButtonItem } } - if self.chatListDisplayNode.inlineStackContainerNode != nil { + if self.chatListDisplayNode.inlineStackContainerTransitionFraction != 0.0 { self.backNavigationItem?.title = self.presentationData.strings.Common_Back } else if case .chatList(.root) = self.location { self.navigationItem.leftBarButtonItem = editItem @@ -2483,6 +2483,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + self.navigationBar?.secondaryContentNodeDisplayFraction = 1.0 - self.chatListDisplayNode.inlineStackContainerTransitionFraction + + if let inlineStackContainerNode = self.chatListDisplayNode.inlineStackContainerNode { + let _ = inlineStackContainerNode + } else { + } + super.containerLayoutUpdated(layout, transition: transition) let wasInVoiceOver = self.validLayout?.inVoiceOver ?? false @@ -2503,9 +2510,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController tabContainerOffset += layout.statusBarHeight ?? 0.0 tabContainerOffset += 44.0 + 20.0 } + tabContainerOffset += self.chatListDisplayNode.inlineStackContainerTransitionFraction * NavigationBar.defaultSecondaryContentHeight let navigationBarHeight = self.navigationBar?.frame.maxY ?? 0.0 + transition.updateAlpha(node: self.tabContainerNode, alpha: 1.0 - self.chatListDisplayNode.inlineStackContainerTransitionFraction) + transition.updateFrame(node: self.tabContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight - self.additionalNavigationBarHeight - 46.0 + tabContainerOffset), size: CGSize(width: layout.size.width, height: 46.0))) self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing, canReorderAllChats: self.isPremium, filtersLimit: self.tabContainerData?.2, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring)) diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index dd77507bd0..3df33b9ec7 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -309,7 +309,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { private var shimmerNodeOffset: CGFloat = 0.0 let listNode: ChatListNode - private var validLayout: (CGSize, UIEdgeInsets, CGFloat, ChatListControllerLocation?)? + private var validLayout: (CGSize, UIEdgeInsets, CGFloat, CGFloat, ChatListControllerLocation?, CGFloat)? init(context: AccountContext, location: ChatListControllerLocation, filter: ChatListFilter?, previewing: Bool, isInlineMode: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, becameEmpty: @escaping (ChatListFilter?) -> Void, emptyAction: @escaping (ChatListFilter?) -> Void, secondaryEmptyAction: @escaping () -> Void) { self.context = context @@ -375,7 +375,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { }) strongSelf.emptyNode = emptyNode strongSelf.addSubnode(emptyNode) - if let (size, insets, _, _) = strongSelf.validLayout { + if let (size, insets, _, _, _, _) = strongSelf.validLayout { let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom)) emptyNode.frame = emptyNodeFrame emptyNode.updateLayout(size: emptyNodeFrame.size, transition: .immediate) @@ -401,7 +401,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { let emptyShimmerEffectNode = ChatListShimmerNode() strongSelf.emptyShimmerEffectNode = emptyShimmerEffectNode strongSelf.insertSubnode(emptyShimmerEffectNode, belowSubnode: strongSelf.listNode) - if let (size, insets, _, _) = strongSelf.validLayout, let offset = strongSelf.floatingHeaderOffset { + if let (size, insets, _, _, _, _) = strongSelf.validLayout, let offset = strongSelf.floatingHeaderOffset { strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset + strongSelf.shimmerNodeOffset, transition: .immediate) } } @@ -421,7 +421,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { return } strongSelf.floatingHeaderOffset = offset - if let (size, insets, _, _) = strongSelf.validLayout, let emptyShimmerEffectNode = strongSelf.emptyShimmerEffectNode { + if let (size, insets, _, _, _, _) = strongSelf.validLayout, let emptyShimmerEffectNode = strongSelf.emptyShimmerEffectNode { strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset + strongSelf.shimmerNodeOffset, transition: transition) } } @@ -444,14 +444,14 @@ private final class ChatListContainerItemNode: ASDisplayNode { self.emptyNode?.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings) } - func updateLayout(size: CGSize, insets: UIEdgeInsets, visualNavigationHeight: CGFloat, inlineNavigationLocation: ChatListControllerLocation?, transition: ContainedViewLayoutTransition) { - self.validLayout = (size, insets, visualNavigationHeight, inlineNavigationLocation) + func updateLayout(size: CGSize, insets: UIEdgeInsets, visualNavigationHeight: CGFloat, originalNavigationHeight: CGFloat, inlineNavigationLocation: ChatListControllerLocation?, inlineNavigationTransitionFraction: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (size, insets, visualNavigationHeight, originalNavigationHeight, inlineNavigationLocation, inlineNavigationTransitionFraction) let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: size, insets: insets, duration: duration, curve: curve) transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size)) - self.listNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, visibleTopInset: visualNavigationHeight, inlineNavigationLocation: inlineNavigationLocation) + self.listNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, visibleTopInset: visualNavigationHeight, originalTopInset: originalNavigationHeight, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction) if let emptyNode = self.emptyNode { let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom)) @@ -487,7 +487,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { private(set) var transitionFraction: CGFloat = 0.0 private var transitionFractionOffset: CGFloat = 0.0 private var disableItemNodeOperationsWhileAnimating: Bool = false - private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, insets: UIEdgeInsets, isReorderingFilters: Bool, isEditing: Bool, inlineNavigationLocation: ChatListControllerLocation?)? + private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, originalNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, insets: UIEdgeInsets, isReorderingFilters: Bool, isEditing: Bool, inlineNavigationLocation: ChatListControllerLocation?, inlineNavigationTransitionFraction: CGFloat)? private var enableAdjacentFilterLoading: Bool = false @@ -744,7 +744,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { self.onFilterSwitch?() self.transitionFractionOffset = 0.0 - if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) = self.validLayout, let itemNode = self.itemNodes[self.selectedId] { + if let (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) = self.validLayout, let itemNode = self.itemNodes[self.selectedId] { for (id, itemNode) in self.itemNodes { if id != selectedId { itemNode.emptyNode?.restartAnimation() @@ -757,13 +757,13 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { for (_, itemNode) in self.itemNodes { itemNode.layer.removeAllAnimations() } - self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, transition: .immediate) + self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: .immediate) self.currentItemFilterUpdated?(self.currentItemFilter, self.transitionFraction, .immediate, true) } } } case .changed: - if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) = self.validLayout, let selectedIndex = self.availableFilters.firstIndex(where: { $0.id == self.selectedId }) { + if let (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) = self.validLayout, let selectedIndex = self.availableFilters.firstIndex(where: { $0.id == self.selectedId }) { let translation = recognizer.translation(in: self.view) var transitionFraction = translation.x / layout.size.width @@ -800,11 +800,11 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { } } } - self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, transition: .immediate) + self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: .immediate) self.currentItemFilterUpdated?(self.currentItemFilter, self.transitionFraction, .immediate, false) } case .cancelled, .ended: - if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) = self.validLayout, let selectedIndex = self.availableFilters.firstIndex(where: { $0.id == self.selectedId }) { + if let (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) = self.validLayout, let selectedIndex = self.availableFilters.firstIndex(where: { $0.id == self.selectedId }) { let translation = recognizer.translation(in: self.view) let velocity = recognizer.velocity(in: self.view) var directionIsToRight: Bool? @@ -843,12 +843,12 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { self.transitionFraction = 0.0 let transition: ContainedViewLayoutTransition = .animated(duration: 0.45, curve: .spring) self.disableItemNodeOperationsWhileAnimating = true - self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, transition: transition) + self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: transition) self.currentItemFilterUpdated?(self.currentItemFilter, self.transitionFraction, transition, false) DispatchQueue.main.async { self.disableItemNodeOperationsWhileAnimating = false - if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) = self.validLayout { - self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, transition: .immediate) + if let (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) = self.validLayout { + self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: .immediate) } } } @@ -864,7 +864,13 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { func updatePresentationData(_ presentationData: PresentationData) { self.presentationData = presentationData - self.backgroundColor = self.presentationData.theme.chatList.backgroundColor + if let validLayout = self.validLayout { + if let _ = validLayout.inlineNavigationLocation { + self.backgroundColor = self.presentationData.theme.chatList.backgroundColor.mixedWith(self.presentationData.theme.chatList.pinnedItemBackgroundColor, alpha: validLayout.inlineNavigationTransitionFraction) + } else { + self.backgroundColor = self.presentationData.theme.chatList.backgroundColor + } + } self.leftSeparatorLayer.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor.cgColor @@ -922,8 +928,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { } strongSelf.availableFilters = availableFilters strongSelf.filtersLimit = limit - if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) = strongSelf.validLayout { - strongSelf.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, transition: .immediate) + if let (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) = strongSelf.validLayout { + strongSelf.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: .immediate) } } if !availableFilters.contains(where: { $0.id == self.selectedId }) { @@ -940,8 +946,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { if value != self.enableAdjacentFilterLoading { self.enableAdjacentFilterLoading = value - if self.enableAdjacentFilterLoading, let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) = self.validLayout { - self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, transition: .immediate) + if self.enableAdjacentFilterLoading, let (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) = self.validLayout { + self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: .immediate) } } } @@ -950,7 +956,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { self.onFilterSwitch?() if id != self.selectedId, let index = self.availableFilters.firstIndex(where: { $0.id == id }) { if let itemNode = self.itemNodes[id] { - guard let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) = self.validLayout else { + guard let (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) = self.validLayout else { return } self.selectedId = id @@ -959,7 +965,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { } self.applyItemNodeAsCurrent(id: id, itemNode: itemNode) let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring) - self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, transition: transition) + self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: transition) self.currentItemFilterUpdated?(self.currentItemFilter, self.transitionFraction, transition, false) itemNode.emptyNode?.restartAnimation() completion?() @@ -989,7 +995,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { strongSelf.pendingItemNode = nil - guard let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) = strongSelf.validLayout else { + guard let (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) = strongSelf.validLayout else { strongSelf.itemNodes[id] = itemNode strongSelf.addSubnode(itemNode) @@ -1038,7 +1044,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { transition.animatePositionAdditive(node: itemNode, offset: CGPoint(x: -offset, y: 0.0)) - itemNode.updateLayout(size: layout.size, insets: insets, visualNavigationHeight: visualNavigationHeight, inlineNavigationLocation: inlineNavigationLocation, transition: .immediate) + itemNode.updateLayout(size: layout.size, insets: insets, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: .immediate) strongSelf.selectedId = id if let currentItemNode = strongSelf.currentItemNodeValue { @@ -1046,7 +1052,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { } strongSelf.applyItemNodeAsCurrent(id: id, itemNode: itemNode) - strongSelf.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, transition: .immediate) + strongSelf.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: .immediate) strongSelf.currentItemFilterUpdated?(strongSelf.currentItemFilter, strongSelf.transitionFraction, transition, false) } @@ -1057,14 +1063,20 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { } } - func update(layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, insets: UIEdgeInsets, isReorderingFilters: Bool, isEditing: Bool, inlineNavigationLocation: ChatListControllerLocation?, transition: ContainedViewLayoutTransition) { - self.validLayout = (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation) + func update(layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, originalNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, insets: UIEdgeInsets, isReorderingFilters: Bool, isEditing: Bool, inlineNavigationLocation: ChatListControllerLocation?, inlineNavigationTransitionFraction: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction) self._validLayoutReady.set(.single(true)) transition.updateAlpha(node: self, alpha: isReorderingFilters ? 0.5 : 1.0) self.isUserInteractionEnabled = !isReorderingFilters + if let _ = inlineNavigationLocation { + transition.updateBackgroundColor(node: self, color: self.presentationData.theme.chatList.backgroundColor.mixedWith(self.presentationData.theme.chatList.pinnedItemBackgroundColor, alpha: inlineNavigationTransitionFraction)) + } else { + transition.updateBackgroundColor(node: self, color: self.presentationData.theme.chatList.backgroundColor) + } + self.panRecognizer?.isEnabled = !isEditing transition.updateFrame(layer: self.leftSeparatorLayer, frame: CGRect(origin: CGPoint(x: -UIScreenPixel, y: 0.0), size: CGSize(width: UIScreenPixel, height: layout.size.height))) @@ -1113,7 +1125,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { nodeTransition.updateFrame(node: itemNode, frame: itemFrame, completion: { _ in }) - itemNode.updateLayout(size: layout.size, insets: insets, visualNavigationHeight: visualNavigationHeight, inlineNavigationLocation: inlineNavigationLocation, transition: nodeTransition) + itemNode.updateLayout(size: layout.size, insets: insets, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, transition: nodeTransition) if wasAdded, case .animated = transition { animateSlidingIds.append(id) @@ -1138,7 +1150,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { } } -final class ChatListControllerNode: ASDisplayNode { +final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { private let context: AccountContext private let location: ChatListControllerLocation private var presentationData: PresentationData @@ -1146,7 +1158,11 @@ final class ChatListControllerNode: ASDisplayNode { private let animationRenderer: MultiAnimationRenderer let containerNode: ChatListContainerNode + + private(set) var inlineStackContainerTransitionFraction: CGFloat = 0.0 private(set) var inlineStackContainerNode: ChatListContainerNode? + private var inlineContentPanRecognizer: InteractiveTransitionGestureRecognizer? + private var tapRecognizer: UITapGestureRecognizer? var navigationBar: NavigationBar? weak var controller: ChatListControllerImpl? @@ -1247,6 +1263,19 @@ final class ChatListControllerNode: ASDisplayNode { strongSelf.controller?.dismissAllUndoControllers() } } + + let inlineContentPanRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.inlineContentPanGesture(_:)), allowedDirections: { [weak self] _ in + guard let strongSelf = self, strongSelf.inlineStackContainerNode != nil else { + return [] + } + let directions: InteractiveTransitionGestureRecognizerDirections = [.leftCenter, .rightCenter] + return directions + }, edgeWidth: .widthMultiplier(factor: 1.0 / 6.0, min: 22.0, max: 80.0)) + inlineContentPanRecognizer.delegate = self + inlineContentPanRecognizer.delaysTouchesBegan = false + inlineContentPanRecognizer.cancelsTouchesInView = true + self.inlineContentPanRecognizer = inlineContentPanRecognizer + self.view.addGestureRecognizer(inlineContentPanRecognizer) } override func didLoad() { @@ -1264,6 +1293,69 @@ final class ChatListControllerNode: ASDisplayNode { } } + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + return false + } + + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool { + if let _ = otherGestureRecognizer as? InteractiveTransitionGestureRecognizer { + return false + } + if let _ = otherGestureRecognizer as? UIPanGestureRecognizer { + return true + } + return false + } + + @objc private func inlineContentPanGesture(_ recognizer: UIPanGestureRecognizer) { + switch recognizer.state { + case .began: + break + case .changed: + if let inlineStackContainerNode = self.inlineStackContainerNode { + let translation = recognizer.translation(in: self.view) + var transitionFraction = translation.x / inlineStackContainerNode.bounds.width + transitionFraction = 1.0 - max(0.0, min(1.0, transitionFraction)) + self.inlineStackContainerTransitionFraction = transitionFraction + self.controller?.requestLayout(transition: .immediate) + } + case .cancelled, .ended: + if let inlineStackContainerNode = self.inlineStackContainerNode { + let translation = recognizer.translation(in: self.view) + let velocity = recognizer.velocity(in: self.view) + var directionIsToRight: Bool? + if abs(velocity.x) > 10.0 { + if translation.x > 0.0 { + if velocity.x <= 0.0 { + directionIsToRight = nil + } else { + directionIsToRight = true + } + } else { + if velocity.x >= 0.0 { + directionIsToRight = nil + } else { + directionIsToRight = false + } + } + } else { + if abs(translation.x) > inlineStackContainerNode.bounds.width / 2.0 { + directionIsToRight = translation.x > inlineStackContainerNode.bounds.width / 2.0 + } + } + + if let directionIsToRight = directionIsToRight, directionIsToRight { + self.setInlineChatList(location: nil) + } else { + self.inlineStackContainerTransitionFraction = 1.0 + self.controller?.requestLayout(transition: .animated(duration: 0.4, curve: .spring)) + } + } + default: + break + } + } + func updatePresentationData(_ presentationData: PresentationData) { self.presentationData = presentationData @@ -1342,12 +1434,12 @@ final class ChatListControllerNode: ASDisplayNode { var mainNavigationBarHeight = navigationBarHeight var cleanMainNavigationBarHeight = cleanNavigationBarHeight var mainInsets = insets - if self.inlineStackContainerNode != nil { + if self.inlineStackContainerNode != nil && "".isEmpty { mainNavigationBarHeight = visualNavigationHeight cleanMainNavigationBarHeight = visualNavigationHeight mainInsets.top = visualNavigationHeight } - self.containerNode.update(layout: layout, navigationBarHeight: mainNavigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanMainNavigationBarHeight, insets: mainInsets, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, inlineNavigationLocation: self.inlineStackContainerNode?.location, transition: transition) + self.containerNode.update(layout: layout, navigationBarHeight: mainNavigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: navigationBarHeight, cleanNavigationBarHeight: cleanMainNavigationBarHeight, insets: mainInsets, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, inlineNavigationLocation: self.inlineStackContainerNode?.location, inlineNavigationTransitionFraction: self.inlineStackContainerTransitionFraction, transition: transition) if let inlineStackContainerNode = self.inlineStackContainerNode { var inlineStackContainerNodeTransition = transition @@ -1359,7 +1451,9 @@ final class ChatListControllerNode: ASDisplayNode { } let inlineSideInset: CGFloat = layout.safeInsets.left + 72.0 - inlineStackContainerNodeTransition.updateFrame(node: inlineStackContainerNode, frame: CGRect(origin: CGPoint(x: inlineSideInset, y: 0.0), size: layout.size)) + var inlineStackFrame = CGRect(origin: CGPoint(x: inlineSideInset, y: 0.0), size: CGSize(width: layout.size.width - inlineSideInset, height: layout.size.height)) + inlineStackFrame.origin.x += (1.0 - self.inlineStackContainerTransitionFraction) * inlineStackFrame.width + inlineStackContainerNodeTransition.updateFrame(node: inlineStackContainerNode, frame: inlineStackFrame) var inlineLayout = layout inlineLayout.size.width -= inlineSideInset inlineLayout.safeInsets.left = 0.0 @@ -1369,7 +1463,7 @@ final class ChatListControllerNode: ASDisplayNode { var inlineInsets = insets inlineInsets.left = 0.0 - inlineStackContainerNode.update(layout: inlineLayout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: inlineInsets, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, inlineNavigationLocation: nil, transition: inlineStackContainerNodeTransition) + inlineStackContainerNode.update(layout: inlineLayout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: navigationBarHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: inlineInsets, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, inlineNavigationLocation: nil, inlineNavigationTransitionFraction: 0.0, transition: inlineStackContainerNodeTransition) if animateIn { transition.animatePosition(node: inlineStackContainerNode, from: CGPoint(x: inlineStackContainerNode.position.x + inlineStackContainerNode.bounds.width + UIScreenPixel, y: inlineStackContainerNode.position.y)) @@ -1561,8 +1655,9 @@ final class ChatListControllerNode: ASDisplayNode { let previousInlineStackContainerNode = self.inlineStackContainerNode self.inlineStackContainerNode = inlineStackContainerNode + self.inlineStackContainerTransitionFraction = 1.0 - if let containerLayout = self.containerLayout { + if let _ = self.containerLayout { let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring) if let previousInlineStackContainerNode { @@ -1571,7 +1666,7 @@ final class ChatListControllerNode: ASDisplayNode { }) } - self.containerLayoutUpdated(containerLayout.layout, navigationBarHeight: containerLayout.navigationBarHeight, visualNavigationHeight: containerLayout.visualNavigationHeight, cleanNavigationBarHeight: containerLayout.cleanNavigationBarHeight, transition: transition) + self.controller?.requestLayout(transition: transition) } else { previousInlineStackContainerNode?.removeFromSupernode() } @@ -1579,16 +1674,18 @@ final class ChatListControllerNode: ASDisplayNode { } else { if let inlineStackContainerNode = self.inlineStackContainerNode { self.inlineStackContainerNode = nil + self.inlineStackContainerTransitionFraction = 0.0 self.containerNode.contentScrollingEnded = self.contentScrollingEnded - if let containerLayout = self.containerLayout { + if let _ = self.containerLayout { let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring) - self.containerLayoutUpdated(containerLayout.layout, navigationBarHeight: containerLayout.navigationBarHeight, visualNavigationHeight: containerLayout.visualNavigationHeight, cleanNavigationBarHeight: containerLayout.cleanNavigationBarHeight, transition: transition) transition.updatePosition(node: inlineStackContainerNode, position: CGPoint(x: inlineStackContainerNode.position.x + inlineStackContainerNode.bounds.width + UIScreenPixel, y: inlineStackContainerNode.position.y), completion: { [weak inlineStackContainerNode] _ in inlineStackContainerNode?.removeFromSupernode() }) + + self.controller?.requestLayout(transition: transition) } else { inlineStackContainerNode.removeFromSupernode() } diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index bf2f42a507..55ab0e5eb0 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -2349,26 +2349,28 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { strongSelf.contextContainer.position = contextContainerFrame.center transition.updateBounds(node: strongSelf.contextContainer, bounds: contextContainerFrame.offsetBy(dx: -strongSelf.revealOffset, dy: 0.0)) - if item.interaction.inlineNavigationLocation != nil { - let mainContentFrame = CGRect(origin: CGPoint(x: params.leftInset + 72.0, y: 0.0), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height)) - transition.updatePosition(node: strongSelf.mainContentContainerNode, position: mainContentFrame.center) + var mainContentFrame: CGRect + var mainContentBoundsOffset: CGFloat + var mainContentAlpha: CGFloat = 1.0 + + if case .chatList = item.chatListLocation { + mainContentFrame = CGRect(origin: CGPoint(x: params.leftInset + 72.0, y: 0.0), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height)) + mainContentBoundsOffset = mainContentFrame.origin.x - transition.updateBounds(node: strongSelf.mainContentContainerNode, bounds: CGRect(origin: CGPoint(x: mainContentFrame.size.width, y: 0.0), size: mainContentFrame.size)) - transition.updateAlpha(node: strongSelf.mainContentContainerNode, alpha: 0.0) - } else if case .chatList = item.chatListLocation { - let mainContentFrame = CGRect(origin: CGPoint(x: params.leftInset + 72.0, y: 0.0), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height)) - transition.updatePosition(node: strongSelf.mainContentContainerNode, position: mainContentFrame.center) - - transition.updateBounds(node: strongSelf.mainContentContainerNode, bounds: CGRect(origin: CGPoint(x: mainContentFrame.origin.x, y: 0.0), size: mainContentFrame.size)) - transition.updateAlpha(node: strongSelf.mainContentContainerNode, alpha: 1.0) + if let inlineNavigationLocation = item.interaction.inlineNavigationLocation { + mainContentAlpha = 1.0 - inlineNavigationLocation.progress + mainContentBoundsOffset += (mainContentFrame.width - mainContentFrame.minX) * inlineNavigationLocation.progress + } } else { - let mainContentFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height)) - transition.updatePosition(node: strongSelf.mainContentContainerNode, position: mainContentFrame.center) - - transition.updateBounds(node: strongSelf.mainContentContainerNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: mainContentFrame.size)) - transition.updateAlpha(node: strongSelf.mainContentContainerNode, alpha: 1.0) + mainContentFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height)) + mainContentBoundsOffset = 0.0 } + transition.updatePosition(node: strongSelf.mainContentContainerNode, position: mainContentFrame.center) + + transition.updateBounds(node: strongSelf.mainContentContainerNode, bounds: CGRect(origin: CGPoint(x: mainContentBoundsOffset, y: 0.0), size: mainContentFrame.size)) + transition.updateAlpha(node: strongSelf.mainContentContainerNode, alpha: mainContentAlpha) + var crossfadeContent = false if let selectableControlSizeAndApply = selectableControlSizeAndApply { let selectableControlSize = CGSize(width: selectableControlSizeAndApply.0, height: layout.contentSize.height) @@ -2441,9 +2443,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let avatarFrame = CGRect(origin: CGPoint(x: leftInset - avatarLeftInset + editingOffset + 10.0 + revealOffset, y: floor((itemHeight - avatarDiameter) / 2.0)), size: CGSize(width: avatarDiameter, height: avatarDiameter)) var avatarScaleOffset: CGFloat = 0.0 var avatarScale: CGFloat = 1.0 - if item.interaction.inlineNavigationLocation != nil { - avatarScale = 54.0 / avatarFrame.width - avatarScaleOffset = -(avatarFrame.width - avatarFrame.width * avatarScale) * 0.5 + if let inlineNavigationLocation = item.interaction.inlineNavigationLocation { + let targetAvatarScale: CGFloat = 54.0 / avatarFrame.width + avatarScale = targetAvatarScale * inlineNavigationLocation.progress + 1.0 * (1.0 - inlineNavigationLocation.progress) + + let targetAvatarScaleOffset: CGFloat = -(avatarFrame.width - avatarFrame.width * avatarScale) * 0.5 + avatarScaleOffset = targetAvatarScaleOffset * inlineNavigationLocation.progress } transition.updatePosition(node: strongSelf.avatarNode, position: avatarFrame.center.offsetBy(dx: avatarScaleOffset, dy: 0.0)) transition.updateBounds(node: strongSelf.avatarNode, bounds: CGRect(origin: CGPoint(), size: avatarFrame.size)) @@ -2470,7 +2475,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } inlineNavigationMarkLayer.backgroundColor = item.presentationData.theme.list.itemAccentColor.cgColor let markHeight: CGFloat = 50.0 - let markFrame = CGRect(origin: CGPoint(x: -4.0, y: avatarFrame.midY - markHeight * 0.5), size: CGSize(width: 8.0, height: markHeight)) + var markFrame = CGRect(origin: CGPoint(x: -4.0, y: avatarFrame.midY - markHeight * 0.5), size: CGSize(width: 8.0, height: markHeight)) + markFrame.origin.x -= (1.0 - inlineNavigationLocation.progress) * markFrame.width * 0.5 if animateIn { inlineNavigationMarkLayer.frame = markFrame transition.animatePositionAdditive(layer: inlineNavigationMarkLayer, offset: CGPoint(x: -markFrame.width * 0.5, y: 0.0)) @@ -2979,15 +2985,16 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } transition.updateFrame(node: strongSelf.separatorNode, frame: CGRect(origin: CGPoint(x: separatorInset, y: layoutOffset + itemHeight - separatorHeight), size: CGSize(width: params.width - separatorInset, height: separatorHeight))) - transition.updateAlpha(node: strongSelf.separatorNode, alpha: item.interaction.inlineNavigationLocation != nil ? 0.0 : 1.0) + if let inlineNavigationLocation = item.interaction.inlineNavigationLocation { + transition.updateAlpha(node: strongSelf.separatorNode, alpha: 1.0 - inlineNavigationLocation.progress) + } else { + transition.updateAlpha(node: strongSelf.separatorNode, alpha: 1.0) + } transition.updateFrame(node: strongSelf.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.contentSize.width, height: itemHeight))) let backgroundColor: UIColor let highlightedBackgroundColor: UIColor - if item.interaction.inlineNavigationLocation != nil { - backgroundColor = theme.pinnedItemBackgroundColor - highlightedBackgroundColor = theme.itemHighlightedBackgroundColor - } else if item.selected { + if item.selected { backgroundColor = theme.itemSelectedBackgroundColor highlightedBackgroundColor = theme.itemHighlightedBackgroundColor } else if isPinned { @@ -3002,11 +3009,19 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { backgroundColor = theme.itemBackgroundColor highlightedBackgroundColor = theme.itemHighlightedBackgroundColor } + if animated { transition.updateBackgroundColor(node: strongSelf.backgroundNode, color: backgroundColor) } else { strongSelf.backgroundNode.backgroundColor = backgroundColor } + + if let inlineNavigationLocation = item.interaction.inlineNavigationLocation { + transition.updateAlpha(node: strongSelf.backgroundNode, alpha: 1.0 - inlineNavigationLocation.progress) + } else { + transition.updateAlpha(node: strongSelf.backgroundNode, alpha: 1.0) + } + strongSelf.highlightedBackgroundNode.backgroundColor = highlightedBackgroundColor let topNegativeInset: CGFloat = 0.0 strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: layoutOffset - separatorHeight - topNegativeInset), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height + separatorHeight + topNegativeInset)) diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 5b361a601d..9907331c0e 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -889,6 +889,7 @@ public final class ChatListNode: ListView { public var reachedSelectionLimit: ((Int32) -> Void)? private var visibleTopInset: CGFloat? + private var originalTopInset: CGFloat? public init(context: AccountContext, location: ChatListControllerLocation, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, disableAnimations: Bool, isInlineMode: Bool) { self.context = context @@ -1965,7 +1966,7 @@ public final class ChatListNode: ListView { } }) - self.visibleContentOffsetChanged = { [weak self] offset in + self.visibleContentOffsetChanged = { [weak self] offset, transition in guard let strongSelf = self else { return } @@ -2375,27 +2376,54 @@ public final class ChatListNode: ListView { self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: scrollToItem, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })*/ } - public func updateLayout(transition: ContainedViewLayoutTransition, updateSizeAndInsets: ListViewUpdateSizeAndInsets, visibleTopInset: CGFloat, inlineNavigationLocation: ChatListControllerLocation?) { - self.visibleTopInset = visibleTopInset - - self.visualInsets = UIEdgeInsets(top: visibleTopInset, left: 0.0, bottom: 0.0, right: 0.0) + public func updateLayout(transition: ContainedViewLayoutTransition, updateSizeAndInsets: ListViewUpdateSizeAndInsets, visibleTopInset: CGFloat, originalTopInset: CGFloat, inlineNavigationLocation: ChatListControllerLocation?, inlineNavigationTransitionFraction: CGFloat) { var highlightedLocation: ChatListHighlightedLocation? if case let .forum(peerId) = inlineNavigationLocation { - highlightedLocation = ChatListHighlightedLocation(location: .peer(id: peerId), progress: 1.0) + highlightedLocation = ChatListHighlightedLocation(location: .peer(id: peerId), progress: inlineNavigationTransitionFraction) } + var navigationLocationPresenceUpdated = false + if (self.interaction?.inlineNavigationLocation == nil) != (highlightedLocation == nil) { + navigationLocationPresenceUpdated = true + } + var navigationLocationUpdated = false if self.interaction?.inlineNavigationLocation != highlightedLocation { self.interaction?.inlineNavigationLocation = highlightedLocation navigationLocationUpdated = true } + let insetDelta: CGFloat = 0.0 + if navigationLocationPresenceUpdated { + let targetTopInset: CGFloat + if highlightedLocation != nil { + targetTopInset = self.visibleTopInset ?? self.insets.top + } else { + targetTopInset = self.originalTopInset ?? self.insets.top + } + let immediateInsetDelta = self.insets.top - targetTopInset + + self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, additionalScrollDistance: immediateInsetDelta, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: self.visibleSize, insets: UIEdgeInsets(top: targetTopInset, left: self.insets.left, bottom: self.insets.bottom, right: self.insets.right), duration: 0.0, curve: .Default(duration: 0.0)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + } + + self.visualInsets = UIEdgeInsets(top: visibleTopInset, left: 0.0, bottom: 0.0, right: 0.0) + + self.visibleTopInset = visibleTopInset + self.originalTopInset = originalTopInset + + var additionalScrollDistance: CGFloat = 0.0 + var options: ListViewDeleteAndInsertOptions = [.Synchronous, .LowLatency] if navigationLocationUpdated { options.insert(.ForceUpdate) - options.insert(.AnimateInsertion) + + if transition.isAnimated { + options.insert(.AnimateInsertion) + } + + additionalScrollDistance += insetDelta } - self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: options, scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: options, scrollToItem: nil, additionalScrollDistance: additionalScrollDistance, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) if !self.dequeuedInitialTransitionOnLayout { self.dequeuedInitialTransitionOnLayout = true diff --git a/submodules/Display/Source/ListView.swift b/submodules/Display/Source/ListView.swift index 591ea3c2ba..db7c427d8d 100644 --- a/submodules/Display/Source/ListView.swift +++ b/submodules/Display/Source/ListView.swift @@ -2914,11 +2914,11 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture } else if self.snapToBottomInsetUntilFirstInteraction { offsetFix = -updateSizeAndInsets.insets.bottom + self.insets.bottom } else { - if let visualInsets = self.visualInsets, animated, (visualInsets.top == updateSizeAndInsets.insets.top || visualInsets.top == self.insets.top) { + /*if let visualInsets = self.visualInsets, animated, (visualInsets.top == updateSizeAndInsets.insets.top || visualInsets.top == self.insets.top) { offsetFix = 0.0 - } else { + } else {*/ offsetFix = updateSizeAndInsets.insets.top - self.insets.top - } + //} } offsetFix += additionalScrollDistance diff --git a/submodules/Display/Source/NavigationBar.swift b/submodules/Display/Source/NavigationBar.swift index 7462c6a7ab..6931a979a5 100644 --- a/submodules/Display/Source/NavigationBar.swift +++ b/submodules/Display/Source/NavigationBar.swift @@ -489,6 +489,7 @@ open class NavigationBar: ASDisplayNode { public private(set) var contentNode: NavigationBarContentNode? public private(set) var secondaryContentNode: ASDisplayNode? + public var secondaryContentNodeDisplayFraction: CGFloat = 1.0 private var itemTitleListenerKey: Int? private var itemTitleViewListenerKey: Int? @@ -1200,7 +1201,7 @@ open class NavigationBar: ASDisplayNode { self.backgroundNode.update(size: backgroundFrame.size, transition: transition) } - let apparentAdditionalHeight: CGFloat = self.secondaryContentNode != nil ? NavigationBar.defaultSecondaryContentHeight : 0.0 + let apparentAdditionalHeight: CGFloat = self.secondaryContentNode != nil ? (NavigationBar.defaultSecondaryContentHeight * self.secondaryContentNodeDisplayFraction) : 0.0 let leftButtonInset: CGFloat = leftInset + 16.0 let backButtonInset: CGFloat = leftInset + 27.0 @@ -1218,11 +1219,11 @@ open class NavigationBar: ASDisplayNode { case .expansion: expansionHeight = contentNode.height - let additionalExpansionHeight: CGFloat = self.secondaryContentNode != nil && appearsHidden ? NavigationBar.defaultSecondaryContentHeight : 0.0 + let additionalExpansionHeight: CGFloat = self.secondaryContentNode != nil && appearsHidden ? (NavigationBar.defaultSecondaryContentHeight * self.secondaryContentNodeDisplayFraction) : 0.0 contentNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height - (appearsHidden ? 0.0 : additionalContentHeight) - expansionHeight - apparentAdditionalHeight - additionalExpansionHeight), size: CGSize(width: size.width, height: expansionHeight)) if appearsHidden { if self.secondaryContentNode != nil { - contentNodeFrame.origin.y += NavigationBar.defaultSecondaryContentHeight + contentNodeFrame.origin.y += NavigationBar.defaultSecondaryContentHeight * self.secondaryContentNodeDisplayFraction } } } @@ -1545,7 +1546,7 @@ open class NavigationBar: ASDisplayNode { } if let _ = self.secondaryContentNode { - result += NavigationBar.defaultSecondaryContentHeight + result += NavigationBar.defaultSecondaryContentHeight * self.secondaryContentNodeDisplayFraction } return result diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift b/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift index e38ac68f4d..50adb454d9 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift @@ -279,7 +279,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode { combinedInsets.right += layout.safeInsets.right let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: layout.size, insets: combinedInsets, headerInsets: headerInsets, duration: duration, curve: curve) - chatsNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, visibleTopInset: updateSizeAndInsets.insets.top, inlineNavigationLocation: nil) + chatsNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, visibleTopInset: updateSizeAndInsets.insets.top, originalTopInset: updateSizeAndInsets.insets.top, inlineNavigationLocation: nil, inlineNavigationTransitionFraction: 0.0) } self.contentNode.node.frame = CGRect(origin: CGPoint(), size: layout.size) diff --git a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift index 958645739a..ad695a6d86 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift @@ -576,7 +576,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, headerInsets: headerInsets, duration: duration, curve: curve) - self.chatListNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, visibleTopInset: updateSizeAndInsets.insets.top, inlineNavigationLocation: nil) + self.chatListNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, visibleTopInset: updateSizeAndInsets.insets.top, originalTopInset: updateSizeAndInsets.insets.top, inlineNavigationLocation: nil, inlineNavigationTransitionFraction: 0.0) if let contactListNode = self.contactListNode { contactListNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)