Update overscroll

This commit is contained in:
Ali 2023-07-16 00:06:12 +04:00
parent baf317921e
commit 80c5d0daf4
5 changed files with 98 additions and 9 deletions

View File

@ -2525,7 +2525,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
super.updateNavigationBarLayout(layout, transition: transition)
}
private func chatListHeaderView() -> ChatListHeaderComponent.View? {
func chatListHeaderView() -> ChatListHeaderComponent.View? {
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
if let componentView = navigationBarView.headerContent.view as? ChatListHeaderComponent.View {
return componentView
@ -3667,6 +3667,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
sourceCornerRadius: transitionView.bounds.height * 0.5,
sourceIsAvatar: true
)
Queue.mainQueue().after(0.3, { [weak self] in
guard let self else {
return
}
self.chatListDisplayNode.mainContainerNode.currentItemNode.scroller.panGestureRecognizer.state = .cancelled
})
}
}
}
@ -3680,6 +3688,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
if navigationBarView.storiesUnlocked {
self.scrollToStories()
if let componentView = self.chatListHeaderView() {
if let (transitionView, transitionContentView) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
return StoryContainerScreen.TransitionOut(

View File

@ -875,6 +875,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
previousItemNode.listNode.updatePeerGrouping = nil
previousItemNode.listNode.contentOffsetChanged = nil
previousItemNode.listNode.contentScrollingEnded = nil
previousItemNode.listNode.didBeginInteractiveDragging = nil
previousItemNode.listNode.endedInteractiveDragging = { _ in }
previousItemNode.listNode.shouldStopScrolling = nil
previousItemNode.listNode.activateChatPreview = nil
@ -988,6 +989,9 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
guard let validLayout = self.validLayout else {
return
}
self.didBeginInteractiveDragging?()
let tempTopInset: CGFloat
if validLayout.inlineNavigationLocation != nil {
tempTopInset = 0.0
@ -1106,6 +1110,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
var contentOffset: ListViewVisibleContentOffset?
public var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
public var contentScrollingEnded: ((ListView) -> Bool)?
var didBeginInteractiveDragging: (() -> Void)?
var endedInteractiveDragging: ((ListView) -> Void)?
var shouldStopScrolling: ((ListView, CGFloat) -> Bool)?
var activateChatPreview: ((ChatListItem, Int64?, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
@ -1750,6 +1755,8 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
private var tempDisableStoriesAnimations: Bool = false
private var tempNavigationScrollingTransition: ContainedViewLayoutTransition?
private var allowOverscrollStoryExpansion: Bool = false
private var containerLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, storiesInset: CGFloat)?
var contentScrollingEnded: ((ListView) -> Bool)?
@ -1806,6 +1813,9 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
self.mainContainerNode.contentScrollingEnded = { [weak self] listView in
return self?.contentScrollingEnded(listView: listView, isPrimary: true) ?? false
}
self.mainContainerNode.didBeginInteractiveDragging = { [weak self] in
self?.didBeginInteractiveDragging(isPrimary: true)
}
self.mainContainerNode.endedInteractiveDragging = { [weak self] listView in
self?.endedInteractiveDragging(listView: listView, isPrimary: true)
}
@ -2131,6 +2141,15 @@ 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) {
@ -2422,7 +2441,16 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
return false
}
private func didBeginInteractiveDragging(isPrimary: Bool) {
if isPrimary {
self.allowOverscrollStoryExpansion = true
}
}
private func endedInteractiveDragging(listView: ListView, isPrimary: Bool) {
if isPrimary {
self.allowOverscrollStoryExpansion = false
}
}
private func contentScrollingEnded(listView: ListView, isPrimary: Bool) -> Bool {
@ -2493,6 +2521,9 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
inlineStackContainerNode.contentOffsetChanged = { [weak self] offset in
self?.contentOffsetChanged(offset: offset, isPrimary: false)
}
inlineStackContainerNode.endedInteractiveDragging = { [weak self] listView in
self?.didBeginInteractiveDragging(isPrimary: false)
}
inlineStackContainerNode.endedInteractiveDragging = { [weak self] listView in
self?.endedInteractiveDragging(listView: listView, isPrimary: false)
}

View File

@ -1257,7 +1257,9 @@ private final class StoryContainerScreenComponent: Component {
if let current = self.visibleItemSetViews[slice.peer.id] {
itemSetView = current
} else {
itemSetTransition = .immediate
itemSetTransition = transition.withAnimation(.none).withUserData(StoryItemSetContainerComponent.TransitionHint(
allowSynchronousLoads: !self.visibleItemSetViews.isEmpty
))
itemSetView = ItemSetView()
self.visibleItemSetViews[slice.peer.id] = itemSetView
}

View File

@ -56,6 +56,14 @@ public final class StoryItemSetContainerComponent: Component {
}
}
public final class TransitionHint {
public let allowSynchronousLoads: Bool
public init(allowSynchronousLoads: Bool) {
self.allowSynchronousLoads = allowSynchronousLoads
}
}
public enum NavigationDirection {
case previous
case next
@ -960,6 +968,11 @@ public final class StoryItemSetContainerComponent: Component {
return
}
var hintAllowSynchronousLoads = true
if let hint = transition.userData(TransitionHint.self) {
hintAllowSynchronousLoads = hint.allowSynchronousLoads
}
var validIds: [Int32] = []
var trulyValidIds: [Int32] = []
@ -1080,7 +1093,7 @@ public final class StoryItemSetContainerComponent: Component {
)
let _ = visibleItem.view.update(
transition: itemTransition.withUserData(StoryItemContentComponent.Hint(
synchronousLoad: index == centralIndex && itemLayout.contentScaleFraction <= 0.0001
synchronousLoad: index == centralIndex && itemLayout.contentScaleFraction <= 0.0001 && hintAllowSynchronousLoads
)),
component: AnyComponent(StoryItemContentComponent(
context: component.context,

View File

@ -348,6 +348,8 @@ public final class StoryPeerListComponent: Component {
private var currentTitleWidth: CGFloat = 0.0
private var currentActivityFraction: CGFloat = 0.0
public private(set) var overscrollSelectedId: EnginePeer.Id?
private var sharedBlurEffect: NSObject?
public override init(frame: CGRect) {
@ -449,19 +451,26 @@ public final class StoryPeerListComponent: Component {
}
public func setLoadingItem(peerId: EnginePeer.Id, signal: Signal<Never, NoError>) {
self.loadingItemId = peerId
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: { [weak self] in
self?.state?.updated(transition: .immediate)
})
var applyLoadingItem = true
self.loadingItemDisposable?.dispose()
self.loadingItemDisposable = (signal |> deliverOnMainQueue).start(completed: { [weak self] in
guard let self else {
return
}
self.loadingItemId = nil
applyLoadingItem = false
self.state?.updated(transition: .immediate)
})
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: { [weak self] in
guard let self else {
return
}
if applyLoadingItem {
self.loadingItemId = peerId
self.state?.updated(transition: .immediate)
}
})
}
public func anchorForTooltip() -> (UIView, CGRect)? {
@ -773,6 +782,19 @@ public final class StoryPeerListComponent: Component {
let overscrollFraction: CGFloat = max(0.0, collapsedState.maxFraction - 1.0)
let realTimeOverscrollFraction: CGFloat = max(0.0, (1.0 - component.collapseFraction) - 1.0)
var overscrollFocusIndex: Int?
for i in 0 ..< self.sortedItems.count {
if self.sortedItems[i].peer.id != component.context.account.peerId {
overscrollFocusIndex = i
break
}
}
if let overscrollFocusIndex, overscrollFraction >= 0.7 {
self.overscrollSelectedId = self.sortedItems[overscrollFocusIndex].peer.id
} else {
self.overscrollSelectedId = nil
}
struct MeasuredItem {
var itemFrame: CGRect
var itemScale: CGFloat
@ -808,7 +830,13 @@ public final class StoryPeerListComponent: Component {
let minimizedMaxItemScale: CGFloat = (24.0 + 4.0) / 52.0
let maximizedItemScale: CGFloat = 1.0 + overscrollFraction * 0.1
let overscrollScaleFactor: CGFloat
if index == overscrollFocusIndex {
overscrollScaleFactor = 0.5
} else {
overscrollScaleFactor = 0.1
}
let maximizedItemScale: CGFloat = 1.0 + overscrollFraction * overscrollScaleFactor
let minItemScale: CGFloat = minimizedItemScale.interpolate(to: minimizedMaxItemScale, amount: collapsedState.minFraction) * (1.0 - collapsedState.activityFraction) + 0.1 * collapsedState.activityFraction
@ -824,6 +852,11 @@ public final class StoryPeerListComponent: Component {
}
adjustedRegularFrame.origin.x -= effectiveVisibleBounds.minX
if let overscrollFocusIndex {
let focusIndexOffset: CGFloat = max(-1.0, min(1.0, CGFloat(index - overscrollFocusIndex)))
adjustedRegularFrame.origin.x += focusIndexOffset * overscrollFraction * 0.3 * adjustedRegularFrame.width * 0.5
}
let collapsedItemPosition: CGPoint = collapsedItemFrame.center.interpolate(to: collapsedMaxItemFrame.center, amount: collapsedState.minFraction)
var itemPosition = collapsedItemPosition.interpolate(to: adjustedRegularFrame.center, amount: min(1.0, collapsedState.maxFraction))