diff --git a/TheNoiseClock/Features/Clock/Views/Components/TimeDisplayView.swift b/TheNoiseClock/Features/Clock/Views/Components/TimeDisplayView.swift index 008bf7c..f46bafc 100644 --- a/TheNoiseClock/Features/Clock/Views/Components/TimeDisplayView.swift +++ b/TheNoiseClock/Features/Clock/Views/Components/TimeDisplayView.swift @@ -132,6 +132,7 @@ struct TimeDisplayView: View { TimeSegment(text: secondsText, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode) } } + .frame(maxWidth: .infinity) // Center horizontally in portrait } else { // Landscape mode - use fixed digit widths for stable layout // Each digit gets the same width (based on "8") so clock doesn't shift @@ -145,18 +146,19 @@ struct TimeDisplayView: View { HStack(alignment: .center, spacing: 0) { TimeSegment(text: hour, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode) - .frame(width: segmentWidth, height: containerSize.height) + .frame(width: segmentWidth) ColonView(dotDiameter: dotDiameter, spacing: dotSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight, isHorizontal: false) - .frame(width: dotDiameter, height: containerSize.height) + .frame(width: dotDiameter) TimeSegment(text: minute, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode) - .frame(width: segmentWidth, height: containerSize.height) + .frame(width: segmentWidth) if showSeconds { ColonView(dotDiameter: dotDiameter, spacing: dotSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight, isHorizontal: false) - .frame(width: dotDiameter, height: containerSize.height) + .frame(width: dotDiameter) TimeSegment(text: secondsText, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode) - .frame(width: segmentWidth, height: containerSize.height) + .frame(width: segmentWidth) } } + .frame(maxWidth: .infinity, maxHeight: .infinity) // Center in landscape } } .overlay(alignment: .bottomTrailing) { @@ -288,12 +290,32 @@ struct TimeDisplayView: View { } if !portrait { + // Verify colon height fits let dotDiameter = estimated * Layout.dotDiameterMultiplier let dotSpacing = estimated * Layout.dotSpacingLandscapeMultiplier let colonHeight = (dotDiameter * 2) + dotSpacing if colonHeight > containerSize.height { estimated *= containerSize.height / colonHeight } + + // CRITICAL: Verify total width fits to prevent clipping + // Calculate actual widths that will be used in layout + let actualDigitWidth = FontUtils.digitWidth( + fontName: fontFamily, + weight: fontWeight, + design: fontDesign, + fontSize: estimated + ) + let actualColonWidth = estimated * Layout.dotDiameterMultiplier + let segmentCount: CGFloat = showSeconds ? 3.0 : 2.0 + let totalWidth = (actualDigitWidth * 2 * segmentCount) + (colonCount * actualColonWidth) + + // If total width exceeds container, scale down + if totalWidth > containerSize.width { + let scaleFactor = containerSize.width / totalWidth + estimated *= scaleFactor * 0.98 // Add 2% margin + Design.debugLog("[clockLayout] width overflow: totalWidth=\(Int(totalWidth)) container=\(Int(containerSize.width)) scaling by \(String(format: "%.2f", scaleFactor))") + } } Design.debugLog("[clockLayout] calcFont estimatedFontSize=\(String(format: "%.1f", estimated))")