diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index 4b0bfb3d22..138dae348f 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -948,7 +948,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele let offset = itemNode.listNode.visibleContentOffset() self.contentOffset = offset - self.contentOffsetChanged?(offset) + self.contentOffsetChanged?(offset, self.currentItemNode) self.isSettingUpContentOffset = false return @@ -966,7 +966,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele } self.contentOffset = offset - self.contentOffsetChanged?(offset) + self.contentOffsetChanged?(offset, self.currentItemNode) if !self.isInlineMode, self.currentItemNode.startedScrollingAtUpperBound && self.tempTopInset != 0.0 { if case let .known(value) = offset { @@ -983,15 +983,20 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele } } itemNode.listNode.didBeginInteractiveDragging = { [weak self] _ in - guard let self, !self.isInlineMode else { - return - } - guard let validLayout = self.validLayout else { + guard let self else { return } self.didBeginInteractiveDragging?() + if self.isInlineMode { + return + } + + guard let validLayout = self.validLayout else { + return + } + let tempTopInset: CGFloat if validLayout.inlineNavigationLocation != nil { tempTopInset = 0.0 @@ -1108,7 +1113,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele var groupSelected: ((EngineChatList.Group) -> Void)? var updatePeerGrouping: ((EnginePeer.Id, Bool) -> Void)? var contentOffset: ListViewVisibleContentOffset? - public var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)? + public var contentOffsetChanged: ((ListViewVisibleContentOffset, ListView) -> Void)? public var contentScrollingEnded: ((ListView) -> Bool)? var didBeginInteractiveDragging: (() -> Void)? var endedInteractiveDragging: ((ListView) -> Void)? @@ -1756,6 +1761,8 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { private var tempNavigationScrollingTransition: ContainedViewLayoutTransition? private var allowOverscrollStoryExpansion: Bool = false + private var allowOverscrollItemExpansion: Bool = false + private var currentOverscrollItemExpansionTimestamp: Double? private var containerLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, storiesInset: CGFloat)? @@ -1807,8 +1814,8 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { self.addSubnode(self.mainContainerNode) - self.mainContainerNode.contentOffsetChanged = { [weak self] offset in - self?.contentOffsetChanged(offset: offset, isPrimary: true) + self.mainContainerNode.contentOffsetChanged = { [weak self] offset, listView in + self?.contentOffsetChanged(offset: offset, listView: listView, isPrimary: true) } self.mainContainerNode.contentScrollingEnded = { [weak self] listView in return self?.contentScrollingEnded(listView: listView, isPrimary: true) ?? false @@ -2141,15 +2148,6 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { mainDelta = 0.0 } transition.updateSublayerTransformOffset(layer: self.mainContainerNode.layer, offset: CGPoint(x: 0.0, y: -mainDelta)) - - if self.inlineStackContainerNode == nil && self.allowOverscrollStoryExpansion { - if let controller = self.controller, let componentView = controller.chatListHeaderView(), let storyPeerListView = componentView.storyPeerListView(), let peerId = storyPeerListView.overscrollSelectedId { - self.allowOverscrollStoryExpansion = false - HapticFeedback().tap() - - controller.openStories(peerId: peerId) - } - } } func requestNavigationBarLayout(transition: Transition) { @@ -2408,11 +2406,70 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { } } - private func contentOffsetChanged(offset: ListViewVisibleContentOffset, isPrimary: Bool) { + private func contentOffsetChanged(offset: ListViewVisibleContentOffset, listView: ListView, isPrimary: Bool) { guard let containerLayout = self.containerLayout else { return } self.updateNavigationScrolling(navigationHeight: containerLayout.navigationBarHeight, transition: self.tempNavigationScrollingTransition ?? .immediate) + + if listView.isDragging { + var overscrollSelectedId: EnginePeer.Id? + var overscrollHiddenChatItemsAllowed = false + if let controller = self.controller, let componentView = controller.chatListHeaderView(), let storyPeerListView = componentView.storyPeerListView() { + overscrollSelectedId = storyPeerListView.overscrollSelectedId + overscrollHiddenChatItemsAllowed = storyPeerListView.overscrollHiddenChatItemsAllowed + } + + if let controller = self.controller { + if let peerId = overscrollSelectedId { + if self.allowOverscrollStoryExpansion && self.inlineStackContainerNode == nil && isPrimary { + self.allowOverscrollStoryExpansion = false + self.allowOverscrollItemExpansion = false + self.currentOverscrollItemExpansionTimestamp = nil + HapticFeedback().tap() + + controller.openStories(peerId: peerId) + } + } else { + if !overscrollHiddenChatItemsAllowed { + var manuallyAllow = false + + if isPrimary { + if let storySubscriptions = controller.orderedStorySubscriptions, shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions, isHidden: controller.location == .chatList(groupId: .archive)) { + } else { + manuallyAllow = true + } + } else { + manuallyAllow = true + } + + if manuallyAllow, case let .known(value) = offset, value + listView.tempTopInset <= -40.0 { + overscrollHiddenChatItemsAllowed = true + } + } + + if overscrollHiddenChatItemsAllowed { + if self.allowOverscrollItemExpansion { + let timestamp = CACurrentMediaTime() + if let _ = self.currentOverscrollItemExpansionTimestamp { + } else { + self.currentOverscrollItemExpansionTimestamp = timestamp + } + + if let currentOverscrollItemExpansionTimestamp = self.currentOverscrollItemExpansionTimestamp, currentOverscrollItemExpansionTimestamp <= timestamp - 0.2 { + self.allowOverscrollItemExpansion = false + + if isPrimary { + self.mainContainerNode.currentItemNode.revealScrollHiddenItem() + } else { + self.inlineStackContainerNode?.currentItemNode.revealScrollHiddenItem() + } + } + } + } + } + } + } } private func shouldStopScrolling(listView: ListView, velocity: CGFloat, isPrimary: Bool) -> Bool { @@ -2445,12 +2502,15 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { if isPrimary { self.allowOverscrollStoryExpansion = true } + self.allowOverscrollItemExpansion = true } private func endedInteractiveDragging(listView: ListView, isPrimary: Bool) { if isPrimary { self.allowOverscrollStoryExpansion = false } + self.allowOverscrollItemExpansion = false + self.currentOverscrollItemExpansionTimestamp = nil } private func contentScrollingEnded(listView: ListView, isPrimary: Bool) -> Bool { @@ -2518,10 +2578,10 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { inlineStackContainerNode.groupSelected = self.mainContainerNode.groupSelected inlineStackContainerNode.updatePeerGrouping = self.mainContainerNode.updatePeerGrouping - inlineStackContainerNode.contentOffsetChanged = { [weak self] offset in - self?.contentOffsetChanged(offset: offset, isPrimary: false) + inlineStackContainerNode.contentOffsetChanged = { [weak self] offset, listView in + self?.contentOffsetChanged(offset: offset, listView: listView, isPrimary: false) } - inlineStackContainerNode.endedInteractiveDragging = { [weak self] listView in + inlineStackContainerNode.didBeginInteractiveDragging = { [weak self] in self?.didBeginInteractiveDragging(isPrimary: false) } inlineStackContainerNode.endedInteractiveDragging = { [weak self] listView in diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 4976a70cd4..3c1f6f5f1c 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -2858,32 +2858,7 @@ public final class ChatListNode: ListView { strongSelf.scrolledAtTopValue = atTop strongSelf.contentOffsetChanged?(offset) if revealHiddenItems && !strongSelf.currentState.hiddenItemShouldBeTemporaryRevealed { - var isHiddenItemVisible = false - strongSelf.forEachItemNode({ itemNode in - if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item { - if case let .peer(peerData) = item.content, let threadInfo = peerData.threadInfo { - if threadInfo.isHidden { - isHiddenItemVisible = true - } - } - if case let .groupReference(groupReference) = item.content { - if groupReference.hiddenByDefault { - isHiddenItemVisible = true - } - } - } - }) - if isHiddenItemVisible { - if strongSelf.hapticFeedback == nil { - strongSelf.hapticFeedback = HapticFeedback() - } - strongSelf.hapticFeedback?.impact(.medium) - strongSelf.updateState { state in - var state = state - state.hiddenItemShouldBeTemporaryRevealed = true - return state - } - } + //strongSelf.revealScrollHiddenItem() } } @@ -2915,6 +2890,35 @@ public final class ChatListNode: ListView { } } + func revealScrollHiddenItem() { + var isHiddenItemVisible = false + self.forEachItemNode({ itemNode in + if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item { + if case let .peer(peerData) = item.content, let threadInfo = peerData.threadInfo { + if threadInfo.isHidden { + isHiddenItemVisible = true + } + } + if case let .groupReference(groupReference) = item.content { + if groupReference.hiddenByDefault { + isHiddenItemVisible = true + } + } + } + }) + if isHiddenItemVisible { + if self.hapticFeedback == nil { + self.hapticFeedback = HapticFeedback() + } + self.hapticFeedback?.impact(.medium) + self.updateState { state in + var state = state + state.hiddenItemShouldBeTemporaryRevealed = true + return state + } + } + } + private func pollFilterUpdates() { self.chatFolderUpdates.set(.single(nil)) diff --git a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryPeerListComponent.swift b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryPeerListComponent.swift index aed93de17f..b96174e387 100644 --- a/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryPeerListComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryPeerListComponent/Sources/StoryPeerListComponent.swift @@ -354,6 +354,7 @@ public final class StoryPeerListComponent: Component { private var currentActivityFraction: CGFloat = 0.0 public private(set) var overscrollSelectedId: EnginePeer.Id? + public private(set) var overscrollHiddenChatItemsAllowed: Bool = false private var sharedBlurEffect: NSObject? @@ -712,7 +713,7 @@ public final class StoryPeerListComponent: Component { var rawProgress = CGFloat((timestamp - animationState.startTime) / animationState.duration) rawProgress = max(0.0, min(1.0, rawProgress)) - if !animationState.fromIsUnlocked && animationState.bounce && itemLayout.itemCount > 3 { + if !animationState.fromIsUnlocked && animationState.bounce { let bounceStartFraction: CGFloat = 0.0 let bounceGlobalFraction: CGFloat = animationState.interpolatedFraction(at: timestamp, effectiveFromFraction: 0.0, toFraction: 1.0, linear: true) let bounceFraction: CGFloat = 1.0 - max(0.0, min(1.0, bounceGlobalFraction - bounceStartFraction)) / (1.0 - bounceStartFraction) @@ -788,8 +789,8 @@ public final class StoryPeerListComponent: Component { let expandedItemWidth: CGFloat = 60.0 let totalOverscrollFraction: CGFloat = max(0.0, collapsedState.maxFraction - 1.0) - let overscrollStage1 = min(0.7, totalOverscrollFraction) - let overscrollStage2 = max(0.0, totalOverscrollFraction - 0.7) + let overscrollStage1 = min(0.5, totalOverscrollFraction) + let overscrollStage2 = max(0.0, totalOverscrollFraction - 0.5) //let realTimeOverscrollFraction: CGFloat = max(0.0, (1.0 - component.collapseFraction) - 1.0) let realTimeOverscrollFraction = totalOverscrollFraction @@ -801,7 +802,14 @@ public final class StoryPeerListComponent: Component { break } } - if let overscrollFocusIndex, overscrollStage2 >= 0.6 { + + if overscrollStage1 >= 0.5 { + self.overscrollHiddenChatItemsAllowed = true + } else { + self.overscrollHiddenChatItemsAllowed = false + } + + if let overscrollFocusIndex, overscrollStage2 >= 0.5 { self.overscrollSelectedId = self.sortedItems[overscrollFocusIndex].peer.id } else { self.overscrollSelectedId = nil diff --git a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift index bf3d3bbc3d..db38446f01 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift @@ -262,7 +262,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { } } - self.mainContainerNode?.contentOffsetChanged = { [weak self] offset in + self.mainContainerNode?.contentOffsetChanged = { [weak self] offset, _ in guard let strongSelf = self else { return }