feat: update list fetch trigger logic for UserTimeline scene
This commit is contained in:
parent
dd118023b9
commit
832b146c82
|
@ -377,6 +377,7 @@
|
|||
DB71FD5225F8CCAA00512AE1 /* APIService+Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */; };
|
||||
DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; };
|
||||
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; };
|
||||
DB7274F4273BB9B200577D95 /* ListBatchFetchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */; };
|
||||
DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73B48F261F030A002E9E9F /* SafariActivity.swift */; };
|
||||
DB73BF3B2711885500781945 /* UserDefaults+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF3A2711885500781945 /* UserDefaults+Notification.swift */; };
|
||||
DB73BF4127118B6D00781945 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF4027118B6D00781945 /* Instance.swift */; };
|
||||
|
@ -1195,6 +1196,7 @@
|
|||
DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Status.swift"; sourceTree = "<group>"; };
|
||||
DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = "<group>"; };
|
||||
DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = "<group>"; };
|
||||
DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListBatchFetchViewModel.swift; sourceTree = "<group>"; };
|
||||
DB73B48F261F030A002E9E9F /* SafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariActivity.swift; sourceTree = "<group>"; };
|
||||
DB73BF3A2711885500781945 /* UserDefaults+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Notification.swift"; sourceTree = "<group>"; };
|
||||
DB73BF4027118B6D00781945 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = "<group>"; };
|
||||
|
@ -2972,6 +2974,7 @@
|
|||
DB9D6C2225E502C60051B173 /* MosaicImageViewModel.swift */,
|
||||
2DA6055025F74407006356F9 /* AudioContainerViewModel.swift */,
|
||||
5DF1054625F8870E00D6C0D4 /* VideoPlayerViewModel.swift */,
|
||||
DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */,
|
||||
);
|
||||
path = ViewModel;
|
||||
sourceTree = "<group>";
|
||||
|
@ -4233,6 +4236,7 @@
|
|||
2D24E11D2626D8B100A59D4F /* NotificationStatusTableViewCell.swift in Sources */,
|
||||
DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */,
|
||||
DB1E346825F518E20079D7DF /* CategoryPickerSection.swift in Sources */,
|
||||
DB7274F4273BB9B200577D95 /* ListBatchFetchViewModel.swift in Sources */,
|
||||
2D61254D262547C200299647 /* APIService+Notification.swift in Sources */,
|
||||
DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */,
|
||||
DB73BF4B27140C0800781945 /* UITableViewDiffableDataSource.swift in Sources */,
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
<key>AppShared.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>42</integer>
|
||||
<integer>36</integer>
|
||||
</dict>
|
||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>43</integer>
|
||||
<integer>38</integer>
|
||||
</dict>
|
||||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -102,7 +102,7 @@
|
|||
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>45</integer>
|
||||
<integer>39</integer>
|
||||
</dict>
|
||||
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -122,7 +122,7 @@
|
|||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>44</integer>
|
||||
<integer>37</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
|
|
@ -72,6 +72,16 @@ extension UserTimelineViewController {
|
|||
statusTableViewCellDelegate: self
|
||||
)
|
||||
|
||||
// setup batch fetch
|
||||
viewModel.listBatchFetchViewModel.setup(scrollView: tableView)
|
||||
viewModel.listBatchFetchViewModel.shouldFetch
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.viewModel.stateMachine.enter(UserTimelineViewModel.State.Loading.self)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// trigger user timeline loading
|
||||
Publishers.CombineLatest(
|
||||
viewModel.domain.removeDuplicates().eraseToAnyPublisher(),
|
||||
|
@ -104,11 +114,11 @@ extension UserTimelineViewController {
|
|||
extension UserTimelineViewController: StatusTableViewControllerAspect { }
|
||||
|
||||
// MARK: - UIScrollViewDelegate
|
||||
extension UserTimelineViewController {
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
aspectScrollViewDidScroll(scrollView)
|
||||
}
|
||||
}
|
||||
//extension UserTimelineViewController {
|
||||
// func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
// aspectScrollViewDidScroll(scrollView)
|
||||
// }
|
||||
//}
|
||||
|
||||
// MARK: - TableViewCellHeightCacheableContainer
|
||||
extension UserTimelineViewController: TableViewCellHeightCacheableContainer {
|
||||
|
@ -186,13 +196,13 @@ extension UserTimelineViewController: ScrollViewContainer {
|
|||
}
|
||||
|
||||
// MARK: - LoadMoreConfigurableTableViewContainer
|
||||
extension UserTimelineViewController: LoadMoreConfigurableTableViewContainer {
|
||||
typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell
|
||||
typealias LoadingState = UserTimelineViewModel.State.Loading
|
||||
|
||||
var loadMoreConfigurableTableView: UITableView { return tableView }
|
||||
var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.stateMachine }
|
||||
}
|
||||
//extension UserTimelineViewController: LoadMoreConfigurableTableViewContainer {
|
||||
// typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell
|
||||
// typealias LoadingState = UserTimelineViewModel.State.Loading
|
||||
//
|
||||
// var loadMoreConfigurableTableView: UITable``````View { return tableView }
|
||||
// var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.stateMachine }
|
||||
//}
|
||||
|
||||
extension UserTimelineViewController {
|
||||
override var keyCommands: [UIKeyCommand]? {
|
||||
|
|
|
@ -23,6 +23,7 @@ final class UserTimelineViewModel {
|
|||
let userID: CurrentValueSubject<String?, Never>
|
||||
let queryFilter: CurrentValueSubject<QueryFilter, Never>
|
||||
let statusFetchedResultsController: StatusFetchedResultsController
|
||||
let listBatchFetchViewModel = ListBatchFetchViewModel()
|
||||
var cellFrameCache = NSCache<NSNumber, NSValue>()
|
||||
|
||||
let isBlocking = CurrentValueSubject<Bool, Never>(false)
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// ListBatchFetchViewModel.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by Cirno MainasuK on 2021-11-10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
// ref: Texture.ASBatchFetchingDelegate
|
||||
final class ListBatchFetchViewModel {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
// timer running on `common` mode
|
||||
let timerPublisher = Timer.publish(every: 1.0, on: .main, in: .common)
|
||||
.autoconnect()
|
||||
.share()
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
// input
|
||||
private(set) weak var scrollView: UIScrollView?
|
||||
let hasMore = CurrentValueSubject<Bool, Never>(true)
|
||||
|
||||
// output
|
||||
let shouldFetch = PassthroughSubject<Void, Never>()
|
||||
|
||||
init() {
|
||||
Publishers.CombineLatest(
|
||||
hasMore,
|
||||
timerPublisher
|
||||
)
|
||||
.sink { [weak self] hasMore, _ in
|
||||
guard let self = self else { return }
|
||||
guard hasMore else { return }
|
||||
guard let scrollView = self.scrollView else { return }
|
||||
|
||||
// skip trigger if user interacting
|
||||
if scrollView.isDragging || scrollView.isTracking { return }
|
||||
|
||||
// send fetch request
|
||||
if scrollView.contentSize.height < scrollView.frame.height {
|
||||
self.shouldFetch.send()
|
||||
} else {
|
||||
let frame = scrollView.frame
|
||||
let contentOffset = scrollView.contentOffset
|
||||
let contentSize = scrollView.contentSize
|
||||
|
||||
let visibleBottomY = contentOffset.y + frame.height
|
||||
let offset = 2 * frame.height
|
||||
let fetchThrottleOffsetY = contentSize.height - offset
|
||||
|
||||
if visibleBottomY > fetchThrottleOffsetY {
|
||||
self.shouldFetch.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ListBatchFetchViewModel {
|
||||
func setup(scrollView: UIScrollView) {
|
||||
self.scrollView = scrollView
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue