Tweak timeline state restoration to maintain scroll position of center item
This commit is contained in:
parent
d409d26478
commit
366834e2e4
|
@ -186,37 +186,39 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
func stateRestorationActivity() -> NSUserActivity? {
|
||||
let visible = collectionView.indexPathsForVisibleItems.sorted()
|
||||
let snapshot = dataSource.snapshot()
|
||||
let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
|
||||
let midPoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
|
||||
guard let currentAccountID = mastodonController.accountInfo?.id,
|
||||
!visible.isEmpty,
|
||||
let statusesSection = snapshot.sectionIdentifiers.firstIndex(of: .statuses),
|
||||
let firstVisible = visible.first(where: { $0.section == statusesSection }),
|
||||
let lastVisible = visible.last(where: { $0.section == statusesSection }) else {
|
||||
let rawCenterVisible = collectionView.indexPathForItem(at: midPoint),
|
||||
let centerVisible = visible.first(where: { $0.section == statusesSection && $0 >= rawCenterVisible }) else {
|
||||
return nil
|
||||
}
|
||||
let allItems = snapshot.itemIdentifiers(inSection: .statuses)
|
||||
|
||||
let startIndex = max(0, firstVisible.row - 20)
|
||||
let endIndex = min(allItems.count - 1, lastVisible.row + 20)
|
||||
let startIndex = max(0, centerVisible.row - 20)
|
||||
let endIndex = min(allItems.count - 1, centerVisible.row + 20)
|
||||
|
||||
let firstVisibleItem: Item
|
||||
let centerVisibleItem: Item
|
||||
var items = allItems[startIndex...endIndex]
|
||||
if let gapIndex = items.firstIndex(of: .gap) {
|
||||
// if the gap is above the top visible item, we take everything below the gap
|
||||
// otherwise, we take everything above the gap
|
||||
if gapIndex <= firstVisible.row {
|
||||
if gapIndex <= centerVisible.row {
|
||||
items = allItems[(gapIndex + 1)...endIndex]
|
||||
if gapIndex == firstVisible.row {
|
||||
firstVisibleItem = allItems.first!
|
||||
if gapIndex == centerVisible.row {
|
||||
centerVisibleItem = allItems.first!
|
||||
} else {
|
||||
assert(items.indices.contains(firstVisible.row))
|
||||
firstVisibleItem = allItems[firstVisible.row]
|
||||
assert(items.indices.contains(centerVisible.row))
|
||||
centerVisibleItem = allItems[centerVisible.row]
|
||||
}
|
||||
} else {
|
||||
items = allItems[startIndex..<gapIndex]
|
||||
firstVisibleItem = allItems[firstVisible.row]
|
||||
centerVisibleItem = allItems[centerVisible.row]
|
||||
}
|
||||
} else {
|
||||
firstVisibleItem = allItems[firstVisible.row]
|
||||
centerVisibleItem = allItems[centerVisible.row]
|
||||
}
|
||||
let ids = items.map {
|
||||
if case .status(id: let id, state: _) = $0 {
|
||||
|
@ -225,18 +227,18 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
fatalError()
|
||||
}
|
||||
}
|
||||
let firstVisibleID: String
|
||||
if case .status(id: let id, state: _) = firstVisibleItem {
|
||||
firstVisibleID = id
|
||||
let centerVisibleID: String
|
||||
if case .status(id: let id, state: _) = centerVisibleItem {
|
||||
centerVisibleID = id
|
||||
} else {
|
||||
fatalError()
|
||||
}
|
||||
stateRestorationLogger.debug("TimelineViewController: creating state restoration activity with topID \(firstVisibleID)")
|
||||
stateRestorationLogger.debug("TimelineViewController: creating state restoration activity with topID \(centerVisibleID)")
|
||||
|
||||
let activity = UserActivityManager.showTimelineActivity(timeline: timeline, accountID: currentAccountID)!
|
||||
activity.addUserInfoEntries(from: [
|
||||
"statusIDs": ids,
|
||||
"topID": firstVisibleID,
|
||||
"centerID": centerVisibleID,
|
||||
])
|
||||
activity.isEligibleForPrediction = false
|
||||
return activity
|
||||
|
@ -260,8 +262,8 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
let items = statusIDs.map { Item.status(id: $0, state: .unknown) }
|
||||
snapshot.appendItems(items, toSection: .statuses)
|
||||
dataSource.apply(snapshot, animatingDifferences: false) {
|
||||
if let topID = activity.userInfo?["topID"] as? String,
|
||||
let index = statusIDs.firstIndex(of: topID),
|
||||
if let centerID = activity.userInfo?["centerID"] as? String ?? activity.userInfo?["topID"] as? String,
|
||||
let index = statusIDs.firstIndex(of: centerID),
|
||||
let indexPath = self.dataSource.indexPath(for: items[index]) {
|
||||
// it sometimes takes multiple attempts to convert on the right scroll position
|
||||
// since we're dealing with a bunch of unmeasured cells, so just try a few times in a loop
|
||||
|
@ -270,15 +272,15 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
count += 1
|
||||
let origOffset = self.collectionView.contentOffset
|
||||
self.collectionView.layoutIfNeeded()
|
||||
self.collectionView.scrollToItem(at: indexPath, at: .top, animated: false)
|
||||
self.collectionView.scrollToItem(at: indexPath, at: .centeredVertically, animated: false)
|
||||
let newOffset = self.collectionView.contentOffset
|
||||
if abs(origOffset.y - newOffset.y) <= 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
stateRestorationLogger.fault("TimelineViewController: restored statuses with top ID \(topID)")
|
||||
stateRestorationLogger.fault("TimelineViewController: restored statuses with center ID \(centerID)")
|
||||
} else {
|
||||
stateRestorationLogger.fault("TimelineViewController: restored statuses, but couldn't find top ID")
|
||||
stateRestorationLogger.fault("TimelineViewController: restored statuses, but couldn't find center ID")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue