pointfreeco/swift-parsing

Value of type 'Parsers.Map<PathComponent, Tab>' has no member 'orElse'

BrunoCerberus opened this issue · 2 comments

I was just following this video https://www.pointfree.co/episodes/ep168-swiftui-navigation-the-point and got this problem

let deepLinker = PathComponent("one").map { Tab.one }
    .orElse(PathComponent("inventory").map { .inventory })
    .orElse(PathComponent("three").map { .three })

What should be the same equivalent for orElse?

I've found this lib provided by them as well, it works as a equivalent of previous implementation

I ended up using swift-url-routing as well. This is what I ended up with in case it's useful for anyone else.

ContentView.swift:

import SwiftUI
import URLRouting

enum InventoryRoute {
    case none
    case add(name: String, quantity: Int)
}

enum AppRoute {
    case one
    case inventory(InventoryRoute)
    case three
}

let inventoryRouter = OneOf {
    Route(.case(InventoryRoute.none))
    Route(.case(InventoryRoute.add(name:quantity:))) {
        Path { "add" }
        Query {
            Field("name", default: "New item")
            Field("quantity", default: 1) { Digits() }
        }
    }
}

let appRouter = OneOf {
    Route(.case(AppRoute.one)) {
        Path { "one" }
    }
    Route(.case(AppRoute.inventory)) {
        Path { "inventory" }
        inventoryRouter
    }
    Route(.case(AppRoute.three)) {
        Path { "three" }
    }
}

enum Tab {
    case one, inventory, three
}

class AppViewModel: ObservableObject {
    @Published var inventoryViewModel: InventoryViewModel
    @Published var selectedTab: Tab
    
    init(
        inventoryViewModel: InventoryViewModel = .init(),
        selectedTab: Tab = .one
    ) {
        self.inventoryViewModel = inventoryViewModel
        self.selectedTab = selectedTab
    }
    
    func open(url: URL) {
        do {
            switch try appRouter.match(url: url) {
            case .one:
                selectedTab = .one
                inventoryViewModel.route = nil
            case let .inventory(inventoryRoute):
                selectedTab = .inventory
                self.inventoryViewModel.navigate(to: inventoryRoute)
            case .three:
                selectedTab = .three
                inventoryViewModel.route = nil
            }
        } catch { }
    }
}

extension InventoryViewModel {
    func navigate(to route: InventoryRoute) {
        switch route {
        case .none:
            self.route = nil
        case let .add(name: name, quantity: quantity):
            self.route = .add(ItemViewModel(item: .init(name: name, status: .inStock(quantity: quantity))))
        }
    }
}

struct ContentView: View {
    @ObservedObject var viewModel: AppViewModel
    
    var body: some View {
        TabView(selection: $viewModel.selectedTab) {
            Button("Go to Inventory") {
                viewModel.selectedTab = .inventory
            }
            .tabItem { Text("One") }
            .tag(Tab.one)
            
            NavigationView {
                InventoryView(viewModel: viewModel.inventoryViewModel)
            }
            .tabItem { Text("Inventory") }
            .tag(Tab.inventory)
            
            Text("Three")
                .tabItem { Text("Three") }
                .tag(Tab.three)
        }
        .onOpenURL { url in
            viewModel.open(url: url)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(viewModel: .init())
    }
}