Minor quicklook fixes. (#6112)

* Only show a spinner when opening the media viewer is slow

* Keep a sent local echo's page in the media viewer

* Fix the caption visibility.

---------

Co-authored-by: Stefan Ceriu <stefan.ceriu@gmail.com>
Co-authored-by: Matthew Hodgson <matthew@matrix.org>
This commit is contained in:
Doug
2026-09-08 09:40:43 +01:00
committed by GitHub
parent 1af16e92db
commit 15627e4512
4 changed files with 112 additions and 10 deletions
@@ -73,6 +73,11 @@ class TimelineMediaPreviewController: QLPreviewController {
super.init(nibName: nil, bundle: nil)
headerHostingController.rootView.onMoveToWindow = { [weak self] in
guard #available(iOS 26, *) else { return }
self?.updateCaptionVisibility()
}
view.addSubview(captionView)
// Constraints added later as the toolbar isn't available yet.
@@ -128,11 +133,9 @@ class TimelineMediaPreviewController: QLPreviewController {
super.viewWillLayoutSubviews()
if let bottomBarItemsContainer {
// Using the toolbar's visibility doesn't work so check its frame.
captionView.isHidden = if #available(iOS 26, *) {
navigationBar?.topItem?.leftBarButtonItem?.frame(in: view) == nil
} else {
bottomBarItemsContainer.frame.minY >= view.frame.maxY
if #unavailable(iOS 26) {
// Using the toolbar's visibility doesn't work so check its frame.
captionView.isHidden = bottomBarItemsContainer.frame.minY >= view.frame.maxY
}
if captionView.constraints.isEmpty {
@@ -176,6 +179,15 @@ class TimelineMediaPreviewController: QLPreviewController {
barButtonTimer = nil
}
@available(iOS 26, *)
private func updateCaptionVisibility() {
// The caption should be hidden alongside the header.
let isHeaderHidden = headerHostingController.view.window == nil
if captionView.isHidden != isHeaderHidden {
captionView.isHidden = isHeaderHidden
}
}
private func updateBarButtons() {
guard let topItem = navigationBar?.topItem else { return }
@@ -306,11 +318,20 @@ class TimelineMediaPreviewController: QLPreviewController {
private struct HeaderView: View {
@ObservedObject var context: TimelineMediaPreviewViewModel.Context
/// Called whenever the header is added or removed from a window.
var onMoveToWindow: () -> Void = { }
private var currentItem: TimelineMediaPreviewItem {
context.viewState.currentItem
}
var body: some View {
content
.background(WindowTrackingView(onMoveToWindow: onMoveToWindow))
}
@ViewBuilder
private var content: some View {
if let mediaItem = currentItem.mediaItem {
VStack(spacing: 0) {
Text(mediaItem.sender.displayName ?? mediaItem.sender.id)
@@ -475,6 +496,31 @@ private struct DownloadIndicatorView: View {
// MARK: - Helpers
/// An invisible view that reports when it is added to or removed from a window.
private struct WindowTrackingView: UIViewRepresentable {
let onMoveToWindow: () -> Void
func makeUIView(context: Context) -> TrackingView {
let view = TrackingView()
view.isUserInteractionEnabled = false
view.onMoveToWindow = onMoveToWindow
return view
}
func updateUIView(_ uiView: TrackingView, context: Context) {
uiView.onMoveToWindow = onMoveToWindow
}
class TrackingView: UIView {
var onMoveToWindow: (() -> Void)?
override func didMoveToWindow() {
super.didMoveToWindow()
onMoveToWindow?()
}
}
}
private extension UIView {
func firstScrollView() -> UIScrollView? {
for view in subviews {