Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
e4202d5853
commit
8e91eed772
1
PRD.md
1
PRD.md
@ -435,7 +435,6 @@ TheNoiseClock/
|
|||||||
│ │ │ ├── ClockDisplayContainer.swift
|
│ │ │ ├── ClockDisplayContainer.swift
|
||||||
│ │ │ ├── ClockOverlayContainer.swift
|
│ │ │ ├── ClockOverlayContainer.swift
|
||||||
│ │ │ ├── ClockGestureHandler.swift
|
│ │ │ ├── ClockGestureHandler.swift
|
||||||
│ │ │ ├── ClockTabBarManager.swift
|
|
||||||
│ │ │ ├── ClockToolbar.swift
|
│ │ │ ├── ClockToolbar.swift
|
||||||
│ │ │ ├── FullScreenHintView.swift
|
│ │ │ ├── FullScreenHintView.swift
|
||||||
│ │ │ └── Settings/
|
│ │ │ └── Settings/
|
||||||
|
|||||||
@ -35,6 +35,14 @@ struct ContentView: View {
|
|||||||
@State private var onboardingState = OnboardingState(appIdentifier: "TheNoiseClock")
|
@State private var onboardingState = OnboardingState(appIdentifier: "TheNoiseClock")
|
||||||
@State private var keepAwakePromptState = KeepAwakePromptState()
|
@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
|
// MARK: - Body
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -51,10 +59,6 @@ struct ContentView: View {
|
|||||||
|
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
AlarmView(viewModel: alarmViewModel)
|
AlarmView(viewModel: alarmViewModel)
|
||||||
.toolbar(.visible, for: .tabBar)
|
|
||||||
.onAppear {
|
|
||||||
Design.debugLog("[AlarmView] onAppear - forcing tabBar visible")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Alarms", systemImage: "alarm")
|
Label("Alarms", systemImage: "alarm")
|
||||||
@ -63,10 +67,6 @@ struct ContentView: View {
|
|||||||
|
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
NoiseView()
|
NoiseView()
|
||||||
.toolbar(.visible, for: .tabBar)
|
|
||||||
.onAppear {
|
|
||||||
Design.debugLog("[NoiseView] onAppear - forcing tabBar visible")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Noise", systemImage: "waveform")
|
Label("Noise", systemImage: "waveform")
|
||||||
@ -83,23 +83,27 @@ struct ContentView: View {
|
|||||||
onboardingState.reset()
|
onboardingState.reset()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.toolbar(.visible, for: .tabBar)
|
|
||||||
.onAppear {
|
|
||||||
Design.debugLog("[ClockSettingsView] onAppear - forcing tabBar visible")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Settings", systemImage: "gearshape")
|
Label("Settings", systemImage: "gearshape")
|
||||||
}
|
}
|
||||||
.tag(Tab.settings)
|
.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
|
.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 {
|
if oldValue == .clock && newValue != .clock {
|
||||||
Design.debugLog("[ContentView] Leaving clock tab, setting displayMode to false")
|
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)
|
clockViewModel.setDisplayMode(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onChange(of: clockViewModel.isDisplayMode) { oldValue, newValue in
|
||||||
|
Design.debugLog("[ContentView] isDisplayMode changed: \(oldValue) -> \(newValue), selectedTab: \(selectedTab), shouldHideTabBar: \(shouldHideTabBar)")
|
||||||
|
}
|
||||||
.accentColor(AppAccent.primary)
|
.accentColor(AppAccent.primary)
|
||||||
.background(Color.Branding.primary.ignoresSafeArea())
|
.background(Color.Branding.primary.ignoresSafeArea())
|
||||||
.fullScreenCover(item: activeAlarmBinding) { alarm in
|
.fullScreenCover(item: activeAlarmBinding) { alarm in
|
||||||
|
|||||||
@ -79,10 +79,7 @@ struct ClockView: View {
|
|||||||
.ignoresSafeArea() // Extend GeometryReader to full screen, we handle safe areas manually
|
.ignoresSafeArea() // Extend GeometryReader to full screen, we handle safe areas manually
|
||||||
.toolbar(.hidden, for: .navigationBar)
|
.toolbar(.hidden, for: .navigationBar)
|
||||||
.statusBarHidden(true)
|
.statusBarHidden(true)
|
||||||
.overlay {
|
// Tab bar visibility is now controlled at ContentView level to prevent race conditions
|
||||||
// Tab bar management overlay
|
|
||||||
ClockTabBarManager(isDisplayMode: viewModel.isDisplayMode)
|
|
||||||
}
|
|
||||||
.simultaneousGesture(
|
.simultaneousGesture(
|
||||||
DragGesture(minimumDistance: 0)
|
DragGesture(minimumDistance: 0)
|
||||||
.onChanged { _ in
|
.onChanged { _ in
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user