// // BrowserWindowView.swift // Zyquo Atlas // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // // The browser window root. Composes the chrome — tab strip (top-horizontal OR // left-vertical per the live layout), optional bookmarks bar, toolbar, find // bar, web content, and the AI sidebar — themed live by ThemeEngine and driven // by a per-window WindowState that the app commands target. Hosts the history, // bookmarks-manager, downloads, and customization panels. // import SwiftUI struct BrowserWindowView: View { @EnvironmentObject private var env: AppEnvironment @EnvironmentObject private var themeEngine: ThemeEngine @StateObject private var tabManager: TabManager @StateObject private var windowState = WindowState() private let profile: Profile init(profile: Profile = .defaultProfile) { self.profile = profile _tabManager = StateObject(wrappedValue: TabManager(profile: profile)) } private var theme: AtlasTheme { themeEngine.theme } private var layout: LayoutSettings { themeEngine.layout } var body: some View { Group { if layout.tabPosition == .left { HStack(spacing: 0) { VerticalTabBarView(tabManager: tabManager, onNewTab: { tabManager.newTab() }) mainColumn } } else { VStack(spacing: 0) { TabBarView(tabManager: tabManager) mainColumn } } } .background(theme.backgroundColor) .frame(minWidth: 900, minHeight: 600) .animation(.easeInOut(duration: 0.15), value: windowState.showAISidebar) .animation(.easeInOut(duration: 0.18), value: layout.tabPosition) .environmentObject(windowState) .focusedSceneValue(\.windowState, windowState) .onAppear { windowState.tabManager = tabManager windowState.env = env if tabManager.history == nil { tabManager.history = profile.isPrivate ? nil : env.history tabManager.restoreSessionOrOpenHome() } } .sheet(isPresented: $windowState.showCustomize) { CustomizationView().environmentObject(themeEngine) } .sheet(isPresented: $windowState.showHistory) { HistoryView(onOpen: { tabManager.newTab(url: URL(string: $0)) }) .environmentObject(env).environmentObject(themeEngine) } .sheet(isPresented: $windowState.showBookmarksManager) { BookmarksManagerView(onOpen: { tabManager.newTab(url: URL(string: $0)) }) .environmentObject(env).environmentObject(themeEngine) } } // MARK: - Main column (bookmarks bar + toolbar + content + AI sidebar) @ViewBuilder private var mainColumn: some View { if let tab = tabManager.activeTab { VStack(spacing: 0) { ToolbarView( tab: tab, isAISidebarOpen: windowState.showAISidebar, onSubmit: { tabManager.loadInActiveTab($0) }, onNewTab: { tabManager.newTab() }, onToggleAI: { windowState.showAISidebar.toggle() }, onCustomize: { windowState.showCustomize = true }, downloadCount: tabManager.downloads.items.filter { $0.state == .inProgress }.count, onToggleDownloads: { windowState.showDownloads.toggle() } ) if layout.showBookmarksBar && !profile.isPrivate { BookmarksBarView(onOpen: { tabManager.loadInActiveTab($0) }) } if windowState.showFindBar { FindBarView(tab: tab, onClose: { windowState.showFindBar = false }) } HStack(spacing: 0) { TabContentView( tab: tab, onNavigate: { tabManager.loadInActiveTab($0) }, onAsk: { windowState.showAISidebar = true } ) if windowState.showAISidebar { AISidebarView(tab: tab, ai: tab.ai, tabManager: tabManager) .transition(.move(edge: .trailing)) } } } .overlay(alignment: .topTrailing) { if windowState.showDownloads { DownloadsPopover(downloads: tabManager.downloads, onClose: { windowState.showDownloads = false }) .padding(.top, 4).padding(.trailing, 8) } } } else { Spacer() } } } /// The active tab's content region. Observes the tab so it switches reactively /// between the start page (blank/home), reader mode, and live web content as the /// URL changes — and overlays the selection toolbar on web pages. private struct TabContentView: View { @ObservedObject var tab: Tab let onNavigate: (String) -> Void let onAsk: () -> Void @EnvironmentObject private var windowState: WindowState var body: some View { if tab.url == nil || tab.url == TabManager.homeURL { StartPageView(onNavigate: onNavigate, onAsk: onAsk) } else if windowState.showReader { ReaderView(tab: tab) } else { WebContentArea(tab: tab) .overlay { SelectionToolbar(tab: tab) } } } } /// Hosts the active tab's web view. Keyed by tab id so SwiftUI re-mounts the /// correct WKWebView on a tab switch while background tabs keep theirs alive. private struct WebContentArea: View { @ObservedObject var tab: Tab var body: some View { WebView(tab: tab) .id(tab.id) } }