Bring back default controls for QuickLook based media viewers (#3254)

* Fixes #3243 - Bring back default controls for QuickLook based media viewers
This commit is contained in:
Stefan Ceriu
2024-09-11 12:11:30 +03:00
committed by GitHub
parent bef892451e
commit ff5b22cecf
4 changed files with 18 additions and 36 deletions
@@ -12,14 +12,14 @@ import SwiftUI
extension View { extension View {
/// Preview a media file using a QuickLook Preview Controller. The preview is interactive with /// Preview a media file using a QuickLook Preview Controller. The preview is interactive with
/// the dismiss gesture working as expected if it was presented from UIKit. /// the dismiss gesture working as expected if it was presented from UIKit.
func interactiveQuickLook(item: Binding<MediaPreviewItem?>, shouldHideControls: Bool = false) -> some View { func interactiveQuickLook(item: Binding<MediaPreviewItem?>, allowEditing: Bool = true) -> some View {
modifier(InteractiveQuickLookModifier(item: item, shouldHideControls: shouldHideControls)) modifier(InteractiveQuickLookModifier(item: item, allowEditing: allowEditing))
} }
} }
private struct InteractiveQuickLookModifier: ViewModifier { private struct InteractiveQuickLookModifier: ViewModifier {
@Binding var item: MediaPreviewItem? @Binding var item: MediaPreviewItem?
let shouldHideControls: Bool let allowEditing: Bool
@State private var dismissalPublisher = PassthroughSubject<Void, Never>() @State private var dismissalPublisher = PassthroughSubject<Void, Never>()
@@ -27,7 +27,7 @@ private struct InteractiveQuickLookModifier: ViewModifier {
content.background { content.background {
if let item { if let item {
MediaPreviewViewController(previewItem: item, MediaPreviewViewController(previewItem: item,
shouldHideControls: shouldHideControls, allowEditing: allowEditing,
dismissalPublisher: dismissalPublisher) { self.item = nil } dismissalPublisher: dismissalPublisher) { self.item = nil }
} else { } else {
// Work around QLPreviewController dismissal issues, see below. // Work around QLPreviewController dismissal issues, see below.
@@ -39,13 +39,13 @@ private struct InteractiveQuickLookModifier: ViewModifier {
private struct MediaPreviewViewController: UIViewControllerRepresentable { private struct MediaPreviewViewController: UIViewControllerRepresentable {
let previewItem: MediaPreviewItem let previewItem: MediaPreviewItem
let shouldHideControls: Bool let allowEditing: Bool
let dismissalPublisher: PassthroughSubject<Void, Never> let dismissalPublisher: PassthroughSubject<Void, Never>
let onDismiss: () -> Void let onDismiss: () -> Void
func makeUIViewController(context: Context) -> PreviewHostingController { func makeUIViewController(context: Context) -> PreviewHostingController {
PreviewHostingController(previewItem: previewItem, PreviewHostingController(previewItem: previewItem,
shouldHideControls: shouldHideControls, allowEditing: allowEditing,
dismissalPublisher: dismissalPublisher, dismissalPublisher: dismissalPublisher,
onDismiss: onDismiss) onDismiss: onDismiss)
} }
@@ -58,7 +58,7 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
/// animations and interactions which don't work if you represent it directly to SwiftUI 🤷‍♂️ /// animations and interactions which don't work if you represent it directly to SwiftUI 🤷‍♂️
class PreviewHostingController: UIViewController, QLPreviewControllerDataSource, QLPreviewControllerDelegate { class PreviewHostingController: UIViewController, QLPreviewControllerDataSource, QLPreviewControllerDelegate {
let previewItem: MediaPreviewItem let previewItem: MediaPreviewItem
let shouldHideControls: Bool let allowEditing: Bool
let onDismiss: () -> Void let onDismiss: () -> Void
private var dismissalObserver: AnyCancellable? private var dismissalObserver: AnyCancellable?
@@ -66,11 +66,11 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
var previewController: QLPreviewController? var previewController: QLPreviewController?
init(previewItem: MediaPreviewItem, init(previewItem: MediaPreviewItem,
shouldHideControls: Bool, allowEditing: Bool,
dismissalPublisher: PassthroughSubject<Void, Never>, dismissalPublisher: PassthroughSubject<Void, Never>,
onDismiss: @escaping () -> Void) { onDismiss: @escaping () -> Void) {
self.previewItem = previewItem self.previewItem = previewItem
self.shouldHideControls = shouldHideControls self.allowEditing = allowEditing
self.onDismiss = onDismiss self.onDismiss = onDismiss
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
@@ -100,7 +100,7 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
guard self.previewController == nil else { return } guard self.previewController == nil else { return }
let previewController = (shouldHideControls ? NoControlsPreviewController() : QLPreviewController()) let previewController = QLPreviewController()
previewController.dataSource = self previewController.dataSource = self
previewController.delegate = self previewController.delegate = self
present(previewController, animated: true) present(previewController, animated: true)
@@ -120,6 +120,10 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
// MARK: QLPreviewControllerDelegate // MARK: QLPreviewControllerDelegate
func previewController(_ controller: QLPreviewController, editingModeFor previewItem: QLPreviewItem) -> QLPreviewItemEditingMode {
allowEditing ? .createCopy : .disabled
}
func previewControllerDidDismiss(_ controller: QLPreviewController) { func previewControllerDidDismiss(_ controller: QLPreviewController) {
onDismiss() onDismiss()
} }
@@ -139,28 +143,6 @@ class MediaPreviewItem: NSObject, QLPreviewItem {
} }
} }
private class NoControlsPreviewController: QLPreviewController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard let navigationController = children.first as? UINavigationController else {
return
}
// Remove top file details bar
navigationController.navigationBar.isHidden = true
// Remove the toolbars and their buttons
navigationController.view.subviews.compactMap { $0 as? UIToolbar }.forEach { toolbar in
toolbar.subviews.forEach { item in
item.isHidden = true
}
toolbar.isHidden = true
}
}
}
// MARK: - Previews // MARK: - Previews
struct PreviewView_Previews: PreviewProvider { struct PreviewView_Previews: PreviewProvider {
@@ -170,7 +152,7 @@ struct PreviewView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
MediaPreviewViewController(previewItem: previewItem, MediaPreviewViewController(previewItem: previewItem,
shouldHideControls: false, allowEditing: false,
dismissalPublisher: .init()) { } dismissalPublisher: .init()) { }
} }
} }
@@ -57,7 +57,7 @@ struct RoomDetailsScreen: View {
.navigationTitle(L10n.screenRoomDetailsTitle) .navigationTitle(L10n.screenRoomDetailsTitle)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.track(screen: .RoomDetails) .track(screen: .RoomDetails)
.interactiveQuickLook(item: $context.mediaPreviewItem, shouldHideControls: true) .interactiveQuickLook(item: $context.mediaPreviewItem, allowEditing: false)
} }
// MARK: - Private // MARK: - Private
@@ -24,7 +24,7 @@ struct RoomMemberDetailsScreen: View {
.alert(item: $context.ignoreUserAlert, actions: blockUserAlertActions, message: blockUserAlertMessage) .alert(item: $context.ignoreUserAlert, actions: blockUserAlertActions, message: blockUserAlertMessage)
.alert(item: $context.alertInfo) .alert(item: $context.alertInfo)
.track(screen: .User) .track(screen: .User)
.interactiveQuickLook(item: $context.mediaPreviewItem, shouldHideControls: true) .interactiveQuickLook(item: $context.mediaPreviewItem, allowEditing: false)
} }
// MARK: - Private // MARK: - Private
@@ -21,7 +21,7 @@ struct UserProfileScreen: View {
.toolbar { toolbar } .toolbar { toolbar }
.alert(item: $context.alertInfo) .alert(item: $context.alertInfo)
.track(screen: .User) .track(screen: .User)
.interactiveQuickLook(item: $context.mediaPreviewItem, shouldHideControls: true) .interactiveQuickLook(item: $context.mediaPreviewItem, allowEditing: false)
} }
// MARK: - Private // MARK: - Private