import SwiftUI /// The main application entry point for the Ancient Prophecy Tab Bars app. /// /// This app demonstrates a custom tab bar implementation with an overlay menu system. /// Specifically the implementation of a separate tab bar option now available in iOS 26. /// The app automatically exits when the main content view disappears and uses a fixed content size window. @main struct AncientProphecyTabBarsApp: App { var body: some Scene { WindowGroup { ContentView() .onDisappear { // Exit the app when the content view disappears exit(0) } } // Set window to resize based on content size only .windowResizability(.contentSize) } } // MARK: - Custom Tab Enum /// Represents the available tabs in the custom tab bar interface. /// /// Each tab case provides its own title, SF Symbol, and unique identifier. /// The enum conforms to multiple protocols to support SwiftUI's TabView and ForEach requirements. enum CustomTab: Int, Equatable, Hashable, Identifiable, CaseIterable { case watchNow case library case new case favorites case share /// Unique identifier for each tab case. /// /// Uses the raw integer value as the identifier for Identifiable conformance. var id: Int { rawValue } /// Localized display title for each tab. /// /// Returns the appropriate localized string for display in the tab bar. var title: String { switch self { case .watchNow: return String(localized: "Watch Now", comment: "Tab title for immediate content viewing") case .library: return String(localized: "Library", comment: "Tab title for content library") case .new: return String(localized: "New", comment: "Tab title for new content discovery") case .favorites: return String(localized: "Favorites", comment: "Tab title for favorited content") case .share: return String(localized: "share", comment: "Tab title for sharing functionality") } } /// SF Symbol name for each tab's icon. /// /// Returns the appropriate SF Symbol string for display in the tab bar. var symbol: String { switch self { case .watchNow: return "tv.fill" case .library: return "play.square.stack.fill" case .new: return "video.fill.badge.plus" case .favorites: return "heart.fill" case .share: return "square.and.arrow.up.fill" } } /// Creates a view representation for the specified tab's content area. /// /// This static method generates a consistent layout for all tab content views, /// displaying the tab's icon and title in a vertical stack. /// /// - Parameter tab: The tab case to create a view for /// - Returns: A SwiftUI view containing the tab's icon and title @ViewBuilder static func makeTabView(for tab: CustomTab) -> some View { if tab == .library { ScrollView { LazyVStack(alignment: .leading, spacing: 12) { ForEach(0 ..< 100, id: \.self) { _ in HStack { Text(UUID().uuidString.prefix(18)) .padding() Spacer() Image(systemName: "play.circle") .padding() } } } .padding(.vertical) } } else { VStack(spacing: 25) { // Display the tab's SF Symbol icon Image(systemName: tab.symbol) .font(.largeTitle) // Display the tab's localized title Text(tab.title) .font(.title) } } } } // MARK: - ContentView /// The main content view that implements a custom tab bar with overlay menu functionality. /// /// This view creates a TabView with custom tabs and implements a special overlay menu /// that appears when the share tab is selected. The overlay menu provides additional /// options without actually navigating to a share tab. @available(iOS 26, *) struct ContentView: View { // MARK: - Properties /// Array of all available tabs for the tab bar let tabs: [CustomTab] = CustomTab.allCases /// The currently selected tab in the tab bar /// /// This state property tracks which tab is currently active and updates the UI accordingly. @State private var selectedTab: CustomTab = .watchNow /// Controls the visibility of the overlay menu /// /// When true, displays the overlay menu with additional options. /// This is triggered when the share tab is selected. @State private var showOverlay: Bool = false // MARK: - Body var body: some View { ZStack { // MARK: - Main Tab View TabView(selection: $selectedTab) { ForEach(tabs) { tab in Tab(value: tab, role: tab == CustomTab.share ? .search : .none) { // Display the content view for each tab ZStack { CustomTab.makeTabView(for: tab) } } label: { // Tab bar item with icon and title Image(systemName: tab.symbol) Text(tab.title) } } } .tint(Color(uiColor: .systemPink)) // Custom tint color for the tab bar .tabBarMinimizeBehavior(.onScrollDown) // Hide tab bar when scrolling down .onChange(of: selectedTab) { oldValue, newValue in // Handle share tab selection by showing overlay instead of navigating if newValue == .share { showOverlay = true // Revert to previous tab selection to prevent actual navigation selectedTab = oldValue } } // MARK: - Overlay Menu if showOverlay { // Semi-transparent background overlay Color.black.opacity(0.0001) .ignoresSafeArea() .transition(.opacity) .onTapGesture { // Dismiss overlay when tapping outside the menu withAnimation(.bouncy) { showOverlay = false } } // MARK: - Menu Content GeometryReader { proxy in VStack { Spacer() HStack { Spacer() // Menu container with options VStack(alignment: .leading, spacing: 0) { // Menu header Text("Some Options") .font(.headline) .fontWeight(.bold) .foregroundStyle(.primary) .padding() Divider() // First menu option Button { // Handle first option selection // TODO: Implement actual functionality withAnimation { showOverlay = false } } label: { VStack(alignment: .leading) { Text("Button Option 1") .font(.headline) .fontWeight(.medium) .foregroundStyle(.primary) Text("Subtitle option 1") .font(.caption) .foregroundStyle(.secondary) } .padding() } .buttonStyle(.plain) Divider() // Second menu option Button { // Handle second option selection // TODO: Implement actual functionality withAnimation { showOverlay = false } } label: { VStack(alignment: .leading) { Text("Button Option 2") .font(.headline) .fontWeight(.medium) .foregroundStyle(.primary) Text("Subtitle option 2") .font(.caption) .foregroundStyle(.secondary) } .padding() } .buttonStyle(.plain) } .background(.ultraThinMaterial) // Translucent background material .frame(width: proxy.size.width * 0.5) // Responsive width .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous)) .padding(.horizontal, 24) .padding(.bottom, 60) // Account for tab bar height .shadow(radius: 2) // Subtle shadow for depth .transition(.move(edge: .bottom).combined(with: .opacity)) } } } .animation(.bouncy, value: showOverlay) // Bouncy animation for menu appearance } } } }