diff --git a/TablePro/Models/Query/QueryTab.swift b/TablePro/Models/Query/QueryTab.swift index 260a2573..65b6f4fc 100644 --- a/TablePro/Models/Query/QueryTab.swift +++ b/TablePro/Models/Query/QueryTab.swift @@ -561,19 +561,32 @@ struct QueryTab: Identifiable, Equatable { /// Manager for query tabs @MainActor @Observable final class QueryTabManager { - var tabs: [QueryTab] = [] + var tabs: [QueryTab] = [] { + didSet { _tabIndexMapDirty = true } + } + var selectedTabId: UUID? + @ObservationIgnored private var _tabIndexMap: [UUID: Int] = [:] + @ObservationIgnored private var _tabIndexMapDirty = true + + private func rebuildTabIndexMapIfNeeded() { + guard _tabIndexMapDirty else { return } + _tabIndexMap = Dictionary(uniqueKeysWithValues: tabs.enumerated().map { ($1.id, $0) }) + _tabIndexMapDirty = false + } + var tabIds: [UUID] { tabs.map(\.id) } var selectedTab: QueryTab? { - guard let id = selectedTabId else { return tabs.first } - return tabs.first { $0.id == id } + if let index = selectedTabIndex { return tabs[index] } + return selectedTabId == nil ? tabs.first : nil } var selectedTabIndex: Int? { guard let id = selectedTabId else { return nil } - return tabs.firstIndex { $0.id == id } + rebuildTabIndexMapIfNeeded() + return _tabIndexMap[id] } init() { diff --git a/TablePro/Views/Main/MainContentCoordinator.swift b/TablePro/Views/Main/MainContentCoordinator.swift index 44b93a6a..93af39e4 100644 --- a/TablePro/Views/Main/MainContentCoordinator.swift +++ b/TablePro/Views/Main/MainContentCoordinator.swift @@ -97,7 +97,7 @@ final class MainContentCoordinator { var needsLazyLoad = false /// Cache for async-sorted query tab rows (large datasets sorted on background thread) - private(set) var querySortCache: [UUID: QuerySortCacheEntry] = [:] + @ObservationIgnored private(set) var querySortCache: [UUID: QuerySortCacheEntry] = [:] // MARK: - Internal State @@ -134,7 +134,7 @@ final class MainContentCoordinator { /// True while a database switch is in progress. Guards against /// side-effect window creation during the switch cascade. - var isSwitchingDatabase = false + @ObservationIgnored var isSwitchingDatabase = false /// True once the coordinator's view has appeared (onAppear fired). /// Coordinators that SwiftUI creates during body re-evaluation but never