110 lines
3.0 KiB
Swift
110 lines
3.0 KiB
Swift
//
|
||
// NavigationRouter.swift
|
||
// suixinkan
|
||
//
|
||
// Created by Codex on 2026/6/18.
|
||
//
|
||
|
||
import Foundation
|
||
|
||
/// 应用内可导航目标,承载各 Tab 内部的路由目的地。
|
||
enum AppRoute: Hashable {
|
||
case placeholder(title: String)
|
||
case home(HomeRoute)
|
||
case profile(ProfileRoute)
|
||
case orders(OrdersRoute)
|
||
|
||
/// 返回该路由通过 push 后是否隐藏底部 TabBar。
|
||
var hidesTabBarWhenPushed: Bool {
|
||
true
|
||
}
|
||
}
|
||
|
||
@MainActor
|
||
/// 单个导航栈的路径容器,用于保存某个 Tab 的导航历史。
|
||
final class RouterPath {
|
||
var onChange: (() -> Void)?
|
||
var path: [AppRoute] = [] { didSet { onChange?() } }
|
||
|
||
/// 将指定路由压入当前 Tab 的导航栈。
|
||
func navigate(to route: AppRoute) {
|
||
path.append(route)
|
||
}
|
||
|
||
/// 从当前 Tab 的导航栈弹出最后一级路由。
|
||
func navigateBack() {
|
||
guard !path.isEmpty else { return }
|
||
path.removeLast()
|
||
}
|
||
|
||
/// 清空当前 Tab 的导航栈。
|
||
func reset() {
|
||
path = []
|
||
}
|
||
}
|
||
|
||
@MainActor
|
||
/// 主导航状态中心,管理当前 Tab 和每个 Tab 独立的导航路径。
|
||
final class AppRouter {
|
||
var onChange: (() -> Void)?
|
||
var selectedTab: AppTab = .home { didSet { onChange?() } }
|
||
var selectedOrdersEntry: OrdersEntry = .storeOrders { didSet { onChange?() } }
|
||
private(set) var pendingOrderScanCode: String? { didSet { onChange?() } }
|
||
|
||
private let routers: [AppTab: RouterPath]
|
||
|
||
init() {
|
||
var builtRouters: [AppTab: RouterPath] = [:]
|
||
for tab in AppTab.allCases {
|
||
builtRouters[tab] = RouterPath()
|
||
}
|
||
routers = builtRouters
|
||
routers.values.forEach { router in
|
||
router.onChange = { [weak self] in
|
||
self?.onChange?()
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 获取指定 Tab 对应的路由路径容器。
|
||
func router(for tab: AppTab) -> RouterPath {
|
||
guard let router = routers[tab] else {
|
||
assertionFailure("Missing router path for tab: \(tab)")
|
||
return RouterPath()
|
||
}
|
||
return router
|
||
}
|
||
|
||
/// 切换到指定主 Tab。
|
||
func select(_ tab: AppTab) {
|
||
selectedTab = tab
|
||
}
|
||
|
||
/// 切换到订单 Tab,并指定订单内部子入口。
|
||
func selectOrders(entry: OrdersEntry) {
|
||
selectedOrdersEntry = entry
|
||
selectedTab = .orders
|
||
}
|
||
|
||
/// 切换到核销订单入口,并暂存全局扫码结果等待订单页消费。
|
||
func routeToOrderVerification(scannedCode: String) {
|
||
pendingOrderScanCode = scannedCode
|
||
selectOrders(entry: .verificationOrders)
|
||
}
|
||
|
||
/// 读取并清空待处理的全局扫码结果,确保同一次扫码只被处理一次。
|
||
func consumePendingOrderScanCode() -> String? {
|
||
let code = pendingOrderScanCode
|
||
pendingOrderScanCode = nil
|
||
return code
|
||
}
|
||
|
||
/// 重置主 Tab 选择和所有 Tab 的导航历史。
|
||
func reset() {
|
||
selectedTab = .home
|
||
selectedOrdersEntry = .storeOrders
|
||
pendingOrderScanCode = nil
|
||
routers.values.forEach { $0.reset() }
|
||
}
|
||
}
|