diff --git a/Sources/XCoordinator/CoordinatorContextMenuInteractionDelegate.swift b/Sources/XCoordinator/CoordinatorContextMenuInteractionDelegate.swift new file mode 100644 index 00000000..b93fafb8 --- /dev/null +++ b/Sources/XCoordinator/CoordinatorContextMenuInteractionDelegate.swift @@ -0,0 +1,81 @@ +// +// CoordinatorContextMenuInteractionDelegate.swift +// XCoordinator +// +// Created by Paul Kraft on 13.02.20. +// + +import UIKit + +@available(iOS 13.0, *) +internal class CoordinatorContextMenuInteractionDelegate: NSObject, UIContextMenuInteractionDelegate { + + // MARK: Stored properties + + private let identifier: NSCopying? + private let transition: () -> TransitionType + private let menu: UIMenu? + + private let rootViewController: TransitionType.RootViewController + private let completion: PresentationHandler? + + // MARK: Initialization + + internal init( + identifier: NSCopying?, + transition: @escaping () -> TransitionType, + rootViewController: TransitionType.RootViewController, + menu: UIMenu?, + completion: PresentationHandler? + ) { + self.identifier = identifier + self.transition = transition + self.menu = menu + self.rootViewController = rootViewController + self.completion = completion + } + + // MARK: Methods + + internal func contextMenuInteraction( + _ interaction: UIContextMenuInteraction, + configurationForMenuAtLocation location: CGPoint + ) -> UIContextMenuConfiguration? { + UIContextMenuConfiguration( + identifier: identifier, + previewProvider: { [weak self] in + self?.transition().presentables.last?.viewController + }, + actionProvider: { [weak self] _ in + self?.menu + } + ) + } + + internal func contextMenuInteraction( + _ interaction: UIContextMenuInteraction, + willDisplayMenuFor configuration: UIContextMenuConfiguration, + animator: UIContextMenuInteractionAnimating? + ) { + print(#function) + } + + internal func contextMenuInteraction( + _ interaction: UIContextMenuInteraction, + willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, + animator: UIContextMenuInteractionCommitAnimating + ) { + transition().perform(on: rootViewController, + with: .default, + completion: completion) + } + + internal func contextMenuInteraction( + _ interaction: UIContextMenuInteraction, + willEndFor configuration: UIContextMenuConfiguration, + animator: UIContextMenuInteractionAnimating? + ) { + completion?() + } + +} diff --git a/Sources/XCoordinator/Transition+Init.swift b/Sources/XCoordinator/Transition+Init.swift index d73ae128..282cc6b5 100755 --- a/Sources/XCoordinator/Transition+Init.swift +++ b/Sources/XCoordinator/Transition+Init.swift @@ -274,4 +274,31 @@ extension Coordinator where Self: AnyObject { } } + /// + /// Use this method to create a UIContextMenuInteractionDelegate to generate a preview + /// from a given route and perform the route when the preview is tapped. + /// + /// - Parameters: + /// - route: The route to be triggered when the preview has been selected. + /// - menu: The menu to be shown alongside the preview. + /// + @available(iOS 13.0, *) + public func contextMenuInteractionDelegate( + for route: RouteType, + identifier: NSCopying? = nil, + menu: UIMenu? = nil, + completion: PresentationHandler? = nil + ) -> UIContextMenuInteractionDelegate { + + CoordinatorContextMenuInteractionDelegate( + identifier: identifier, + transition: { [weak self] in + self?.prepareTransition(for: route) ?? .multiple() + }, + rootViewController: rootViewController, + menu: menu, + completion: completion + ) + } + } diff --git a/XCoordinator.xcodeproj/project.pbxproj b/XCoordinator.xcodeproj/project.pbxproj index c49d76d3..a0381925 100644 --- a/XCoordinator.xcodeproj/project.pbxproj +++ b/XCoordinator.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 9B6E0D0623F5BBD100694FA3 /* CoordinatorContextMenuInteractionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B6E0D0523F5BBD100694FA3 /* CoordinatorContextMenuInteractionDelegate.swift */; }; OBJ_244 /* AddRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_74 /* AddRef.swift */; }; OBJ_245 /* Amb.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_75 /* Amb.swift */; }; OBJ_246 /* AnonymousDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_76 /* AnonymousDisposable.swift */; }; @@ -288,6 +289,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 9B6E0D0523F5BBD100694FA3 /* CoordinatorContextMenuInteractionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorContextMenuInteractionDelegate.swift; sourceTree = ""; }; OBJ_10 /* AnyCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCoordinator.swift; sourceTree = ""; }; OBJ_100 /* ConcurrentDispatchQueueScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentDispatchQueueScheduler.swift; sourceTree = ""; }; OBJ_101 /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentMainScheduler.swift; sourceTree = ""; }; @@ -883,6 +885,7 @@ OBJ_32 /* SplitTransition.swift */, OBJ_33 /* StaticTransitionAnimation.swift */, OBJ_34 /* StrongRouter.swift */, + 9B6E0D0523F5BBD100694FA3 /* CoordinatorContextMenuInteractionDelegate.swift */, OBJ_35 /* TabBarAnimationDelegate.swift */, OBJ_36 /* TabBarCoordinator.swift */, OBJ_37 /* TabBarTransition.swift */, @@ -1294,6 +1297,7 @@ OBJ_448 /* UnownedErased.swift in Sources */, OBJ_449 /* ViewCoordinator.swift in Sources */, OBJ_450 /* WeakErased+Router.swift in Sources */, + 9B6E0D0623F5BBD100694FA3 /* CoordinatorContextMenuInteractionDelegate.swift in Sources */, OBJ_451 /* WeakErased.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0;