Scroll position maintenance when loading up
This commit is contained in:
parent
d80988e6e3
commit
c00adc2767
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue