diff --git a/TheNoiseClock/Core/Utilities/FontUtils.swift b/TheNoiseClock/Core/Utilities/FontUtils.swift index df0f46e..3b464c4 100644 --- a/TheNoiseClock/Core/Utilities/FontUtils.swift +++ b/TheNoiseClock/Core/Utilities/FontUtils.swift @@ -44,19 +44,19 @@ enum FontUtils { if isPortrait { // In portrait, height is the limiting factor // Account for separators and spacing - let separatorHeight = availableHeight * 0.08 // 8% for separators (reduced) + let separatorHeight = availableHeight * 0.05 // 5% for separators (reduced further) let contentHeight = availableHeight - separatorHeight let estimatedLines = showSeconds ? 3 : 2 // HH, MM, SS or HH, MM let lineHeight = contentHeight / CGFloat(estimatedLines) - optimalSize = lineHeight * 0.85 // 85% of line height for actual text (increased) + optimalSize = lineHeight * 0.9 // 90% of line height for actual text (increased) } else { // In landscape, be more aggressive with space usage // Account for separators and spacing - let separatorWidth = availableWidth * 0.08 // 8% for separators (reduced) + let separatorWidth = availableWidth * 0.08 // 8% for separators (increased for safety) let contentWidth = availableWidth - separatorWidth let estimatedColumns = showSeconds ? 3 : 2 // HH, MM, SS or HH, MM let columnWidth = contentWidth / CGFloat(estimatedColumns) - optimalSize = columnWidth * 0.75 // 75% of column width for actual text (increased) + optimalSize = columnWidth * 0.75 // 75% of column width for actual text (reduced for safety) } // Apply reasonable bounds @@ -409,16 +409,16 @@ enum FontUtils { let optimalSize: CGFloat if isPortrait { // In portrait, use most of the available height - let contentHeight = availableHeight * 0.85 // Use 85% of available height + let contentHeight = availableHeight * 0.95 // Use 95% of available height (increased) let estimatedLines = showSeconds ? 3 : 2 let lineHeight = contentHeight / CGFloat(estimatedLines) - optimalSize = lineHeight * 0.8 // Use 80% of line height + optimalSize = lineHeight * 0.9 // Use 90% of line height (increased) } else { // In landscape, use most of the available width - let contentWidth = availableWidth * 0.85 // Use 85% of available width + let contentWidth = availableWidth * 0.90 // Use 90% of available width (reduced for safety) let estimatedColumns = showSeconds ? 3 : 2 let columnWidth = contentWidth / CGFloat(estimatedColumns) - optimalSize = columnWidth * 0.7 // Use 70% of column width + optimalSize = columnWidth * 0.75 // Use 75% of column width (reduced for safety) } // Apply reasonable bounds diff --git a/TheNoiseClock/Models/ClockStyle.swift b/TheNoiseClock/Models/ClockStyle.swift index e9597ea..e5ca04a 100644 --- a/TheNoiseClock/Models/ClockStyle.swift +++ b/TheNoiseClock/Models/ClockStyle.swift @@ -15,6 +15,7 @@ class ClockStyle: Codable, Equatable { // MARK: - Time Format Settings var use24Hour: Bool = true var showSeconds: Bool = false + var forceHorizontalMode: Bool = false // Force horizontal layout even in portrait // MARK: - Visual Settings var digitColorHex: String = AppConstants.Defaults.digitColorHex @@ -60,6 +61,7 @@ class ClockStyle: Codable, Equatable { private enum CodingKeys: String, CodingKey { case use24Hour case showSeconds + case forceHorizontalMode case digitColorHex case randomizeColor case glowIntensity @@ -97,6 +99,7 @@ class ClockStyle: Codable, Equatable { self.use24Hour = try container.decodeIfPresent(Bool.self, forKey: .use24Hour) ?? self.use24Hour self.showSeconds = try container.decodeIfPresent(Bool.self, forKey: .showSeconds) ?? self.showSeconds + self.forceHorizontalMode = try container.decodeIfPresent(Bool.self, forKey: .forceHorizontalMode) ?? self.forceHorizontalMode self.digitColorHex = try container.decodeIfPresent(String.self, forKey: .digitColorHex) ?? self.digitColorHex self.randomizeColor = try container.decodeIfPresent(Bool.self, forKey: .randomizeColor) ?? self.randomizeColor self.glowIntensity = try container.decodeIfPresent(Double.self, forKey: .glowIntensity) ?? self.glowIntensity @@ -129,6 +132,7 @@ class ClockStyle: Codable, Equatable { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(use24Hour, forKey: .use24Hour) try container.encode(showSeconds, forKey: .showSeconds) + try container.encode(forceHorizontalMode, forKey: .forceHorizontalMode) try container.encode(digitColorHex, forKey: .digitColorHex) try container.encode(randomizeColor, forKey: .randomizeColor) try container.encode(glowIntensity, forKey: .glowIntensity) @@ -405,6 +409,7 @@ class ClockStyle: Codable, Equatable { static func == (lhs: ClockStyle, rhs: ClockStyle) -> Bool { lhs.use24Hour == rhs.use24Hour && lhs.showSeconds == rhs.showSeconds && + lhs.forceHorizontalMode == rhs.forceHorizontalMode && lhs.digitColorHex == rhs.digitColorHex && lhs.randomizeColor == rhs.randomizeColor && lhs.glowIntensity == rhs.glowIntensity && diff --git a/TheNoiseClock/Views/Clock/ClockSettingsView.swift b/TheNoiseClock/Views/Clock/ClockSettingsView.swift index 1b7a566..82f246c 100644 --- a/TheNoiseClock/Views/Clock/ClockSettingsView.swift +++ b/TheNoiseClock/Views/Clock/ClockSettingsView.swift @@ -159,6 +159,11 @@ private struct BasicDisplaySection: View { Toggle("24‑Hour Format", isOn: $style.use24Hour) Toggle("Show Seconds", isOn: $style.showSeconds) Toggle("Auto Brightness", isOn: $style.autoBrightness) + + // Only show horizontal mode option in portrait orientation + if UIDevice.current.orientation.isPortrait || UIDevice.current.orientation == .unknown { + Toggle("Horizontal Mode", isOn: $style.forceHorizontalMode) + } } } } diff --git a/TheNoiseClock/Views/Clock/Components/ClockDisplayContainer.swift b/TheNoiseClock/Views/Clock/Components/ClockDisplayContainer.swift index ea081f6..039c091 100644 --- a/TheNoiseClock/Views/Clock/Components/ClockDisplayContainer.swift +++ b/TheNoiseClock/Views/Clock/Components/ClockDisplayContainer.swift @@ -41,7 +41,8 @@ struct ClockDisplayContainer: View { clockOpacity: style.clockOpacity, fontFamily: style.fontFamily, fontWeight: style.fontWeight, - fontDesign: style.fontDesign + fontDesign: style.fontDesign, + forceHorizontalMode: style.forceHorizontalMode ) .transition(.opacity) diff --git a/TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift b/TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift index cc3e44e..7bb6221 100644 --- a/TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift +++ b/TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift @@ -22,6 +22,7 @@ struct TimeDisplayView: View { let fontFamily: String let fontWeight: String let fontDesign: String + let forceHorizontalMode: Bool // MARK: - Formatters private static let hour24DF: DateFormatter = { @@ -56,7 +57,7 @@ struct TimeDisplayView: View { var body: some View { GeometryReader { proxy in let containerSize = proxy.size - let portrait = containerSize.height >= containerSize.width + let portrait = !forceHorizontalMode && containerSize.height >= containerSize.width // Use optimal font sizing based on actual container size let baseFontSize = stretched ? @@ -120,6 +121,7 @@ struct TimeDisplayView: View { .minimumScaleFactor(0.1) .clipped() // Prevent overflow beyond bounds } + .border(.yellow, width: 1) .frame(maxWidth: .infinity, maxHeight: .infinity) .onOrientationChange() // Force updates on orientation changes } @@ -142,6 +144,7 @@ struct TimeDisplayView: View { clockOpacity: style.clockOpacity, fontFamily: style.fontFamily, fontWeight: style.fontWeight, - fontDesign: style.fontDesign + fontDesign: style.fontDesign, + forceHorizontalMode: style.forceHorizontalMode ) .background(Color.black) } diff --git a/TheNoiseClock/Views/Clock/Components/TimeSegment.swift b/TheNoiseClock/Views/Clock/Components/TimeSegment.swift index bc55386..b0a153e 100644 --- a/TheNoiseClock/Views/Clock/Components/TimeSegment.swift +++ b/TheNoiseClock/Views/Clock/Components/TimeSegment.swift @@ -6,6 +6,7 @@ // import SwiftUI +import Foundation /// Component for displaying a time segment (hours, minutes, seconds) with fixed-width digits struct TimeSegment: View { @@ -54,9 +55,13 @@ struct TimeSegment: View { } private var digitWidth: CGFloat { - // Calculate the width of a single digit based on font size - // This ensures consistent spacing regardless of the actual digit - return fontSize * 0.6 // Approximate width-to-height ratio for monospace digits + // Calculate the actual width needed for a digit using font metrics + // This accounts for built-in font padding and ensures proper spacing + let font = customFont + let testString = "8" // Use a wide character to get maximum width + let attributes: [NSAttributedString.Key: Any] = [.font: font] + let size = testString.size(withAttributes: attributes) + return size.width + 4 // Add small padding for safety }