Skip to content
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

Pipe Blueprint's environment through during layout and measurement by creating an environment of our own #225

Merged
merged 2 commits into from
Oct 29, 2020

Conversation

kyleve
Copy link
Collaborator

@kyleve kyleve commented Oct 27, 2020

This PR updates List to ensure that we pass BlueprintUI.Environment through to the inner blueprint views within each item and header/footer within the list. This is done by writing BlueprintUI.Environment into our own ListEnvironment – which is now piped through to each item and header/footer within the list, and then, we reach this into environment and pull out the bp environment within BlueprintItemContent and BlueprintHeaderFooterContent to continue to pass the values down.

@kyleve kyleve requested a review from kylebshr October 27, 2020 02:34
@kyleve kyleve marked this pull request as ready for review October 27, 2020 02:37
@kyleve kyleve changed the title [DRAFT] Pipe Blueprint's environment through during layout and measurement by creating an environment of our own Pipe Blueprint's environment through during layout and measurement by creating an environment of our own Oct 27, 2020
@kyleve kyleve requested a review from watt October 27, 2020 02:42
CHANGELOG.md Outdated Show resolved Hide resolved
@kyleve kyleve requested a review from zadr October 27, 2020 17:06
Copy link
Collaborator

@kylebshr kylebshr left a comment

Choose a reason for hiding this comment

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

High level thoughts/questions:

  • Do we need the env to also exist/get passed through in the ListableUI types? If you think it's useful I'm fine with it, but I'm not sure I see the utility of it?
  • If the answer to ^ is no, we don't need it, I don't think we should add a ListEnvironment type at all, and just pipe through the BP environment. We can add keys and use the BP environment to pass stuff down in BlueprintUILists

@kyleve
Copy link
Collaborator Author

kyleve commented Oct 27, 2020

I guess I'm not seeing how we'd get the Blueprint Environment down to each header and footer without some sort of environment-like thing in Listable – the data flow is:

  1. You make a List
  2. It goes into an outer BlueprintView
  3. Blueprint updates the inner ListView
  4. The inner ListView then renders cells by creating their inner BlueprintViews
  5. Those inner views need the outer view's environment when they're getting rendered – their lifetime is not known by the outer List.

The key part being there's an inner extra layer of blueprint views whose lifetime is not known or controlled by users of the List itself.

@kyleve
Copy link
Collaborator Author

kyleve commented Oct 27, 2020

(I do wonder if there's some way that we can / need to solve this more generally in blueprint at some point – eg this will also break for any nested BP views in Market itself; which is not good for when we let people inject custom content, or we want to leverage the environment ourselves... But that's a whole thing)

section += TestItemContent(wasCalled: callback)
}
}.adaptedEnvironment { env in
env[TestingKey.self] = true
Copy link
Collaborator

Choose a reason for hiding this comment

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

worth an XCTAssertTrue(env[TestingKey.self]) somewhere at the end of the test (similar to TestHeaderContent and TestItemContent)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Can you clarify what you mean here? I think this would only be testing Blueprint itself; since this is just a normal element.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I just missed that it was a plain mock element the first time around and asking from a place of "if we set a state in a test, should we assert that it was set anywhere?"

} else {
self.content = nil
}
}
}

var reuseCache : ReusableViewCache?
Copy link
Collaborator

Choose a reason for hiding this comment

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

when would the reuseCache be nil— if we init something instead of dequeuing it?

if so, something like precondition(reuseCache != nil, "must dequeue a Supplementary Container View") might make it clearer. definitely a nit, though

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Because these are UICollectionReusableView; the init method is called by UICollectionView – you can't customize it. Thus, using IUOs to make things explode if these properties haven't been injected, without having to unwrap it at every callsite.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added an inline comment to clarify this

/// }
/// }
/// ```
public struct ListEnvironment {
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe something like

public typealias ListEnvironment = BlueprintUI.Environment
public typealias ListEnvironmentKey = BlueprintUI.EnvironmentKey

for now? so you own the type but don't have to rebuild the world until you have a use-case to do so

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ListableUI itself doesnt depend on BlueprintUI, so, can't do that.

@zadr
Copy link
Collaborator

zadr commented Oct 27, 2020

(I do wonder if there's some way that we can / need to solve this more generally in blueprint at some point – eg this will also break for any nested BP views in Market itself; which is not good for when we let people inject custom content, or we want to leverage the environment ourselves... But that's a whole thing)

My naive expectation was that EnvironmentReader would keep going up some internal tree until it found an environment to use

So if the tree was

0. UIView
1. - AdaptedEnvironment
2. -- BlueprintElement
3. --- UIView
4. ---- BlueprintElement
5. ----- EnvironmentReader
6. ------ BlueprintElementtent

so instead of the EnvironmentReader at level 5 fizzling out at level 3 because it found a UIView, it would keep traversing the view hierarchy to see if any parent was a view backed by a BlueprintElement and could provide an Environment to use

but on second thought, going up the tree is likely messy implementation (e.g.: would it require the description view to have a back reference to any ElementContent in case it holds an Environment?) and definitely not as nice as explicitly propagating state down the tree

@kyleve
Copy link
Collaborator Author

kyleve commented Oct 27, 2020

(I do wonder if there's some way that we can / need to solve this more generally in blueprint at some point – eg this will also break for any nested BP views in Market itself; which is not good for when we let people inject custom content, or we want to leverage the environment ourselves... But that's a whole thing)

My naive expectation was that EnvironmentReader would keep going up some internal tree until it found an environment to use

So if the tree was

0. UIView
1. - AdaptedEnvironment
2. -- BlueprintElement
3. --- UIView
4. ---- BlueprintElement
5. ----- EnvironmentReader
6. ------ BlueprintElementtent

so instead of the EnvironmentReader at level 5 fizzling out at level 3 because it found a UIView, it would keep traversing the view hierarchy to see if any parent was a view backed by a BlueprintElement and could provide an Environment to use

but on second thought, going up the tree is likely messy implementation (e.g.: would it require the description view to have a back reference to any ElementContent in case it holds an Environment?) and definitely not as nice as explicitly propagating state down the tree

Yeah, this – and there's different layout and measurement passes; so you can't just pass it down or "reach up" to find the current status easily.

@zadr
Copy link
Collaborator

zadr commented Oct 27, 2020

Yeah, this – and there's different layout and measurement passes; so you can't just pass it down or "reach up" to find the current status easily.

Yeah, that makes a lot of sense, thanks.

I was thinking that the Environment is more independent of the layout/measurement passes so it might be okay. But now that you mention it, I can definitely see people wanting to store per-view information in an environment and propagate it down (e.g. the view size influencing size classes as you get further down the tree is super believable)

@kyleve kyleve force-pushed the kve/support-blueprint-env-passthrough branch from d90d494 to 213f94f Compare October 27, 2020 19:11
@kyleve
Copy link
Collaborator Author

kyleve commented Oct 29, 2020

@kylebshr any more thoughts here? I can set up some time to run thorough why this is needed (I think?) which might be easier than going back and forth here

@kylebshr
Copy link
Collaborator

I didn't realize at first that it had to pass through ListableUI, so needs it's own environment to not depend on BlueprintUI - makes sense now!

@kyleve kyleve merged commit 4d96646 into main Oct 29, 2020
@kyleve kyleve deleted the kve/support-blueprint-env-passthrough branch October 29, 2020 18:04
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.

3 participants