// // TabStore.swift // Prisme // // Author: Simon-Pierre Boucher // import Foundation import Observation /// Ordered collection of open tabs plus the active selection. /// Grouping by intention (P0) will layer on top of this later — the store /// itself stays a dumb, predictable list. @MainActor @Observable final class TabStore { private(set) var tabs: [Tab] = [] var activeTabID: Tab.ID? var activeTab: Tab? { guard let id = activeTabID else { return nil } return tabs.first { $0.id == id } } func tabs(in containerID: IdentityContainer.ID) -> [Tab] { tabs.filter { $0.containerID == containerID } } func mostRecentTab(in containerID: IdentityContainer.ID) -> Tab? { tabs(in: containerID).max { $0.lastActivatedAt < $1.lastActivatedAt } } @discardableResult func open(_ url: URL?, in containerID: IdentityContainer.ID, activate: Bool = true) -> Tab { let tab = Tab(initialURL: url, containerID: containerID) tabs.append(tab) if activate { self.activate(tab) } return tab } func activate(_ tab: Tab) { tab.lastActivatedAt = Date() activeTabID = tab.id } func close(_ tab: Tab) { guard let index = tabs.firstIndex(where: { $0.id == tab.id }) else { return } tabs.remove(at: index) guard activeTabID == tab.id else { return } // Prefer a neighbour from the same container, else none. let siblings = tabs(in: tab.containerID) activeTabID = siblings.last?.id } }