Mijick / NavigationView

Navigation made simple (SwiftUI)
MIT License
238 stars 9 forks source link

👋 push View with Environment and EnvironmentObject #10

Closed stodevCoding closed 12 months ago

stodevCoding commented 1 year ago

I've been racking my brain trying to figure out how to push a new view with environment modifiers in SwiftUI. So I was just wondering if it's possible, and if this usage is intended. Thank you for your work and your response.

FulcrumOne commented 1 year ago

Hey! Thanks for your kind words!

Well, this functionality wasn't intended indeed, but the library is still on very early stage, so I think it shouldn't be a problem to extend it in this direction.

And I must sorry you, but I'm a visualiser, so could you share please an example of functionality that you wanted to achieve?

Thanks and have a good day!

stodevCoding commented 1 year ago

Oh thanks for your quick feedback and yes of course, here's a little example:

import SwiftUI
import Combine
import Navigattie

struct FirstFlowScreen: NavigatableView {

    @Environment(SharedVariables.self) var shared

    @StateObject var navState = NavigationStateManager()

    var titleView: String
    var sharedFlowVM = BigFlowViewModel()

    var body: some View {

        NavigationStack(path: $navState.inventorySelectionPath) {
            ScrollView(showsIndicators: false){

                //Content
            }
            .navigationDestination(for: NavigationStateManager.self) { state in
                switch state {
                    case .goToView1: View1()
                        .environment(sharedFlowVM)
                        .environment(shared)
                        .environmentObject(navState)
                    case .goToView2: View2()
                        .environment(sharedFlowVM)
                        .environment(shared)
                        .environmentObject(navState)
                }
            }
        }
    }
}

Views depend on certain environment objects and are passed to it that way. And I'm wondering how to do this with Navigattie.

(I have another question that I'll do in another ticket ;) )

FulcrumOne commented 1 year ago

Hi, sorry for my late response, but I'm having a real crunch at work :)

Let's divide the problem you described into three parts:

  1. FirstFlowScreen If I have understood the purpose of this screen correctly, it should act like a RootView, which controls the entire flow inside the application.

  2. EnvironmentObject value Personally I try to avoid @EnvironmentObjects as much as I can, so if I were you I would consider using Singleton.

  3. .navigationDestination modifier By reimplementing 1 and 2, I think it's possible to avoid using that part of your code.

stodevCoding commented 1 year ago

Hi, It's okay, don't worry about it.

Yes, it's almost like that. Except that the Tabview contains several flows. (FirstFlowScreen, SecondFlowScreen, ThirdFlowScreen, etc). Each first screen of each flow should be the RootView of its own flow.

I can see the reasons for avoiding EnvironmentObjects. ;)

FulcrumOne commented 1 year ago

Oh, so let's call these flows app states. Every app state can contain can flows. The design I propose is as follows:

struct ScreenA: View {
    @ObservedObject private var stateStore: StateStore = .shared

    var body: some View {
        switch stateStore.appStatus {
            case .stateA, .stateB: View1()
            case .stateC: View2()
            case .stateD: View3()
            case .stateE: View4()
            case .stateF: View5()
        }
    }
}

States are controlled by stateStore that works like a ViewModel. To initialize the correct state, just add a modifier to this structure, which calls the method from your VM:

struct ScreenA: View {
    @ObservedObject private var stateStore: StateStore = .shared

    var body: some View {
        Group {
            switch stateStore.appStatus {
                case .stateA, .stateB: View1()
                case .stateC: View2()
                case .stateD: View3()
                case .stateE: View4()
                case .stateF: View5()
            }
        }
        .task(stateStore.refreshCredentials)
    }
}
stodevCoding commented 1 year ago

Thanks, I'll try it and let you know ;) good luck