diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 8b75de62..57979578 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -74,6 +74,7 @@ 2D82BA0525E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D82BA0425E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift */; }; 2D8434F525FF465D00EECE90 /* HomeTimelineNavigationBarState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D8434F425FF465D00EECE90 /* HomeTimelineNavigationBarState.swift */; }; 2D8434FB25FF46B300EECE90 /* HomeTimelineNavigationBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D8434FA25FF46B300EECE90 /* HomeTimelineNavigationBarView.swift */; }; + 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D84350425FF858100EECE90 /* UIScrollView.swift */; }; 2D927F0225C7E4F2004F19B8 /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0125C7E4F2004F19B8 /* Mention.swift */; }; 2D927F0825C7E9A8004F19B8 /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0725C7E9A8004F19B8 /* Tag.swift */; }; 2D927F0E25C7E9C9004F19B8 /* History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0D25C7E9C9004F19B8 /* History.swift */; }; @@ -322,6 +323,7 @@ 2D82BA0425E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonResendEmailViewModelNavigationDelegateShim.swift; sourceTree = ""; }; 2D8434F425FF465D00EECE90 /* HomeTimelineNavigationBarState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineNavigationBarState.swift; sourceTree = ""; }; 2D8434FA25FF46B300EECE90 /* HomeTimelineNavigationBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineNavigationBarView.swift; sourceTree = ""; }; + 2D84350425FF858100EECE90 /* UIScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = ""; }; 2D927F0125C7E4F2004F19B8 /* Mention.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mention.swift; sourceTree = ""; }; 2D927F0725C7E9A8004F19B8 /* Tag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = ""; }; 2D927F0D25C7E9C9004F19B8 /* History.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = History.swift; sourceTree = ""; }; @@ -1145,6 +1147,7 @@ 2D206B9125F60EA700143C56 /* UIControl.swift */, 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */, DB47229625F9EFAD00DA7F53 /* NSManagedObjectContext.swift */, + 2D84350425FF858100EECE90 /* UIScrollView.swift */, ); path = Extension; sourceTree = ""; @@ -1646,6 +1649,7 @@ 2D82B9FF25E7863200E36F0F /* OnboardingViewControllerAppearance.swift in Sources */, 5DF1054725F8870E00D6C0D4 /* VideoPlayerViewModel.swift in Sources */, 2D38F1E525CD46C100561493 /* HomeTimelineViewModel.swift in Sources */, + 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */, 2D76316B25C14D4C00929FB9 /* PublicTimelineViewModel.swift in Sources */, 2DA6055125F74407006356F9 /* AudioContainerViewModel.swift in Sources */, 0FB3D2FE25E4CB6400AAD544 /* PickServerTitleCell.swift in Sources */, diff --git a/Mastodon/Extension/UIScrollView.swift b/Mastodon/Extension/UIScrollView.swift new file mode 100644 index 00000000..8999d255 --- /dev/null +++ b/Mastodon/Extension/UIScrollView.swift @@ -0,0 +1,32 @@ +// +// UIScrollView.swift +// Mastodon +// +// Created by sxiaojian on 2021/3/15. +// + +import UIKit + +extension UIScrollView { + public enum ScrollDirection { + case top + case bottom + case left + case right + } + + public func scroll(to direction: ScrollDirection, animated: Bool) { + let offset: CGPoint + switch direction { + case .top: + offset = CGPoint(x: contentOffset.x, y: -adjustedContentInset.top) + case .bottom: + offset = CGPoint(x: contentOffset.x, y: max(-adjustedContentInset.top, contentSize.height - frame.height + adjustedContentInset.bottom)) + case .left: + offset = CGPoint(x: -adjustedContentInset.left, y: contentOffset.y) + case .right: + offset = CGPoint(x: max(-adjustedContentInset.left, contentSize.width - frame.width + adjustedContentInset.right), y: contentOffset.y) + } + setContentOffset(offset, animated: animated) + } +} diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineNavigationBarState.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineNavigationBarState.swift index 41be16f8..7dc4223a 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineNavigationBarState.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineNavigationBarState.swift @@ -17,8 +17,8 @@ final class HomeTimelineNavigationBarState { var titleViewBeforePublishing: UIView? // used for restore titleView after published - var newTopContent = CurrentValueSubject(false) - var newBottomContent = CurrentValueSubject(false) + var newTopContent = CurrentValueSubject(false) + var newBottomContent = CurrentValueSubject(false) var hasContentBeforeFetching: Bool = true weak var viewController: HomeTimelineViewController? @@ -26,6 +26,7 @@ final class HomeTimelineNavigationBarState { init() { reCountdown() subscribeNewContent() + addGesture() } } @@ -56,15 +57,54 @@ extension HomeTimelineNavigationBarState { } } +extension HomeTimelineNavigationBarState { + func handleScrollViewDidScroll(_ scrollView: UIScrollView) { + let contentOffsetY = scrollView.contentOffset.y + print(contentOffsetY) + let isTop = contentOffsetY < -scrollView.contentInset.top + if isTop { + newTopContent.value = false + showMastodonLogoInNavigationBar() + } + let isBottom = contentOffsetY > max(-scrollView.adjustedContentInset.top, scrollView.contentSize.height - scrollView.frame.height + scrollView.adjustedContentInset.bottom) + if isBottom { + newBottomContent.value = false + showMastodonLogoInNavigationBar() + } + } + + func addGesture() { + let tapGesture = UITapGestureRecognizer.singleTapGestureRecognizer + tapGesture.addTarget(self, action: #selector(newPostsNewDidPressed)) + HomeTimelineNavigationBarView.newPostsView.addGestureRecognizer(tapGesture) + } + + @objc func newPostsNewDidPressed() { + if newTopContent.value == true { + scrollToDirection(direction: .top) + } + if newBottomContent.value == true { + scrollToDirection(direction: .bottom) + } + } + + func scrollToDirection(direction: UIScrollView.ScrollDirection) { + viewController?.tableView.scroll(to: direction, animated: true) + } +} + extension HomeTimelineNavigationBarState { func subscribeNewContent() { newTopContent .receive(on: DispatchQueue.main) .sink { [weak self] newContent in guard let self = self else { return } - if self.hasContentBeforeFetching && newContent { + if self.hasContentBeforeFetching, newContent { self.showNewPostsInNavigationBar() } + if newContent { + self.newBottomContent.value = false + } } .store(in: &disposeBag) newBottomContent @@ -74,10 +114,13 @@ extension HomeTimelineNavigationBarState { if newContent { self.showNewPostsInNavigationBar() } + if (newContent) { + self.newTopContent.value = false + } } .store(in: &disposeBag) - } + func reCountdown() { errorCountDownDispose = networkErrorCountSubject .scan(0) { value, _ in value + 1 } @@ -89,21 +132,6 @@ extension HomeTimelineNavigationBarState { }) } - func handleScrollViewDidScroll(_ scrollView: UIScrollView) { - let contentOffsetY = scrollView.contentOffset.y - print(contentOffsetY) - let isTop = contentOffsetY < -scrollView.contentInset.top - if isTop { - newTopContent.value = false - showMastodonLogoInNavigationBar() - } - let isBottom = contentOffsetY > max(-scrollView.contentInset.top, scrollView.contentSize.height - scrollView.frame.height + scrollView.contentInset.bottom) - if isBottom { - newBottomContent.value = false - showMastodonLogoInNavigationBar() - } - } - func receiveCompletion(completion: Subscribers.Completion) { switch completion { case .failure: