Skip to content

[feat]: Add support for automatic ViewEnvironment bridging in WorkflowUI #211

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

Merged
merged 14 commits into from
May 31, 2023

Conversation

n8chur
Copy link
Collaborator

@n8chur n8chur commented May 11, 2023

Note: This PR is targeting the feature/viewenvironmentui branch and depends on #205.

Overview

This PR adds deep integration of ViewEnvironmentUI to WorkflowUI. This deep integration makes working with contexts that need to bridge between both systems much easier. For example, applications that have not fully adopted Workflow but utilize the ViewEnvironment for theme propagation via ViewEnvironmentUI (as is true in Square's ios-register codebase).

This PR is part of the larger effort to add support for automatic ViewEnvironment bridging between UIKit propagation and WorkflowUI propagation within WorkflowUI.

See the associated proposal for more information.

Changes

This PR integrates ViewEnvironmentUI vanilla UIKit ViewEnvironment propagation support into WorkflowUI. This includes:

  • Automatic bridging of the ViewEnvironment from UIViewController propagation into Screen's ViewEnvironment within WorkflowHostingController.
  • Automatic bridging of the ViewEnvironment from Screen's ViewEnvironment into UIViewController propagation within ViewControllerDescription.

With these new features came some minor API adjustments:

  • ViewControllerDescription now takes in a ViewEnvironment as a parameter. This environment is added into an ancestor propagation node above the described view controller so that it can be served to any UIViewController ViewEnvironment queries (performed via ViewEnvironmentUI's propagation system).
  • WorkflowHostingController now takes a customizeEnvironment closure instead of a rootViewEnvironment. This makes it possible to configure environment properties as the ViewEnvironment is bridged into the Screen hierarchy without fully overwriting the entire ViewEnvironment.
  • ScreenViewController no longer takes an environment in its update(...) function. The Environment is now managed by the ViewControllerDescription for the Screen that it's backing. The environment parameter is still present in the initializer for ScreenViewController as it can be convenient to have valid environment state before the ancestor propagation node is configured above it (which is configured after initialization completes).

Square Integration PRs

https://github.com/squareup/market/pull/6224
https://github.com/squareup/ios-register/pull/85648

Checklist

  • Unit Tests
  • UI Tests
  • Snapshot Tests (iOS only)
  • I have made corresponding changes to the documentation

@n8chur n8chur force-pushed the westin/viewenvironmentui-auto-bridge branch 2 times, most recently from 9ce7fc5 to febb569 Compare May 16, 2023 20:18
@n8chur n8chur changed the title [DNR WIP] [feat] Add support for automatic ViewEnvironment bridging in WorkflowUI [feat] Add support for automatic ViewEnvironment bridging in WorkflowUI May 16, 2023
@n8chur n8chur mentioned this pull request May 16, 2023
4 tasks
@n8chur n8chur force-pushed the westin/viewenvironmentui-auto-bridge branch 3 times, most recently from 21936dc to 8f096c2 Compare May 18, 2023 17:16
@n8chur n8chur changed the title [feat] Add support for automatic ViewEnvironment bridging in WorkflowUI [feat]: Add support for automatic ViewEnvironment bridging in WorkflowUI May 18, 2023
@@ -42,11 +44,11 @@ open class ScreenViewController<ScreenType: Screen>: UIViewController {
return ScreenType.self
}

public private(set) final var environment: ViewEnvironment
private var previousEnvironment: ViewEnvironment
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to store this at all? I don't see it being used

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's being used in update(screen:) below.

@n8chur n8chur force-pushed the westin/viewenvironmentui-auto-bridge branch from 8f096c2 to 0f8083a Compare May 18, 2023 22:44
Base automatically changed from westin/viewenvironmentui to feature/viewenvironmentui May 18, 2023 22:58
@n8chur n8chur force-pushed the westin/viewenvironmentui-auto-bridge branch from 0f8083a to 34595b1 Compare May 18, 2023 23:02
Copy link
Collaborator

@watt watt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly bikesheds 👍

super.viewWillLayoutSubviews()
applyEnvironmentIfNeeded()
}

override public func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
rootViewController.view.frame = view.bounds
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated but we should move this to viewWillLayoutSubviews

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fairly confident we should but I was nervous to make this change as part of this work.

Let me know if you think it's worth doing now!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, it's less risky to isolate that to a separate change. Just wanted to flag it.

@@ -42,11 +44,11 @@ open class ScreenViewController<ScreenType: Screen>: UIViewController {
return ScreenType.self
}

public private(set) final var environment: ViewEnvironment
private var previousEnvironment: ViewEnvironment
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bikeshed: lastEnvironment or latestEnvironment? It's not exactly "previous" until an update happens.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already built into the public API as previousEnvironment in screenDidChange(from:,previousEnvironment:). I'd rather not change the public API and I think it's nice that this variable name matches the public API parameter it's it exists to support.

That being said, I don't feel super strongly! Let me know if you do.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already built into the public API as previousEnvironment in screenDidChange(from:,previousEnvironment:). I'd rather not change the public API and I think it's nice that this variable name matches the public API parameter it's it exists to support.

OK, so, my reasoning is that it's not the "previous" environment while it's being stored — it becomes the previous one during an update, when we read a new environment to replace it. Until then, it's just the latest one we observed. Not a big deal though.

Comment on lines 165 to 167
// We must nil this out first or we'll hit an assertion which protects against overriding the ancestor when
// some other system has already attempted to provide an override.
viewController.environmentAncestorOverride = nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could make PropagationNode a class and update the same instance. I'm not sure if there's a performance concern to updating the override on every render due to the associated object.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is an optimization I was talking through with @bencochran. You think it's worth doing now?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think I'd lean towards just doing it now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please re-review if/when you have time 🙏

@n8chur n8chur marked this pull request as ready for review May 22, 2023 17:12
@n8chur n8chur requested review from a team as code owners May 22, 2023 17:12
import Workflow

/// Drives view controllers from a root Workflow.
public final class WorkflowHostingController<ScreenType, Output>: UIViewController where ScreenType: Screen {
public typealias CustomizeEnvironment = (inout ViewEnvironment) -> Void
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this alias be nested under the generic parent type? the fully-specified spelling will be parametrized by the screen/output, which might be unwieldy. then again, maybe nobody will need to reference it in that manner?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'd be surprised if we ever seen folks referencing the type directly in the context of WorkflowHostingController usage.

I can move it out if we'd prefer though! There are a few opportunities in Market to re-use this type if it was at the top level. Let me know if you'd prefer we do move it out, and if so, what to name it/where to put it!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

your call to relocate/rename if you think it makes sense – just a thought!

@n8chur n8chur merged commit f52fe53 into feature/viewenvironmentui May 31, 2023
@n8chur n8chur deleted the westin/viewenvironmentui-auto-bridge branch May 31, 2023 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants