How to figure out what navigationpath you came from to append to it?

252 views Asked by At

I have several navigation paths using the same enum so that I'm able to clear that path and bring the user back to the main tab view for that item. This works great when I am using navigationLink(value: ) but there are times when I need to wait for data to load to navigate. So for those cases when I need to load data first and then navigate, I am using an onreceive from the view model. My question is how would I know what path to append this view to since I don't know how the user got to this view? They could have gotten here from any of my tab views. In the example, I append it to feedpath but that doesn't work if they got to this view from profilepath or any of the other paths.

class NavigationManager: ObservableObject {    
    @Published var feedPath = [FeedNavigation]()
    @Published var searchPath = [FeedNavigation]()
    @Published var libraryPath = [FeedNavigation]()
    @Published var profilePath = [FeedNavigation]()
}

enum FeedNavigation: Hashable, Codable {
    case profile(User)
    case bookPage(Book)
    case notification
    case chat
    case feedCell(Post)
    case chatView(User)
    case followView(User, Int)
}
struct ProfileView: View {

@EnvironmentObject var navigationManager: NavigationManager

var body: some View {
VStack {
    NavigationLink(value: FeedNavigation.profile(user)) {
        KFImage(URL(string: user.profileImageUrl ?? defaultPhoto))
            .resizable()
            .scaledToFill()
            .frame(width: 40, height: 40)
            .cornerRadius(6)
    }
    Button(action: {
        viewModel.fetchBookForList(book: book)
    }) {
        Text("Load data in view model")
    }
    
    .onReceive(viewModel.$googleBookFetched) { success in
        if success {
            if let book = viewModel.googleBook {
                navigationManager.feedPath.append(FeedNavigation.bookPage(book))
            }
        }
    }
    .navigationDestination(for: FeedNavigation.self) { state in
        switch state {
        case .profile(let user):
            ProfileView(user: user)
        case .bookPage(let book):
            BookPageView(viewModel: BookPageViewModel(book: book))
        case .notification:
            NotificationsView()
        case .chat:
            ConversationsView()
        case .feedCell(let post):
            ScrollView {
                FeedCell(viewModel: FeedCellViewModel(post: post))
            }
        case .chatView(let user):
            ChatView(viewModel: ChatViewModel(user: user))
        case .followView(let user, let followTab):
            FollowListView(viewModel: FollowListViewModel(user: user), followTab: followTab)
        }
    }
}
}
}
TabView(selection: $currentTab) {
    
    NavigationStack(path: $navigationManager.feedPath) {
        FeedView()
    }
    .tag(Tabs.feed)
    
    NavigationStack(path: $navigationManager.searchPath) {
        SearchView()
    }
    .tag(Tabs.search)
    
    NavigationStack(path: $navigationManager.libraryPath) {
        LibraryView()
    }
    .tag(Tabs.inbox)
    
    NavigationStack(path: $navigationManager.profilePath) {
        ProfileView(user: user)
    }
    .tag(Tabs.profile)
    
}
1

There are 1 answers

0
amelia On

This seems like a workaround but it's at least working. Still open to better answers if anyone has one.

I just added another path in my navigationManager to listen for which path is active, then in my view I choose the path I'm appending to based on which path is active.

// in navigation manager
@Published var activePath = [FeedNavigation]() {
    didSet {
        // Handle any additional logic when activePath changes
        print("Active Path updated: \(activePath)")
    }
}

@Published var feedPath = [FeedNavigation]() {
    didSet {
        activePath = feedPath
    }
}

@Published var searchPath = [FeedNavigation]() {
    didSet {
        activePath = searchPath
    }
}

@Published var libraryPath = [FeedNavigation]() {
    didSet {
        activePath = libraryPath
    }
}

@Published var profilePath = [FeedNavigation]() {
    didSet {
        activePath = profilePath
    }
}

// in view
if navigationManager.activePath == navigationManager.feedPath {
    navigationManager.feedPath.append(FeedNavigation.profile(user))
} else if navigationManager.activePath == navigationManager.libraryPath {
    navigationManager.libraryPath.append(FeedNavigation.profile(user))
} else if navigationManager.activePath == navigationManager.profilePath {
    navigationManager.profilePath.append(FeedNavigation.profile(user))
} else if navigationManager.activePath == navigationManager.searchPath {
    navigationManager.searchPath.append(FeedNavigation.profile(user))
}

}