// // Swiftfin is subject to the terms of the Mozilla Public // License, v2.0. If a copy of the MPL was not distributed with this // file, you can obtain one at https://mozilla.org/MPL/2.0/. // // Copyright (c) 2025 Jellyfin & Jellyfin Contributors // import SwiftUI @MainActor final class TabCoordinator: ObservableObject { struct SelectedEvent { let isRoot: Bool let isRepeat: Bool } typealias TabData = ( item: TabItem, coordinator: NavigationCoordinator, publisher: TabItemSelectedPublisher ) @Published var selectedTabID: String! = nil { didSet { guard let tab = tabs.first(property: \.item.id, equalTo: selectedTabID) else { return } tab.publisher.send( .init( isRoot: tab.coordinator.path.isEmpty, isRepeat: oldValue == selectedTabID ) ) } } @Published var tabs: [TabData] = [] private let sessionManager: SessionManager init(sessionManager: SessionManager) { self.sessionManager = sessionManager refreshTabs() } func refreshTabs() { let newTabs = buildTabs() // Preserve navigation coordinators for existing tabs let preservedTabs = newTabs.map { newTab in if let existingTab = tabs.first(where: { $0.item.id == newTab.id }) { return (newTab, existingTab.coordinator, existingTab.publisher) } else { let coordinator = NavigationCoordinator() let publisher = TabItemSelectedPublisher() return (newTab, coordinator, publisher) } } tabs = preservedTabs // Reset selected tab if it no longer exists if let selectedID = selectedTabID, !tabs.contains(where: { $0.item.id == selectedID }) { selectedTabID = tabs.first?.item.id } } private func buildTabs() -> [TabItem] { var tabItems: [TabItem] = [] // Add Jellyfin tabs if JF session is active if sessionManager.hasJellyfinProvider { #if os(iOS) tabItems.append(TabItem.home) tabItems.append(TabItem.search) tabItems.append(TabItem.media) #else tabItems.append(TabItem.home) tabItems.append(TabItem.library( title: L10n.tvShows, systemName: "tv", filters: .init(itemTypes: [.series]) )) tabItems.append(TabItem.library( title: L10n.movies, systemName: "film", filters: .init(itemTypes: [.movie]) )) tabItems.append(TabItem.search) tabItems.append(TabItem.media) #endif } // Add Xtream tab if XC session is active if sessionManager.hasXtreamProvider { tabItems.append(TabItem.xtream) } // Always add settings on tvOS (if JF is active) #if !os(iOS) if sessionManager.hasJellyfinProvider { tabItems.append(TabItem.settings) } #endif return tabItems } }