Fixes #1140 - Dismiss all modals when presenting a room

This commit is contained in:
Stefan Ceriu
2023-08-10 09:55:10 +03:00
committed by Stefan Ceriu
parent e891d6a88b
commit 0a58fbfeac
12 changed files with 56 additions and 5 deletions

View File

@@ -259,6 +259,10 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
private func asyncPresentRoom(_ roomID: String, animated: Bool, destinationRoomProxy: RoomProxyProtocol? = nil) async {
// If any sheets are presented dismiss them, rely on their dismissal callbacks to transition the state machine
// through the correct states before presenting the room
navigationStackCoordinator.setSheetCoordinator(nil)
if let roomProxy, roomProxy.id == roomID {
navigationStackCoordinator.popToRoot()
return

View File

@@ -14,6 +14,7 @@
// limitations under the License.
//
import Combine
import QuickLook
import SwiftUI
@@ -28,10 +29,15 @@ extension View {
private struct InteractiveQuickLookModifier: ViewModifier {
@Binding var item: MediaPreviewItem?
@State private var dismissalPublisher = PassthroughSubject<Void, Never>()
func body(content: Content) -> some View {
content.background {
if let item {
MediaPreviewViewController(previewItem: item) { self.item = nil }
MediaPreviewViewController(previewItem: item, dismissalPublisher: dismissalPublisher) { self.item = nil }
} else {
// Work around QLPreviewController dismissal issues, see below.
let _ = dismissalPublisher.send(())
}
}
}
@@ -39,10 +45,11 @@ private struct InteractiveQuickLookModifier: ViewModifier {
private struct MediaPreviewViewController: UIViewControllerRepresentable {
let previewItem: MediaPreviewItem
let dismissalPublisher: PassthroughSubject<Void, Never>
let onDismiss: () -> Void
func makeUIViewController(context: Context) -> PreviewHostingController {
PreviewHostingController(previewItem: previewItem, onDismiss: onDismiss)
PreviewHostingController(previewItem: previewItem, dismissalPublisher: dismissalPublisher, onDismiss: onDismiss)
}
func updateUIViewController(_ uiViewController: PreviewHostingController, context: Context) { }
@@ -53,15 +60,26 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
/// animations and interactions which don't work if you represent it directly to SwiftUI 🤷
class PreviewHostingController: UIViewController, QLPreviewControllerDataSource, QLPreviewControllerDelegate {
let previewItem: MediaPreviewItem
let dismissalPublisher: PassthroughSubject<Void, Never>
let onDismiss: () -> Void
private var dismissalObserver: AnyCancellable?
var previewController: QLPreviewController?
init(previewItem: MediaPreviewItem, onDismiss: @escaping () -> Void) {
init(previewItem: MediaPreviewItem, dismissalPublisher: PassthroughSubject<Void, Never>, onDismiss: @escaping () -> Void) {
self.previewItem = previewItem
self.dismissalPublisher = dismissalPublisher
self.onDismiss = onDismiss
super.init(nibName: nil, bundle: nil)
// The QLPreviewController will not automatically dismiss itself when the underlying view is removed
// (e.g. switching rooms from a notification) and it continues to hold on to the whole hierarcy.
// Manually tell it to dismiss itself here.
dismissalObserver = dismissalPublisher.sink { _ in
self.dismiss(animated: true)
}
}
@available(*, unavailable)
@@ -125,6 +143,6 @@ struct PreviewView_Previews: PreviewProvider {
title: "Important Document")
static var previews: some View {
MediaPreviewViewController(previewItem: previewItem) { }
MediaPreviewViewController(previewItem: previewItem, dismissalPublisher: .init()) { }
}
}

View File

@@ -79,6 +79,10 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
}
}
func stop() {
viewModel.stop()
}
func toPresentable() -> AnyView {
AnyView(RoomDetailsScreen(context: viewModel.context))
}

View File

@@ -69,6 +69,11 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
// MARK: - Public
func stop() {
// Work around QLPreviewController dismissal issues, see the InteractiveQuickLookModifier.
state.bindings.mediaPreviewItem = nil
}
override func process(viewAction: RoomDetailsScreenViewAction) {
switch viewAction {
case .processTapPeople:

View File

@@ -20,4 +20,5 @@ import Foundation
protocol RoomDetailsScreenViewModelProtocol {
var callback: ((RoomDetailsScreenViewModelAction) -> Void)? { get set }
var context: RoomDetailsScreenViewModelType.Context { get }
func stop()
}

View File

@@ -41,6 +41,8 @@ final class RoomMemberDetailsScreenCoordinator: CoordinatorProtocol {
}
func start() { }
func stop() { viewModel.stop() }
func toPresentable() -> AnyView {
AnyView(RoomMemberDetailsScreen(context: viewModel.context))

View File

@@ -43,6 +43,11 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro
// MARK: - Public
func stop() {
// Work around QLPreviewController dismissal issues, see the InteractiveQuickLookModifier.
state.bindings.mediaPreviewItem = nil
}
override func process(viewAction: RoomMemberDetailsScreenViewAction) {
switch viewAction {
case .showUnignoreAlert:

View File

@@ -20,4 +20,5 @@ import Foundation
protocol RoomMemberDetailsScreenViewModelProtocol {
var callback: ((RoomMemberDetailsScreenViewModelAction) -> Void)? { get set }
var context: RoomMemberDetailsScreenViewModelType.Context { get }
func stop()
}

View File

@@ -106,6 +106,10 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
.store(in: &cancellables)
}
func stop() {
viewModel.stop()
}
func toPresentable() -> AnyView {
AnyView(RoomScreen(context: viewModel.context, composerToolbar: ComposerToolbar(context: composerViewModel.context)))
}

View File

@@ -89,6 +89,11 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
actionsSubject.eraseToAnyPublisher()
}
func stop() {
// Work around QLPreviewController dismissal issues, see the InteractiveQuickLookModifier.
state.bindings.mediaPreviewItem = nil
}
override func process(viewAction: RoomScreenViewAction) {
switch viewAction {
case .displayRoomDetails:

View File

@@ -23,4 +23,5 @@ protocol RoomScreenViewModelProtocol {
var actions: AnyPublisher<RoomScreenViewModelAction, Never> { get }
var context: RoomScreenViewModelType.Context { get }
func process(composerAction: ComposerToolbarViewModelAction)
func stop()
}

1
changelog.d/1140.bugfix Normal file
View File

@@ -0,0 +1 @@
Prevent inconsistent view hierarchies when opening rooms from push notifications