wwt / SwiftCurrent

A library for managing complex workflows in Swift

Home Page:https://wwt.github.io/SwiftCurrent/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Allow `thenProceed` in preview providers

Tyler-Keith-Thompson opened this issue · comments

Is your feature request related to a problem? Please describe.

I want to use previews to view my FlowRepresentable as it'll appear in a workflow, even if that's just a single item workflow. However, right now thenProceed is not available.

Describe the solution you'd like

Either make thenProceed globally available so we quit having one-off "I need it added" or add it to PreviewProvider.

Describe alternatives you've considered

I could write my own extension for this, but it should just work out of the box. Additionally, I suppose we could wrap thenProceed in some new protocol? However, I don't like the idea that I have to conform to a protocol just to define a workflow. There may be something to investigating resultBuilders in a future version of Swift where they allow those scoped functions. I've seen proposals about it, but for now I don't think we should go that route.

Even hacky workarounds are proving difficult

Screen Shot 2021-12-11 at 1 50 10 PM

For anybody who might also be stuck here's a horrible workaround:

struct HomeView_Previews: PreviewProvider {
    struct WF: View {
        var body: some View {
            WorkflowLauncher(isLaunched: .constant(true)) {
                thenProceed(with: HomeView.self)
                    .presentationType(.navigationLink)
            }.embedInNavigationView()
        }
    }

    static var previews: some View { WF() }
}

Closing because this is working and has been merged.

Please reopen. This was not merged to main. It isn't available for consumers because it was a breaking change

I'll reopen but I'm a little confused. I was able to see the ContentView in the SwiftUI sample rendering correctly while using the preview canvas. Unless you're saying that you can't write thenProceed in the previewprovider, but I'm not sure why that would be a thing we'd want to do. My impression was that you just put the view into the previewprovider and if that rendered then you're good.

TL;DR: We want this for several reasons

  • Our design philosophy leads us down this path
  • A FlowRepresentable may not have an obvious initializer outside of WorkflowLauncher depending on client set-ups
  • PreviewProviders are about seeing a view in context, workflows are context
  • It came from a real-world situation

Apologies, you made a statement about being a little confused and got a dissertation back, but context matters are words are hard.

I'll start by referencing our design philosophy. Having an API that doesn't work for a key and critical part of SwiftUI feels wrong. Even if our assumption is that people will use a containing view. The attempt to lock down thenProceed in general was probably a little misguided. It certainly came from a good place, we didn't want to pollute a global namespace. However, it came at too steep a cost of maintenance, which is why it's already extended on so many things.

This came from a real-world situation, as I tend to build with this library frequently. The idea was that a had a view, not ContentView but merely a portion of it, called HomeView. I wanted to have my preview reflect various places that HomeView could go. I really didn't want to open a simulator to test out animations between HomeView and as my Workflow dictated. This is where I ran into, what at the time, seemed like a silly limitation. PreviewProvider requires a static method, whereas thenProceed is an instance method on View, App, and Scene.

I wanted to pontificate on the purpose of preview providers. These aren't just about "show me my view" these are about "show me my view in context". This is why the canvas supports multiple previews. You can show your view in dark mode, in light mode, in an iPhone mini, in an iPhone Max Plus Super Duper Ultra High-Def. I'd argue that mature project might even abstract an expected set of previews for a variety of supported device configurations so that new contributions were checked against some reasonable subset of circumstances. Workflows are context of your view.

The standard SwiftUI examples are a little frustrating to me because they're inconsistent in their interpretation of responsibility. For example, a NavigationView example usually shows that an enclosing view declares a navigationTitle. It basically says "If I'm in a nav stack I should look like this". Whereas TabView examples are the opposite. They almost always have enclosing views ignorant of context and in the TabView declaration they add .tabItem contextually to views.

Regardless, if I want to see not a View containing a WorkflowLauncher but a FlowRepresentable in isolation as I develop I might wrap it in my preview provider so that it most accurately represents how it'll render elsewhere. This seems reasonable and logical, therefore is a thing we should support.

Hopefully that serves to clarify motivation and clear up confusion, even if it was long.

I think the part about showing a view in context and also showing a view in multiple states makes sense to me. I've only used previews to visual the design of things as well as show views within other views. The views within other views sounds like what you're talking about here, albeit with views inside of workflows so I think this is a reasonable ask.

I don't normally mind using the simulator or clicking the play button on the canvas, but I could imagine that being heavier in some cases.


It sounds like making thenProceed static is likely the way to go, but there might be a fancier way to achieve that as well.

It sounds like making thenProceed static is likely the way to go, but there might be a fancier way to achieve that as well.

We thought about that, but the PR actually just made it global. The issue was one of maintenance. This is then Nth thing that came up, there will certainly be an N+1 thing in the future. Rather than continually trying to keep up with Apple and lock it down, it felt better to just open it up.

#179 invalidates this issue as a thing. The new SwiftUI API lends itself much better to all use-cases.