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

This commit is contained in:
Matt Bruce 2026-01-31 09:43:40 -06:00
parent 14f8c13f3c
commit 9ae5aef89b
10 changed files with 66 additions and 64 deletions

View File

@ -7,15 +7,15 @@
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "14EE7C9C-8F78-417E-AEF3-D655DB3F17B0"
uuid = "86059BA3-9776-4EB9-B3CA-4D26F156BEEC"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "64"
endingLineNumber = "64"
startingLineNumber = "67"
endingLineNumber = "67"
landmarkName = "body"
landmarkType = "24">
</BreakpointContent>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "container:TheNoiseClock.xcodeproj">
</FileRef>
</Workspace>

View File

@ -15,9 +15,7 @@ enum FontFamily: String, CaseIterable {
case georgia = "Georgia"
case verdana = "Verdana"
case courier = "Courier"
case futura = "Futura"
case avenir = "Avenir"
case roboto = "Roboto"
init?(rawValue: String) {
switch rawValue {
@ -28,9 +26,7 @@ enum FontFamily: String, CaseIterable {
case "Georgia": self = .georgia
case "Verdana": self = .verdana
case "Monaco", "Courier": self = .courier
case "Futura": self = .futura
case "Avenir": self = .avenir
case "Roboto": self = .roboto
default: self = .system
}
}
@ -38,12 +34,13 @@ enum FontFamily: String, CaseIterable {
var percentageDownsize: CGFloat {
switch self {
case .system:
return 0.99
return 0.95
case .georgia:
return 0.90
default: return 1
}
}
var fontWeights: [Font.Weight] {
guard let weightDict = Self.fontMapWeights[self.rawValue] else {
return []
@ -85,18 +82,10 @@ enum FontFamily: String, CaseIterable {
.regular: "Courier",
.bold: "Courier-Bold"
],
FontFamily.futura.rawValue: [
.regular: "Futura-Medium",
.bold: "Futura-Bold"
],
FontFamily.avenir.rawValue: [
.regular: "Avenir-Roman",
.bold: "Avenir-Bold"
],
FontFamily.roboto.rawValue: [
.regular: "Roboto-Regular",
.bold: "Roboto-Bold"
]
]
}

View File

@ -17,7 +17,8 @@ struct FontUtils {
fontName: FontFamily,
weight: Font.Weight,
design: Font.Design,
for size: CGSize
for size: CGSize,
isDisplayMode: Bool = false
) -> CGFloat {
var low: CGFloat = 1.0
var high: CGFloat = 2000.0
@ -39,7 +40,9 @@ struct FontUtils {
}
}
return low * fontName.percentageDownsize
// Apply more conservative sizing in full screen mode
let baseSize = low * fontName.percentageDownsize
return isDisplayMode ? baseSize * 0.95 : baseSize
}
static func createFont(
@ -180,7 +183,8 @@ private struct TestContentView: View {
fontFamily: font,
fontWeight: fontWeight,
fontDesign: fontDesign,
forceHorizontalMode: true)
forceHorizontalMode: true,
isDisplayMode: false)
TimeSegment(
text: digit,
@ -191,6 +195,7 @@ private struct TestContentView: View {
fontFamily: font, // FontFamily
fontWeight: fontWeight,
fontDesign: fontDesign,
isDisplayMode: false
)
}
.frame(width: 400, height: 200)
@ -255,7 +260,8 @@ private struct FontSampleCell: View {
glowIntensity: 0.5, // Double
fontFamily: font, // FontFamily
fontWeight: weight,
fontDesign: design)
fontDesign: design,
isDisplayMode: false)
.frame(width: 100, height: 100)
.border(Color.black)
}

View File

@ -69,9 +69,6 @@ class ClockViewModel {
}
func updateStyle(_ newStyle: ClockStyle) {
DebugLogger.log("ClockViewModel: updateStyle called", category: .settings)
DebugLogger.log("ClockViewModel: old fontFamily = \(style.fontFamily)", category: .settings)
DebugLogger.log("ClockViewModel: new fontFamily = \(newStyle.fontFamily)", category: .settings)
// Update properties of the existing style object instead of replacing it
// This preserves the @Observable chain
@ -103,7 +100,6 @@ class ClockViewModel {
style.dateFormat = newStyle.dateFormat
style.respectFocusModes = newStyle.respectFocusModes
DebugLogger.log("ClockViewModel: after update fontFamily = \(style.fontFamily)", category: .settings)
saveStyle()
updateTimersIfNeeded()

View File

@ -244,11 +244,19 @@ private struct FontSection: View {
}
}
// Computed property for sorted font families (System first, then alphabetical)
private var sortedFontFamilies: [FontFamily] {
let allFamilies = FontFamily.allCases
let systemFamily = allFamilies.filter { $0 == .system }
let otherFamilies = allFamilies.filter { $0 != .system }.sorted { $0.rawValue < $1.rawValue }
return systemFamily + otherFamilies
}
var body: some View {
Section(header: Text("Font")) {
// Font Family
Picker("Family", selection: $style.fontFamily) {
ForEach(FontFamily.allCases, id: \.self) { family in
ForEach(sortedFontFamilies, id: \.self) { family in
Text(family.rawValue).tag(family)
}
}

View File

@ -17,8 +17,6 @@ struct ClockDisplayContainer: View {
// MARK: - Body
var body: some View {
DebugLogger.log("ClockDisplayContainer: body called with fontFamily=\(style.fontFamily), fontWeight=\(style.fontWeight), fontDesign=\(style.fontDesign)", category: .general)
return GeometryReader { geometry in
let isPortrait = geometry.size.height >= geometry.size.width
let hasOverlay = style.showBattery || style.showDate
@ -44,13 +42,13 @@ struct ClockDisplayContainer: View {
fontFamily: style.fontFamily,
fontWeight: style.fontWeight,
fontDesign: style.fontDesign,
forceHorizontalMode: style.forceHorizontalMode
forceHorizontalMode: style.forceHorizontalMode,
isDisplayMode: isDisplayMode
)
.transition(.opacity)
Spacer()
}
.scaleEffect(isDisplayMode ? 1.0 : 0.995)
.animation(UIConstants.AnimationCurves.smooth, value: isDisplayMode)
}
}

View File

@ -18,6 +18,7 @@ struct DigitView: View {
let opacity: Double
let digitColor: Color
let glowIntensity: Double
let isDisplayMode: Bool
@Binding var fontSize: CGFloat
@State private var lastCalculatedSize: CGSize = .zero
@ -30,8 +31,8 @@ struct DigitView: View {
digitColor: Color = .black,
opacity: Double = 1,
glowIntensity: Double = 0,
fontSize: Binding<CGFloat>) {
DebugLogger.log("DigitView: init called with fontName=\(fontName), weight=\(weight), design=\(design)", category: .general)
fontSize: Binding<CGFloat>,
isDisplayMode: Bool = false) {
self.digit = (digit.count == 1 && "0123456789".contains(digit)) ? digit : "0"
self.fontName = fontName
self.weight = weight
@ -39,6 +40,7 @@ struct DigitView: View {
self.opacity = opacity
self.digitColor = digitColor
self.glowIntensity = glowIntensity
self.isDisplayMode = isDisplayMode
self._fontSize = fontSize
}
@ -98,15 +100,12 @@ struct DigitView: View {
calculateOptimalFontSize(for: geometry.size)
}
.onChange(of: fontName) { _, _ in
DebugLogger.log("DigitView: fontName changed to \(fontName)", category: .general)
calculateOptimalFontSize(for: geometry.size)
}
.onChange(of: weight) { _, _ in
DebugLogger.log("DigitView: weight changed to \(weight)", category: .general)
calculateOptimalFontSize(for: geometry.size)
}
.onChange(of: design) { _, _ in
DebugLogger.log("DigitView: design changed to \(design)", category: .general)
calculateOptimalFontSize(for: geometry.size)
}
}
@ -124,7 +123,8 @@ struct DigitView: View {
fontName: fontName,
weight: weight,
design: design,
for: size)
for: size,
isDisplayMode: isDisplayMode)
// Only update if the size is significantly different to prevent micro-adjustments
fontSize = optimalSize

View File

@ -23,6 +23,7 @@ struct TimeDisplayView: View {
let fontWeight: Font.Weight
let fontDesign: Font.Design
let forceHorizontalMode: Bool
let isDisplayMode: Bool
@State var fontSize: CGFloat = 100
// MARK: - Formatters
@ -56,8 +57,6 @@ struct TimeDisplayView: View {
// MARK: - Body
var body: some View {
DebugLogger.log("TimeDisplayView: body called with fontFamily=\(fontFamily), fontWeight=\(fontWeight), fontDesign=\(fontDesign)", category: .general)
return GeometryReader { proxy in
let containerSize = proxy.size
let portraitMode = containerSize.height >= containerSize.width
@ -77,25 +76,25 @@ struct TimeDisplayView: View {
let finalScale = stretched ? 1.0 : CGFloat(max(0.1, min(manualScale, 1.0)))
// Time display with consistent centering and stable layout
Group {
return Group {
if portrait {
VStack(alignment: .center) {
TimeSegment(text: hour, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
TimeSegment(text: hour, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode)
ColonView(dotDiameter: dotDiameter, spacing: dotSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight, isHorizontal: true)
TimeSegment(text: minute, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
TimeSegment(text: minute, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode)
if showSeconds {
ColonView(dotDiameter: dotDiameter, spacing: dotSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight, isHorizontal: true)
TimeSegment(text: secondsText, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
TimeSegment(text: secondsText, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode)
}
}
} else {
HStack(alignment: .center) {
TimeSegment(text: hour, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
TimeSegment(text: hour, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode)
ColonView(dotDiameter: dotDiameter, spacing: dotSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight, isHorizontal: false)
TimeSegment(text: minute, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
TimeSegment(text: minute, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode)
if showSeconds {
ColonView(dotDiameter: dotDiameter, spacing: dotSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight, isHorizontal: false)
TimeSegment(text: secondsText, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
TimeSegment(text: secondsText, fontSize: $fontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign, isDisplayMode: isDisplayMode)
}
}
.frame(maxWidth: .infinity)
@ -120,23 +119,20 @@ struct TimeDisplayView: View {
// MARK: - Preview
#Preview {
let style = ClockStyle()
style.fontFamily = .verdana
style.fontWeight = .medium
return TimeDisplayView(
TimeDisplayView(
date: Date(),
use24Hour: style.use24Hour,
showSeconds: style.showSeconds,
digitColor: style.digitColor,
glowIntensity: style.glowIntensity,
manualScale: style.digitScale,
stretched: style.stretched,
clockOpacity: style.clockOpacity,
fontFamily: style.fontFamily,
fontWeight: style.fontWeight,
fontDesign: style.fontDesign,
forceHorizontalMode: style.forceHorizontalMode
use24Hour: true,
showSeconds: false,
digitColor: .white,
glowIntensity: 0.2,
manualScale: 1.0,
stretched: true,
clockOpacity: 1.0,
fontFamily: .verdana,
fontWeight: .medium,
fontDesign: .default,
forceHorizontalMode: false,
isDisplayMode: false
)
.background(Color.black)
}

View File

@ -18,10 +18,10 @@ struct TimeSegment: View {
let fontFamily: FontFamily
let fontWeight: Font.Weight
let fontDesign: Font.Design
let isDisplayMode: Bool
var body: some View {
DebugLogger.log("TimeSegment: body called with fontFamily=\(fontFamily), fontWeight=\(fontWeight), fontDesign=\(fontDesign)", category: .general)
return HStack(alignment: .center, spacing: 0) {
HStack(alignment: .center, spacing: 0) {
ForEach(Array(text.enumerated()), id: \.offset) { index, character in
DigitView(
digit: String(character),
@ -31,7 +31,8 @@ struct TimeSegment: View {
digitColor: digitColor,
opacity: clampedOpacity,
glowIntensity: glowIntensity,
fontSize: $fontSize
fontSize: $fontSize,
isDisplayMode: isDisplayMode
)
//.border(.red, width: 1)
}
@ -57,7 +58,8 @@ struct TimeSegment: View {
glowIntensity: 0.2,
fontFamily: .system,
fontWeight: .regular,
fontDesign: .default
fontDesign: .default,
isDisplayMode: true
)
.background(Color.black)
}