Scroll position maintenance when loading up

This commit is contained in:
Justin Mazzocchi 2020-10-05 23:40:06 -07:00
parent d80988e6e3
commit c00adc2767
No known key found for this signature in database
GPG Key ID: E223E6937AAFB01C
1 changed files with 31 additions and 9 deletions

View File

@ -15,6 +15,7 @@ final public class CollectionItemsViewModel: ObservableObject {
private var viewModelCache = [CollectionItem: (CollectionItemViewModel, AnyCancellable)]() private var viewModelCache = [CollectionItem: (CollectionItemViewModel, AnyCancellable)]()
private let navigationEventsSubject = PassthroughSubject<NavigationEvent, Never>() private let navigationEventsSubject = PassthroughSubject<NavigationEvent, Never>()
private let loadingSubject = PassthroughSubject<Bool, Never>() private let loadingSubject = PassthroughSubject<Bool, Never>()
private var lastSelectedLoadMore: LoadMore?
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
init(collectionService: CollectionService) { init(collectionService: CollectionService) {
@ -68,7 +69,8 @@ extension CollectionItemsViewModel: CollectionViewModel {
collectionService: collectionService collectionService: collectionService
.navigationService .navigationService
.contextService(id: status.displayStatus.id)))) .contextService(id: status.displayStatus.id))))
case .loadMore: case let .loadMore(loadMore):
lastSelectedLoadMore = loadMore
(viewModel(indexPath: indexPath) as? LoadMoreViewModel)?.loadMore() (viewModel(indexPath: indexPath) as? LoadMoreViewModel)?.loadMore()
case let .account(account): case let .account(account):
navigationEventsSubject.send( navigationEventsSubject.send(
@ -140,7 +142,7 @@ private extension CollectionItemsViewModel {
} }
func process(items: [[CollectionItem]]) { func process(items: [[CollectionItem]]) {
determineIfScrollPositionShouldBeMaintained(newItems: items) maintainScrollPositionOfItem = identifierForScrollPositionMaintenance(newItems: items)
self.items.send(items) self.items.send(items)
let itemsSet = Set(items.reduce([], +)) let itemsSet = Set(items.reduce([], +))
@ -148,18 +150,38 @@ private extension CollectionItemsViewModel {
viewModelCache = viewModelCache.filter { itemsSet.contains($0.key) } viewModelCache = viewModelCache.filter { itemsSet.contains($0.key) }
} }
func determineIfScrollPositionShouldBeMaintained(newItems: [[CollectionItem]]) { func identifierForScrollPositionMaintenance(newItems: [[CollectionItem]]) -> CollectionItemIdentifier? {
maintainScrollPositionOfItem = nil // clear old value let flatNewItems = newItems.reduce([], +)
// Maintain scroll position of parent after initial load of context
if collectionService is ContextService, if collectionService is ContextService,
items.value.isEmpty || items.value.map(\.count) == [0, 1, 0], items.value.isEmpty || items.value.map(\.count) == [0, 1, 0],
let contextParent = newItems.reduce([], +).first(where: { let contextParent = flatNewItems.first(where: {
guard case let .status(_, configuration) = $0 else { return false } guard case let .status(_, configuration) = $0 else { return false }
return configuration.isContextParent return configuration.isContextParent // Maintain scroll position of parent after initial load of context
}) { }) {
maintainScrollPositionOfItem = .init(item: contextParent) return .init(item: contextParent)
} else if collectionService is TimelineService {
let flatItems = items.value.reduce([], +)
let difference = flatNewItems.difference(from: flatItems)
if let lastSelectedLoadMore = lastSelectedLoadMore {
for removal in difference.removals {
if case let .remove(_, item, _) = removal,
case let .loadMore(loadMore) = item,
loadMore == lastSelectedLoadMore,
let direction = (viewModelCache[item]?.0 as? LoadMoreViewModel)?.direction,
direction == .up,
let statusAfterLoadMore = flatItems.first(where: {
guard case let .status(status, _) = $0 else { return false }
return status.id == loadMore.beforeStatusId
}) {
return .init(item: statusAfterLoadMore)
}
}
}
} }
return nil
} }
} }