mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 08:15:24 +00:00
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:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user