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? {
|
func stateRestorationActivity() -> NSUserActivity? {
|
||||||
let visible = collectionView.indexPathsForVisibleItems.sorted()
|
let visible = collectionView.indexPathsForVisibleItems.sorted()
|
||||||
let snapshot = dataSource.snapshot()
|
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,
|
guard let currentAccountID = mastodonController.accountInfo?.id,
|
||||||
!visible.isEmpty,
|
!visible.isEmpty,
|
||||||
let statusesSection = snapshot.sectionIdentifiers.firstIndex(of: .statuses),
|
let statusesSection = snapshot.sectionIdentifiers.firstIndex(of: .statuses),
|
||||||
let firstVisible = visible.first(where: { $0.section == statusesSection }),
|
let rawCenterVisible = collectionView.indexPathForItem(at: midPoint),
|
||||||
let lastVisible = visible.last(where: { $0.section == statusesSection }) else {
|
let centerVisible = visible.first(where: { $0.section == statusesSection && $0 >= rawCenterVisible }) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let allItems = snapshot.itemIdentifiers(inSection: .statuses)
|
let allItems = snapshot.itemIdentifiers(inSection: .statuses)
|
||||||
|
|
||||||
let startIndex = max(0, firstVisible.row - 20)
|
let startIndex = max(0, centerVisible.row - 20)
|
||||||
let endIndex = min(allItems.count - 1, lastVisible.row + 20)
|
let endIndex = min(allItems.count - 1, centerVisible.row + 20)
|
||||||
|
|
||||||
let firstVisibleItem: Item
|
let centerVisibleItem: Item
|
||||||
var items = allItems[startIndex...endIndex]
|
var items = allItems[startIndex...endIndex]
|
||||||
if let gapIndex = items.firstIndex(of: .gap) {
|
if let gapIndex = items.firstIndex(of: .gap) {
|
||||||
// if the gap is above the top visible item, we take everything below the gap
|
// if the gap is above the top visible item, we take everything below the gap
|
||||||
// otherwise, we take everything above the gap
|
// otherwise, we take everything above the gap
|
||||||
if gapIndex <= firstVisible.row {
|
if gapIndex <= centerVisible.row {
|
||||||
items = allItems[(gapIndex + 1)...endIndex]
|
items = allItems[(gapIndex + 1)...endIndex]
|
||||||
if gapIndex == firstVisible.row {
|
if gapIndex == centerVisible.row {
|
||||||
firstVisibleItem = allItems.first!
|
centerVisibleItem = allItems.first!
|
||||||
} else {
|
} else {
|
||||||
assert(items.indices.contains(firstVisible.row))
|
assert(items.indices.contains(centerVisible.row))
|
||||||
firstVisibleItem = allItems[firstVisible.row]
|
centerVisibleItem = allItems[centerVisible.row]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
items = allItems[startIndex..<gapIndex]
|
items = allItems[startIndex..<gapIndex]
|
||||||
firstVisibleItem = allItems[firstVisible.row]
|
centerVisibleItem = allItems[centerVisible.row]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
firstVisibleItem = allItems[firstVisible.row]
|
centerVisibleItem = allItems[centerVisible.row]
|
||||||
}
|
}
|
||||||
let ids = items.map {
|
let ids = items.map {
|
||||||
if case .status(id: let id, state: _) = $0 {
|
if case .status(id: let id, state: _) = $0 {
|
||||||
|
@ -225,18 +227,18 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
fatalError()
|
fatalError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let firstVisibleID: String
|
let centerVisibleID: String
|
||||||
if case .status(id: let id, state: _) = firstVisibleItem {
|
if case .status(id: let id, state: _) = centerVisibleItem {
|
||||||
firstVisibleID = id
|
centerVisibleID = id
|
||||||
} else {
|
} else {
|
||||||
fatalError()
|
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)!
|
let activity = UserActivityManager.showTimelineActivity(timeline: timeline, accountID: currentAccountID)!
|
||||||
activity.addUserInfoEntries(from: [
|
activity.addUserInfoEntries(from: [
|
||||||
"statusIDs": ids,
|
"statusIDs": ids,
|
||||||
"topID": firstVisibleID,
|
"centerID": centerVisibleID,
|
||||||
])
|
])
|
||||||
activity.isEligibleForPrediction = false
|
activity.isEligibleForPrediction = false
|
||||||
return activity
|
return activity
|
||||||
|
@ -260,8 +262,8 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
let items = statusIDs.map { Item.status(id: $0, state: .unknown) }
|
let items = statusIDs.map { Item.status(id: $0, state: .unknown) }
|
||||||
snapshot.appendItems(items, toSection: .statuses)
|
snapshot.appendItems(items, toSection: .statuses)
|
||||||
dataSource.apply(snapshot, animatingDifferences: false) {
|
dataSource.apply(snapshot, animatingDifferences: false) {
|
||||||
if let topID = activity.userInfo?["topID"] as? String,
|
if let centerID = activity.userInfo?["centerID"] as? String ?? activity.userInfo?["topID"] as? String,
|
||||||
let index = statusIDs.firstIndex(of: topID),
|
let index = statusIDs.firstIndex(of: centerID),
|
||||||
let indexPath = self.dataSource.indexPath(for: items[index]) {
|
let indexPath = self.dataSource.indexPath(for: items[index]) {
|
||||||
// it sometimes takes multiple attempts to convert on the right scroll position
|
// 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
|
// 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
|
count += 1
|
||||||
let origOffset = self.collectionView.contentOffset
|
let origOffset = self.collectionView.contentOffset
|
||||||
self.collectionView.layoutIfNeeded()
|
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
|
let newOffset = self.collectionView.contentOffset
|
||||||
if abs(origOffset.y - newOffset.y) <= 1 {
|
if abs(origOffset.y - newOffset.y) <= 1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stateRestorationLogger.fault("TimelineViewController: restored statuses with top ID \(topID)")
|
stateRestorationLogger.fault("TimelineViewController: restored statuses with center ID \(centerID)")
|
||||||
} else {
|
} 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