mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Media preview single stale refresh (#6272)
This commit is contained in:
+33
-19
@@ -22,6 +22,11 @@ class TimelineMediaPreviewController: QLPreviewController {
|
|||||||
|
|
||||||
private var barButtonTimer: Timer?
|
private var barButtonTimer: Timer?
|
||||||
|
|
||||||
|
@CancellableTask private var settledRefreshTask: Task<Void, Never>?
|
||||||
|
/// Media whose file loaded, kept until the swipe settles as each load is only reported once.
|
||||||
|
/// Whichever is on display by then gets refreshed and the rest are dropped.
|
||||||
|
private var itemIDsAwaitingRefresh: Set<MediaPreviewItemID> = []
|
||||||
|
|
||||||
private var pageScrollViewObservation: AnyCancellable?
|
private var pageScrollViewObservation: AnyCancellable?
|
||||||
/// The content offset that the page scroll view rests at when showing the current item.
|
/// The content offset that the page scroll view rests at when showing the current item.
|
||||||
private var pageScrollViewRestingOffset: CGFloat = 0
|
private var pageScrollViewRestingOffset: CGFloat = 0
|
||||||
@@ -44,6 +49,12 @@ class TimelineMediaPreviewController: QLPreviewController {
|
|||||||
view.firstScrollView()
|
view.firstScrollView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the pages are being touched or are still moving, including a touch that hasn't started dragging yet.
|
||||||
|
private var isSwiping: Bool {
|
||||||
|
guard let pageScrollView else { return false }
|
||||||
|
return pageScrollView.isTracking || pageScrollView.isDragging || pageScrollView.isDecelerating
|
||||||
|
}
|
||||||
|
|
||||||
private var captionView: UIView {
|
private var captionView: UIView {
|
||||||
captionHostingController.view
|
captionHostingController.view
|
||||||
}
|
}
|
||||||
@@ -183,6 +194,8 @@ class TimelineMediaPreviewController: QLPreviewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillDisappear(_ animated: Bool) {
|
override func viewWillDisappear(_ animated: Bool) {
|
||||||
|
super.viewWillDisappear(animated)
|
||||||
|
|
||||||
barButtonTimer?.invalidate()
|
barButtonTimer?.invalidate()
|
||||||
barButtonTimer = nil
|
barButtonTimer = nil
|
||||||
}
|
}
|
||||||
@@ -243,7 +256,7 @@ class TimelineMediaPreviewController: QLPreviewController {
|
|||||||
} else if let loadingItem = currentPreviewItem as? TimelineMediaPreviewItem.Loading {
|
} else if let loadingItem = currentPreviewItem as? TimelineMediaPreviewItem.Loading {
|
||||||
// QuickLook prefetches every item up front, so the placeholder may predate a timeline update.
|
// QuickLook prefetches every item up front, so the placeholder may predate a timeline update.
|
||||||
guard !isDisplayedPlaceholderStale else {
|
guard !isDisplayedPlaceholderStale else {
|
||||||
Task { await refreshStalePlaceholder() }
|
refreshCurrentItemWhenSettled()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,29 +283,30 @@ class TimelineMediaPreviewController: QLPreviewController {
|
|||||||
|
|
||||||
private func handleUpdatedItems() {
|
private func handleUpdatedItems() {
|
||||||
guard isDisplayedPlaceholderStale else { return }
|
guard isDisplayedPlaceholderStale else { return }
|
||||||
Task { await refreshStalePlaceholder() }
|
refreshCurrentItemWhenSettled()
|
||||||
}
|
|
||||||
|
|
||||||
private func refreshStalePlaceholder() async {
|
|
||||||
// Refreshing whilst swiping completely breaks the QLPreviewController, so wait for the swipe to settle.
|
|
||||||
while let pageScrollView, pageScrollView.isDragging || pageScrollView.isDecelerating {
|
|
||||||
try? await Task.sleep(for: .seconds(0.1))
|
|
||||||
}
|
|
||||||
|
|
||||||
guard isDisplayedPlaceholderStale else { return }
|
|
||||||
refreshCurrentPreviewItem() // This will trigger loadCurrentItem automatically.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleFileLoaded(itemID: MediaPreviewItemID) {
|
private func handleFileLoaded(itemID: MediaPreviewItemID) {
|
||||||
guard (currentPreviewItem as? TimelineMediaPreviewItem.Media)?.id == itemID else { return }
|
itemIDsAwaitingRefresh.insert(itemID)
|
||||||
|
refreshCurrentItemWhenSettled()
|
||||||
|
}
|
||||||
|
|
||||||
// There's a bug where refreshCurrentPreviewItem completely breaks the QLPreviewController
|
private func refreshCurrentItemWhenSettled() {
|
||||||
// if it's called whilst swiping between items. So don't let that happen.
|
settledRefreshTask = Task {
|
||||||
if let scrollView = pageScrollView, scrollView.isDragging || scrollView.isDecelerating {
|
// Refreshing whilst swiping completely breaks the QLPreviewController, so wait for the swipe to settle.
|
||||||
return
|
// The sleep returns immediately once cancelled, so stop waiting rather than spinning.
|
||||||
|
while !Task.isCancelled, isSwiping {
|
||||||
|
try? await Task.sleep(for: .seconds(0.1))
|
||||||
|
}
|
||||||
|
guard !Task.isCancelled else { return }
|
||||||
|
|
||||||
|
let isDisplayedMediaAwaitingRefresh = (currentPreviewItem as? TimelineMediaPreviewItem.Media).map { itemIDsAwaitingRefresh.contains($0.id) } ?? false
|
||||||
|
itemIDsAwaitingRefresh.removeAll()
|
||||||
|
|
||||||
|
if isDisplayedMediaAwaitingRefresh || isDisplayedPlaceholderStale {
|
||||||
|
refreshCurrentPreviewItem() // This will trigger loadCurrentItem automatically.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshCurrentPreviewItem()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Actions
|
// MARK: - Actions
|
||||||
|
|||||||
Reference in New Issue
Block a user