import SwiftUI struct MainView: View { @Environment(AppState.self) private var appState @Environment(\.horizontalSizeClass) private var sizeClass var body: some View { if let session = appState.session { if sizeClass == .regular { iPadMainView(session: session) } else { iPhoneMainView(session: session) } } else { ServerListView() } } } // MARK: - iPhone layout: TabView private struct iPhoneMainView: View { let session: SessionState var body: some View { TabView { ChannelBrowserView(session: session) .voiceControlsBar(session) .tabItem { Label("Channels", systemImage: "list.bullet.indent") } ChatView(session: session) .voiceControlsBar(session) .tabItem { Label("Chat", systemImage: "message") } SettingsView(session: session) .voiceControlsBar(session) .tabItem { Label("Settings", systemImage: "gear") } } } } private extension View { /// Pin the shared voice controls just above the tab bar, *inside each tab's content area*. /// Applying this per-tab (rather than to the TabView itself) reserves layout space above /// the tab bar — keeping ChatView's compose box visible and cooperating with keyboard /// avoidance — without the bar covering the tab bar's buttons. func voiceControlsBar(_ session: SessionState) -> some View { safeAreaInset(edge: .bottom) { VoiceControlsView(session: session) } } } // MARK: - iPad layout: NavigationSplitView private struct iPadMainView: View { let session: SessionState @State private var columnVisibility = NavigationSplitViewVisibility.all var body: some View { NavigationSplitView(columnVisibility: $columnVisibility) { ChannelTreeView(session: session) .navigationTitle("Channels") } content: { UserListView(session: session) .navigationTitle("Users") } detail: { VStack(spacing: 0) { ChatView(session: session) VoiceControlsView(session: session) } .navigationTitle("Chat") } } }