Skip to content

Commit

Permalink
Fixes #1140 - Dismiss all modals when presenting a room
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanceriu committed Aug 10, 2023
1 parent 8a69ca1 commit a73502a
Show file tree
Hide file tree
Showing 12 changed files with 56 additions and 5 deletions.
4 changes: 4 additions & 0 deletions ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// limitations under the License.
//

import Combine
import QuickLook
import SwiftUI

Expand All @@ -28,21 +29,27 @@ 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(())
}
}
}
}

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) { }
Expand All @@ -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)
Expand Down Expand Up @@ -125,6 +143,6 @@ struct PreviewView_Previews: PreviewProvider {
title: "Important Document")

static var previews: some View {
MediaPreviewViewController(previewItem: previewItem) { }
MediaPreviewViewController(previewItem: previewItem, dismissalPublisher: .init()) { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
}
}

func stop() {
viewModel.stop()
}

func toPresentable() -> AnyView {
AnyView(RoomDetailsScreen(context: viewModel.context))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ import Foundation
protocol RoomDetailsScreenViewModelProtocol {
var callback: ((RoomDetailsScreenViewModelAction) -> Void)? { get set }
var context: RoomDetailsScreenViewModelType.Context { get }
func stop()
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ final class RoomMemberDetailsScreenCoordinator: CoordinatorProtocol {
}

func start() { }

func stop() { viewModel.stop() }

func toPresentable() -> AnyView {
AnyView(RoomMemberDetailsScreen(context: viewModel.context))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ import Foundation
protocol RoomMemberDetailsScreenViewModelProtocol {
var callback: ((RoomMemberDetailsScreenViewModelAction) -> Void)? { get set }
var context: RoomMemberDetailsScreenViewModelType.Context { get }
func stop()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
Expand Down
5 changes: 5 additions & 0 deletions ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ protocol RoomScreenViewModelProtocol {
var actions: AnyPublisher<RoomScreenViewModelAction, Never> { get }
var context: RoomScreenViewModelType.Context { get }
func process(composerAction: ComposerToolbarViewModelAction)
func stop()
}
1 change: 1 addition & 0 deletions changelog.d/1140.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Prevent inconsistent view hierarchies when opening rooms from push notifications

0 comments on commit a73502a

Please sign in to comment.