New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to change root view controller using LoginInterceptor and then continue navigation #82
Comments
I forgot to add that i would like the destination to open from either the circle view controller or from anywhere the user is currently on (and logged in) |
Thank you for the question. I am not able to reply right now as I am not by the computer. Ill try to answer your question asap. |
Thank you,
There is no rush. I am just getting to know this framework, so it might be
I am trying to tackle this problem from the wrong angle. Let me know if you
need any additional clarification.
…On Thu, 2 Jun 2022 at 17:16, Eugene Kazaev ***@***.***> wrote:
@tadelv <https://github.com/tadelv>
Thank you for the question. I am not able to reply right now as I am not
by the computer. Ill try to answer your question asap.
—
Reply to this email directly, view it on GitHub
<#82 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAK35N7ECWIBQLZYPPOBPLVNDF4XANCNFSM5XVDYT5A>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
@ekazaev I think I have found a way to do it. Find the diff below. Is this the right way to go about it? index 12d2bee8..51e6887a 100644
--- a/Example/RouteComposer/Configuration/ExampleConfiguration.swift
+++ b/Example/RouteComposer/Configuration/ExampleConfiguration.swift
@@ -78,6 +78,7 @@ extension ExampleScreenConfiguration {
StepAssembly(
finder: ColorViewControllerFinder(),
factory: ColorViewControllerFactory())
+ .adding(LoginInterceptor<String>())
.adding(DismissalMethodProvidingContextTask(dismissalBlock: { context, animated, completion in
// Demonstrates ability to provide a dismissal method in the configuration using `DismissalMethodProvidingContextTask`
UIViewController.router.commitNavigation(to: GeneralStep.custom(using: PresentingFinder()), with: context, animated: animated, completion: completion)
@@ -86,7 +87,16 @@ extension ExampleScreenConfiguration {
.using(ExampleNavigationController.push())
.from(SingleContainerStep(finder: NilFinder(), factory: NavigationControllerFactory<ExampleNavigationController, String>()))
.using(GeneralAction.presentModally())
- .from(GeneralStep.current())
+ .from(SwitchAssembly<UIViewController, String>()
+ .addCase({ _ in
+ guard isLoggedIn == false else {
+ return nil
+ }
+ return circleScreen.unsafelyRewrapped()
+ })
+ .assemble(default: {
+ GeneralStep.current()
+ }))
.assemble()
} |
Hey @ekazaev, just pinging, are you still away from the computer? :) |
Hey. Sorry. I am on vacation. Will be back tomorrow 🥹 |
Ooops! Sorry for bothering you then 🙈
… On Jun 13, 2022, at 6:04 PM, Eugene Kazaev ***@***.***> wrote:
Hey. Sorry. I am on vacation. Will be back tomorrow 🥹
—
Reply to this email directly, view it on GitHub <#82 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAAK35PHM47ZFDZPMPHDAPTVO5LXZANCNFSM5XVDYT5A>.
You are receiving this because you were mentioned.
|
@tadelv Sorry for the delay. The problem here is that you can't change what router considers as a partialy build stack as correct from the interceptor. For example, if you are on HomePage as origin, you want to navigate somewhere but in the Interceptor you want to change the origin as well. I did not implement it as it will make the router logic to complex, hard to explain and hard to debug. But it is also a rare case as for the intermediate login full screen modal is usually used and then navigation continues. But if it is necessary, the GlobalInterceptorRouter wrapper can help you. You can add your interceptor to it and it will run an interceptror before the main router starts to work. Then only thing is you can not parse the configuration from that wrapper so youll have to mark all the contexts that require to have a login somehow. For example with an empty protocol Then you can write your global interceptor like
Or viceversa if most of the screens require login and only a few dont, mark them with a protocol Another way (complex as it is not provided by the library and requires coding) is to make your own wrapper to the
In this method you can save the configuration that was passed there. Run the configuration through the Another way is to make your configuration like you wrote it, but i think it may limit or make complex your configurations in the future. I would go with one of the solutions above. Hope I understood your question correctly. Please let me know. |
Hey @ekazaev thanks for taking the time to write this exhaustive answer. Let me see if I got it right: The global interceptors run before router decides which will be the originating (root) view controller? So this means, they can change the view controller hierarchy before origin VC is selected? Hope it makes sense. Let me know please if my assumptions regarding global interceptor are correct |
Just a quick update - I was able to get it to work the way you proposed, using a GlobalInterceptor and replacing the root view controller in there. index 31ddbf30..dda355c3 100644
--- a/Example/RouteComposer/Extensions/ViewController.swift
+++ b/Example/RouteComposer/Extensions/ViewController.swift
@@ -11,6 +11,8 @@ import os.log
import RouteComposer
import UIKit
+protocol RequiresLogin {}
+
extension UIViewController {
// This class is needed just for the test purposes
@@ -29,8 +31,53 @@ extension UIViewController {
}
}
+
+
+ private final class GlobalLoginInterceptor<C>: RoutingInterceptor {
+ typealias Context = C
+
+ func perform(with context: Context, completion: @escaping (RoutingResult) -> Void) {
+ guard context is RequiresLogin else {
+ completion(.success)
+ return
+ }
+ guard isLoggedIn == false else {
+ completion(.success)
+ return
+ }
+ let destination = LoginConfiguration.login()
+ do {
+ try UIViewController.router.navigate(to: destination) { routingResult in
+ guard routingResult.isSuccessful,
+ let viewController = ClassFinder<LoginViewController, Any?>().getViewController() else {
+ completion(.failure(RoutingError.compositionFailed(.init("LoginViewController was not found."))))
+ return
+ }
+
+
+ viewController.interceptorCompletionBlock = { result in
+ guard case .success = result else {
+ completion(result)
+ return
+ }
+ do {
+ try viewController.router.navigate(to: ExampleConfiguration().homeScreen, animated: false) { result in
+ completion(result)
+ }
+ } catch {
+ completion(.failure(error))
+ }
+ }
+ }
+ } catch {
+ completion(.failure(RoutingError.compositionFailed(.init("Could not present login view controller", underlyingError: error))))
+ }
+ }
+ }
+
static let router: Router = {
var defaultRouter = GlobalInterceptorRouter(router: FailingRouter(router: DefaultRouter()))
+ defaultRouter.addGlobal(GlobalLoginInterceptor<Any?>())
defaultRouter.addGlobal(TestInterceptor("Global interceptors start"))
defaultRouter.addGlobal(NavigationDelayingInterceptor(strategy: .wait))
defaultRouter.add(TestInterceptor("Router interceptors start"))``` |
@tadelv are you happy with the result? |
Hey @ekazaev, Good luck with all the weddings 😆 |
@tadelv Thank you. Ill close this issue then. Dont hesitate either to reopen it or to create a new one |
Hi!
I am trying to understand how to compose the navigation for the following case:
I've tried to navigate to home in the interceptor, but the subsequent navigation to destination fails, because landing was used for origin view controller.
Any ideas?
P.S.: I'm trying to do this in the example app with the ColorViewController. Here is the diff:
The text was updated successfully, but these errors were encountered: