Migrate from iOS 17 Observation to iOS 16-compatible Combine architecture.

Lower deployment target to iOS 16, replace @Observable with ObservableObject, add navigation and UI compatibility shims, and include login smoke UI tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-26 10:16:35 +08:00
parent c32a610ee0
commit 26f4d0e671
127 changed files with 2320 additions and 1465 deletions

View File

@ -6,13 +6,12 @@
//
import Foundation
import Observation
import Combine
@MainActor
@Observable
/// Tab ViewModel Tab
final class MainTabBadgeViewModel {
private(set) var pendingWriteOffCount: Int?
final class MainTabBadgeViewModel: ObservableObject {
@Published private(set) var pendingWriteOffCount: Int?
///
func refreshPendingWriteOffCount(api: OrderServing, scenicId: Int?, storeId: Int?) async {

View File

@ -32,11 +32,9 @@ struct MainTabsView: View {
/// TabView TabBar 便
private struct SystemMainTabsView: View {
@Environment(AppRouter.self) private var appRouter
@EnvironmentObject private var appRouter: AppRouter
var body: some View {
@Bindable var appRouter = appRouter
TabView(selection: $appRouter.selectedTab) {
ForEach(AppTab.allCases) { tab in
TabNavigationStackHost(tab: tab)
@ -49,12 +47,12 @@ private struct SystemMainTabsView: View {
/// TabBar Tab NavigationStack 访
private struct CustomMainTabsView: View {
@Environment(AccountContext.self) private var accountContext
@Environment(AppRouter.self) private var appRouter
@Environment(OrdersAPI.self) private var ordersAPI
@Environment(ToastCenter.self) private var toastCenter
@EnvironmentObject private var accountContext: AccountContext
@EnvironmentObject private var appRouter: AppRouter
@Environment(\.ordersAPI) private var ordersAPI
@EnvironmentObject private var toastCenter: ToastCenter
@State private var badgeViewModel = MainTabBadgeViewModel()
@StateObject private var badgeViewModel = MainTabBadgeViewModel()
@State private var showScanner = false
@State private var loadedTabs: Set<AppTab> = [.home]
@ -66,8 +64,6 @@ private struct CustomMainTabsView: View {
}
var body: some View {
@Bindable var appRouter = appRouter
ZStack {
ForEach(AppTab.allCases) { tab in
PreservedTabPage(
@ -102,15 +98,15 @@ private struct CustomMainTabsView: View {
loadedTabs.insert(appRouter.selectedTab)
await refreshOrderBadge()
}
.onChange(of: appRouter.selectedTab) { _, selectedTab in
.onChange(of: appRouter.selectedTab) { selectedTab in
loadedTabs.insert(selectedTab)
guard selectedTab == .orders else { return }
Task { await refreshOrderBadge() }
}
.onChange(of: accountContext.currentScenic?.id) { _, _ in
.onChange(of: accountContext.currentScenic?.id) { _ in
Task { await refreshOrderBadge() }
}
.onChange(of: accountContext.currentStore?.id) { _, _ in
.onChange(of: accountContext.currentStore?.id) { _ in
Task { await refreshOrderBadge() }
}
}
@ -127,7 +123,7 @@ private struct CustomMainTabsView: View {
/// TabBar Tab TabBar
private struct CustomTabNavigationStackHost: View {
@Environment(AppRouter.self) private var appRouter
@EnvironmentObject private var appRouter: AppRouter
let tab: AppTab
@Binding var selectedTab: AppTab
@ -153,13 +149,13 @@ private struct CustomTabNavigationStackHost: View {
.toolbar(route.hidesTabBarWhenPushed ? .hidden : .visible, for: .tabBar)
}
}
.environment(appRouter.router(for: tab))
.environmentObject(appRouter.router(for: tab))
}
}
/// Tab TabBar
private struct TabNavigationStackHost: View {
@Environment(AppRouter.self) private var appRouter
@EnvironmentObject private var appRouter: AppRouter
let tab: AppTab
@ -172,7 +168,7 @@ private struct TabNavigationStackHost: View {
.toolbar(route.hidesTabBarWhenPushed ? .hidden : .visible, for: .tabBar)
}
}
.environment(appRouter.router(for: tab))
.environmentObject(appRouter.router(for: tab))
}
}
@ -197,8 +193,8 @@ private struct PreservedTabPage<Content: View>: View {
#Preview {
MainTabsView()
.environment(AppRouter())
.environment(AccountContext())
.environment(OrdersAPI(client: APIClient()))
.environment(ToastCenter())
.environmentObject(AppRouter())
.environmentObject(AccountContext())
.environment(\.ordersAPI, OrdersAPI(client: APIClient()))
.environmentObject(ToastCenter())
}

View File

@ -37,7 +37,7 @@ struct ProfileRootView: View {
/// Tab
private struct PlaceholderTabRootView: View {
@Environment(RouterPath.self) private var router
@EnvironmentObject private var router: RouterPath
let title: String
let systemImage: String