diff --git a/suixinkan/App/Navigation/NavigationRouter.swift b/suixinkan/App/Navigation/NavigationRouter.swift index ce7d7fc..ca211a8 100644 --- a/suixinkan/App/Navigation/NavigationRouter.swift +++ b/suixinkan/App/Navigation/NavigationRouter.swift @@ -81,16 +81,22 @@ final class AppRouter: ObservableObject { @Published var selectedTab: AppTab = .home @Published var selectedOrdersEntry: OrdersEntry = .storeOrders @Published private(set) var pendingOrderScanCode: String? - @Published private var routers: [AppTab: RouterPath] = [:] + private let routers: [AppTab: RouterPath] - /// 获取指定 Tab 对应的路由路径容器,不存在时自动创建。 + init() { + routers = Dictionary( + uniqueKeysWithValues: AppTab.allCases.map { tab in + (tab, RouterPath()) + } + ) + } + + /// 获取指定 Tab 对应的路由路径容器。 func router(for tab: AppTab) -> RouterPath { - if let router = routers[tab] { - return router + guard let router = routers[tab] else { + assertionFailure("Missing router path for tab: \(tab)") + return RouterPath() } - - let router = RouterPath() - routers[tab] = router return router } diff --git a/suixinkan/Core/Design/AppContentUnavailableView.swift b/suixinkan/Core/Design/AppContentUnavailableView.swift index b1ccaa6..d4be0ed 100644 --- a/suixinkan/Core/Design/AppContentUnavailableView.swift +++ b/suixinkan/Core/Design/AppContentUnavailableView.swift @@ -7,7 +7,7 @@ import SwiftUI -/// iOS 16 兼容的空状态视图;iOS 17+ 自动使用系统 AppContentUnavailableView。 +/// iOS 16 兼容的空状态视图;iOS 17+ 自动使用系统 ContentUnavailableView。 struct AppContentUnavailableView: View { private let label: LabelContent private let description: DescriptionContent @@ -25,7 +25,7 @@ struct AppContentUnavailableView Self { - if application.state == .runningForeground { + if hasLaunched, application.state == .runningForeground { application.activate() } else { + if application.state != .notRunning { + application.terminate() + Thread.sleep(forTimeInterval: 0.5) + } application.launch() + hasLaunched = true } dismissSystemAlertsIfNeeded() if waitForLoading { @@ -72,12 +78,10 @@ final class SuixinkanApp { /// 判断主 Tab 是否已出现。 var isOnMainTabs: Bool { - TabBarNavigator.Tab.allCases.contains { tab in - let button = application.buttons.matching( - NSPredicate(format: "label == %@", tab.rawValue) - ).firstMatch - return button.waitForExistence(timeout: 1) - } + application.buttons[TabBarNavigator.Tab.home.identifier].exists + || application.buttons[TabBarNavigator.Tab.orders.identifier].exists + || application.buttons[TabBarNavigator.Tab.statistics.identifier].exists + || application.buttons[TabBarNavigator.Tab.profile.identifier].exists } /// 等待冷启动后进入登录页或主 Tab。 diff --git a/suixinkanUITests/Support/TabBarNavigator.swift b/suixinkanUITests/Support/TabBarNavigator.swift index be634b5..81b2aa6 100644 --- a/suixinkanUITests/Support/TabBarNavigator.swift +++ b/suixinkanUITests/Support/TabBarNavigator.swift @@ -14,6 +14,19 @@ enum TabBarNavigator { case orders = "订单" case statistics = "数据" case profile = "我的" + + var identifier: String { + switch self { + case .home: + return "main.tab.home" + case .orders: + return "main.tab.orders" + case .statistics: + return "main.tab.statistics" + case .profile: + return "main.tab.profile" + } + } } /// 切换到指定 Tab 并等待页面稳定。 @@ -26,6 +39,13 @@ enum TabBarNavigator { /// 在底部自定义 TabBar 中定位唯一可点击的 Tab 按钮。 private static func bottomTabButton(named title: String, in app: SuixinkanApp) -> XCUIElement { + if let tab = Tab(rawValue: title) { + let identifiedButton = app.application.buttons[tab.identifier] + if identifiedButton.exists { + return identifiedButton + } + } + let candidates = app.application.buttons.matching(NSPredicate(format: "label == %@", title)) let screenHeight = app.application.windows.element(boundBy: 0).frame.height var bestMatch: XCUIElement?