Fix inset adjustment

This commit is contained in:
Justin Mazzocchi 2021-01-16 18:16:43 -08:00
parent 73fc2cd599
commit d42642c079
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
5 changed files with 33 additions and 37 deletions

View file

@ -291,14 +291,11 @@ private extension TableViewController {
if
let itemId = update.maintainScrollPositionItemId,
let indexPath = self.dataSource.indexPath(itemId: itemId) {
if self.viewModel.shouldAdjustContentInset {
if update.shouldAdjustContentInset {
self.tableView.contentInset.bottom = max(
Self.bottomInset,
self.tableView.frame.height
- self.tableView.contentSize.height
- self.tableView.safeAreaInsets.top
- self.tableView.safeAreaInsets.bottom)
+ self.tableView.rectForRow(at: indexPath).minY
self.tableView.safeAreaLayoutGuide.layoutFrame.height
- self.tableView.rectForRow(at: indexPath).height,
Self.bottomInset)
}
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)

View file

@ -9,14 +9,16 @@ public final class CollectionItemsViewModel: ObservableObject {
@Published public var alertItem: AlertItem?
public private(set) var nextPageMaxId: String?
private let items = CurrentValueSubject<[[CollectionItem]], Never>([])
@Published private var lastUpdate = CollectionUpdate(
items: [],
maintainScrollPositionItemId: nil,
shouldAdjustContentInset: false)
private let collectionService: CollectionService
private let identification: Identification
private var viewModelCache = [CollectionItem: (viewModel: CollectionItemViewModel, events: AnyCancellable)]()
private let eventsSubject = PassthroughSubject<CollectionItemEvent, Never>()
private let loadingSubject = PassthroughSubject<Bool, Never>()
private let expandAllSubject: CurrentValueSubject<ExpandAllState, Never>
private var maintainScrollPositionItemId: CollectionItem.Id?
private var topVisibleIndexPath = IndexPath(item: 0, section: 0)
private let lastReadId = CurrentValueSubject<String?, Never>(nil)
private var lastSelectedLoadMore: LoadMore?
@ -57,11 +59,7 @@ public final class CollectionItemsViewModel: ObservableObject {
extension CollectionItemsViewModel: CollectionViewModel {
public var updates: AnyPublisher<CollectionUpdate, Never> {
items.map { [weak self] in
CollectionUpdate(items: $0,
maintainScrollPositionItemId: self?.maintainScrollPositionItemId)
}
.eraseToAnyPublisher()
$lastUpdate.eraseToAnyPublisher()
}
public var title: AnyPublisher<String, Never> { collectionService.title }
@ -80,8 +78,6 @@ extension CollectionItemsViewModel: CollectionViewModel {
public var events: AnyPublisher<CollectionItemEvent, Never> { eventsSubject.eraseToAnyPublisher() }
public var shouldAdjustContentInset: Bool { collectionService is ContextService }
public var preferLastPresentIdOverNextPageMaxId: Bool { collectionService.preferLastPresentIdOverNextPageMaxId }
public var canRefresh: Bool { collectionService.canRefresh }
@ -120,7 +116,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
}
public func select(indexPath: IndexPath) {
let item = items.value[indexPath.section][indexPath.item]
let item = lastUpdate.items[indexPath.section][indexPath.item]
switch item {
case let .status(status, _):
@ -162,14 +158,14 @@ extension CollectionItemsViewModel: CollectionViewModel {
topVisibleIndexPath = indexPath
if !shouldRestorePositionOfLocalLastReadId,
items.value.count > indexPath.section,
items.value[indexPath.section].count > indexPath.item {
lastReadId.send(items.value[indexPath.section][indexPath.item].itemId)
lastUpdate.items.count > indexPath.section,
lastUpdate.items[indexPath.section].count > indexPath.item {
lastReadId.send(lastUpdate.items[indexPath.section][indexPath.item].itemId)
}
}
public func canSelect(indexPath: IndexPath) -> Bool {
switch items.value[indexPath.section][indexPath.item] {
switch lastUpdate.items[indexPath.section][indexPath.item] {
case let .status(_, configuration):
return !configuration.isContextParent
case .loadMore:
@ -181,7 +177,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
// swiftlint:disable:next function_body_length cyclomatic_complexity
public func viewModel(indexPath: IndexPath) -> CollectionItemViewModel {
let item = items.value[indexPath.section][indexPath.item]
let item = lastUpdate.items[indexPath.section][indexPath.item]
let cachedViewModel = viewModelCache[item]?.viewModel
switch item {
@ -261,7 +257,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
}
public func toggleExpandAll() {
let statusIds = Set(items.value.reduce([], +).compactMap { item -> Status.Id? in
let statusIds = Set(lastUpdate.items.reduce([], +).compactMap { item -> Status.Id? in
guard case let .status(status, _) = item else { return nil }
return status.id
@ -287,6 +283,10 @@ extension CollectionItemsViewModel: CollectionViewModel {
}
private extension CollectionItemsViewModel {
var lastUpdateWasContextParentOnly: Bool {
collectionService is ContextService && lastUpdate.items.map(\.count) == [0, 1, 0]
}
func cache(viewModel: CollectionItemViewModel, forItem item: CollectionItem) {
viewModelCache[item] = (viewModel, viewModel.events
.flatMap { [weak self] events -> AnyPublisher<CollectionItemEvent, Never> in
@ -299,10 +299,13 @@ private extension CollectionItemsViewModel {
}
func process(items: [[CollectionItem]]) {
maintainScrollPositionItemId = idForScrollPositionMaintenance(newItems: items)
self.items.send(items)
let flatItems = items.reduce([], +)
let itemsSet = Set(flatItems)
let itemsSet = Set(items.reduce([], +))
self.lastUpdate = .init(
items: items,
maintainScrollPositionItemId: idForScrollPositionMaintenance(newItems: items),
shouldAdjustContentInset: lastUpdateWasContextParentOnly && flatItems.count > 1)
viewModelCache = viewModelCache.filter { itemsSet.contains($0.key) }
}
@ -312,14 +315,14 @@ private extension CollectionItemsViewModel {
guard let markerTimeline = collectionService.markerTimeline,
identification.appPreferences.positionBehavior(markerTimeline: markerTimeline) == .rememberPosition,
let lastItemId = items.value.last?.last?.itemId
let lastItemId = lastUpdate.items.last?.last?.itemId
else { return maxId }
return min(maxId, lastItemId)
}
func idForScrollPositionMaintenance(newItems: [[CollectionItem]]) -> CollectionItem.Id? {
let flatItems = items.value.reduce([], +)
let flatItems = lastUpdate.items.reduce([], +)
let flatNewItems = newItems.reduce([], +)
if shouldRestorePositionOfLocalLastReadId,
@ -332,7 +335,7 @@ private extension CollectionItemsViewModel {
}
if collectionService is ContextService,
items.value.isEmpty || items.value.map(\.count) == [0, 1, 0],
lastUpdate.items.isEmpty || lastUpdate.items.map(\.count) == [0, 1, 0],
let contextParent = flatNewItems.first(where: {
guard case let .status(_, configuration) = $0 else { return false }
@ -359,9 +362,9 @@ 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 lastUpdate.items.count > topVisibleIndexPath.section,
lastUpdate.items[topVisibleIndexPath.section].count > topVisibleIndexPath.item {
let topVisibleItem = lastUpdate.items[topVisibleIndexPath.section][topVisibleIndexPath.item]
if newItems.count > topVisibleIndexPath.section,
let newIndex = newItems[topVisibleIndexPath.section]

View file

@ -11,7 +11,6 @@ public protocol CollectionViewModel {
var alertItems: AnyPublisher<AlertItem, Never> { get }
var loading: AnyPublisher<Bool, Never> { get }
var events: AnyPublisher<CollectionItemEvent, Never> { get }
var shouldAdjustContentInset: Bool { get }
var nextPageMaxId: String? { get }
var preferLastPresentIdOverNextPageMaxId: Bool { get }
var canRefresh: Bool { get }

View file

@ -3,4 +3,5 @@
public struct CollectionUpdate: Hashable {
public let items: [[CollectionItem]]
public let maintainScrollPositionItemId: String?
public let shouldAdjustContentInset: Bool
}

View file

@ -95,10 +95,6 @@ extension ProfileViewModel: CollectionViewModel {
.eraseToAnyPublisher()
}
public var shouldAdjustContentInset: Bool {
collectionViewModel.value.shouldAdjustContentInset
}
public var nextPageMaxId: String? {
collectionViewModel.value.nextPageMaxId
}