Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2026-02-02 09:36:49 -06:00
parent e4202d5853
commit 8e91eed772
4 changed files with 18 additions and 52 deletions

1
PRD.md
View File

@ -435,7 +435,6 @@ TheNoiseClock/
│ │ │ ├── ClockDisplayContainer.swift
│ │ │ ├── ClockOverlayContainer.swift
│ │ │ ├── ClockGestureHandler.swift
│ │ │ ├── ClockTabBarManager.swift
│ │ │ ├── ClockToolbar.swift
│ │ │ ├── FullScreenHintView.swift
│ │ │ └── Settings/

View File

@ -35,6 +35,14 @@ struct ContentView: View {
@State private var onboardingState = OnboardingState(appIdentifier: "TheNoiseClock")
@State private var keepAwakePromptState = KeepAwakePromptState()
// MARK: - Computed Properties
/// Single source of truth for tab bar visibility - prevents race conditions
/// Tab bar is ONLY hidden when on clock tab AND in display mode
private var shouldHideTabBar: Bool {
selectedTab == .clock && clockViewModel.isDisplayMode
}
// MARK: - Body
var body: some View {
@ -51,10 +59,6 @@ struct ContentView: View {
NavigationStack {
AlarmView(viewModel: alarmViewModel)
.toolbar(.visible, for: .tabBar)
.onAppear {
Design.debugLog("[AlarmView] onAppear - forcing tabBar visible")
}
}
.tabItem {
Label("Alarms", systemImage: "alarm")
@ -63,10 +67,6 @@ struct ContentView: View {
NavigationStack {
NoiseView()
.toolbar(.visible, for: .tabBar)
.onAppear {
Design.debugLog("[NoiseView] onAppear - forcing tabBar visible")
}
}
.tabItem {
Label("Noise", systemImage: "waveform")
@ -83,23 +83,27 @@ struct ContentView: View {
onboardingState.reset()
}
)
.toolbar(.visible, for: .tabBar)
.onAppear {
Design.debugLog("[ClockSettingsView] onAppear - forcing tabBar visible")
}
}
.tabItem {
Label("Settings", systemImage: "gearshape")
}
.tag(Tab.settings)
}
// SINGLE source of truth for tab bar visibility at TabView level
// This eliminates race conditions from multiple views competing
.toolbar(shouldHideTabBar ? .hidden : .visible, for: .tabBar)
.onChange(of: selectedTab) { oldValue, newValue in
Design.debugLog("[ContentView] Tab changed: \(oldValue) -> \(newValue)")
Design.debugLog("[ContentView] Tab changed: \(oldValue) -> \(newValue), shouldHideTabBar: \(shouldHideTabBar)")
if oldValue == .clock && newValue != .clock {
Design.debugLog("[ContentView] Leaving clock tab, setting displayMode to false")
// Immediately disable display mode when leaving clock tab
// This is now a safety net - the computed property already handles visibility
clockViewModel.setDisplayMode(false)
}
}
.onChange(of: clockViewModel.isDisplayMode) { oldValue, newValue in
Design.debugLog("[ContentView] isDisplayMode changed: \(oldValue) -> \(newValue), selectedTab: \(selectedTab), shouldHideTabBar: \(shouldHideTabBar)")
}
.accentColor(AppAccent.primary)
.background(Color.Branding.primary.ignoresSafeArea())
.fullScreenCover(item: activeAlarmBinding) { alarm in

View File

@ -79,10 +79,7 @@ struct ClockView: View {
.ignoresSafeArea() // Extend GeometryReader to full screen, we handle safe areas manually
.toolbar(.hidden, for: .navigationBar)
.statusBarHidden(true)
.overlay {
// Tab bar management overlay
ClockTabBarManager(isDisplayMode: viewModel.isDisplayMode)
}
// Tab bar visibility is now controlled at ContentView level to prevent race conditions
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged { _ in

View File

@ -1,34 +0,0 @@
//
// ClockTabBarManager.swift
// TheNoiseClock
//
// Created by Matt Bruce on 9/8/25.
//
import SwiftUI
import Bedrock
/// Component that manages tab bar visibility for display mode
/// Uses SwiftUI's native toolbar hiding for proper iPad compatibility
struct ClockTabBarManager: View {
// MARK: - Properties
let isDisplayMode: Bool
// MARK: - Body
var body: some View {
EmptyView()
.toolbar(isDisplayMode ? .hidden : .automatic, for: .tabBar)
.onAppear {
Design.debugLog("[ClockTabBarManager] onAppear - isDisplayMode: \(isDisplayMode), tabBar: \(isDisplayMode ? "hidden" : "automatic")")
}
.onChange(of: isDisplayMode) { oldValue, newValue in
Design.debugLog("[ClockTabBarManager] isDisplayMode changed: \(oldValue) -> \(newValue), tabBar: \(newValue ? "hidden" : "automatic")")
}
}
}
// MARK: - Preview
#Preview {
ClockTabBarManager(isDisplayMode: false)
}