From c589c7405278452d8c74747223248a93112f3e00 Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Tue, 6 Oct 2020 16:12:11 -0700 Subject: [PATCH] Scroll position maintenance --- View Controllers/TableViewController.swift | 6 ++++++ .../ViewModels/CollectionItemsViewModel.swift | 16 ++++++++++++++++ .../Sources/ViewModels/CollectionViewModel.swift | 1 + .../Sources/ViewModels/ProfileViewModel.swift | 4 ++++ 4 files changed, 27 insertions(+) diff --git a/View Controllers/TableViewController.swift b/View Controllers/TableViewController.swift index 879a867..ab8ae3e 100644 --- a/View Controllers/TableViewController.swift +++ b/View Controllers/TableViewController.swift @@ -210,6 +210,12 @@ private extension TableViewController { self.sizeTableHeaderFooterViews() } .store(in: &cancellables) + + tableView.publisher(for: \.contentOffset) + .compactMap { [weak self] _ in self?.tableView.indexPathsForVisibleRows?.first } + .removeDuplicates() + .sink { [weak self] in self?.viewModel.viewedAtTop(indexPath: $0) } + .store(in: &cancellables) } func update(items: [[CollectionItemIdentifier]]) { diff --git a/ViewModels/Sources/ViewModels/CollectionItemsViewModel.swift b/ViewModels/Sources/ViewModels/CollectionItemsViewModel.swift index 6362c99..6aeed0e 100644 --- a/ViewModels/Sources/ViewModels/CollectionItemsViewModel.swift +++ b/ViewModels/Sources/ViewModels/CollectionItemsViewModel.swift @@ -15,6 +15,7 @@ final public class CollectionItemsViewModel: ObservableObject { private var viewModelCache = [CollectionItem: (CollectionItemViewModel, AnyCancellable)]() private let navigationEventsSubject = PassthroughSubject() private let loadingSubject = PassthroughSubject() + private var topVisibleIndexPath = IndexPath(item: 0, section: 0) private var lastSelectedLoadMore: LoadMore? private var cancellables = Set() @@ -80,6 +81,10 @@ extension CollectionItemsViewModel: CollectionViewModel { } } + public func viewedAtTop(indexPath: IndexPath) { + topVisibleIndexPath = indexPath + } + public func canSelect(indexPath: IndexPath) -> Bool { switch items.value[indexPath.section][indexPath.item] { case let .status(_, configuration): @@ -180,6 +185,17 @@ private extension CollectionItemsViewModel { } } } + + if items.value.count > topVisibleIndexPath.section, + items.value[topVisibleIndexPath.section].count > topVisibleIndexPath.item { + let topVisibleItem = items.value[topVisibleIndexPath.section][topVisibleIndexPath.item] + + if newItems.count > topVisibleIndexPath.section, + let newIndex = newItems[topVisibleIndexPath.section].firstIndex(of: topVisibleItem), + newIndex > topVisibleIndexPath.item { + return .init(item: topVisibleItem) + } + } } return nil diff --git a/ViewModels/Sources/ViewModels/CollectionViewModel.swift b/ViewModels/Sources/ViewModels/CollectionViewModel.swift index bd8b7c4..5af1b69 100644 --- a/ViewModels/Sources/ViewModels/CollectionViewModel.swift +++ b/ViewModels/Sources/ViewModels/CollectionViewModel.swift @@ -12,6 +12,7 @@ public protocol CollectionViewModel { var nextPageMaxId: String? { get } var maintainScrollPositionOfItem: CollectionItemIdentifier? { get } func request(maxId: String?, minId: String?) + func viewedAtTop(indexPath: IndexPath) func select(indexPath: IndexPath) func canSelect(indexPath: IndexPath) -> Bool func viewModel(indexPath: IndexPath) -> CollectionItemViewModel diff --git a/ViewModels/Sources/ViewModels/ProfileViewModel.swift b/ViewModels/Sources/ViewModels/ProfileViewModel.swift index cf9e464..ac7a5d4 100644 --- a/ViewModels/Sources/ViewModels/ProfileViewModel.swift +++ b/ViewModels/Sources/ViewModels/ProfileViewModel.swift @@ -85,6 +85,10 @@ extension ProfileViewModel: CollectionViewModel { collectionViewModel.value.request(maxId: maxId, minId: minId) } + public func viewedAtTop(indexPath: IndexPath) { + collectionViewModel.value.viewedAtTop(indexPath: indexPath) + } + public func select(indexPath: IndexPath) { collectionViewModel.value.select(indexPath: indexPath) }