From 78ada0862abd5541cfe002a25ad477471954cf81 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 10 Sep 2025 15:22:06 -0500 Subject: [PATCH] Signed-off-by: Matt Bruce --- .../Core/Utilities/DebugLogger.swift | 37 +++++++++++++++++++ .../Core/Utilities/NotificationUtils.swift | 10 ++--- TheNoiseClock/Models/ClockStyle.swift | 6 ++- .../Services/AlarmSoundService.swift | 6 +-- .../Services/AmbientLightService.swift | 24 +++++++++++- TheNoiseClock/Services/FocusModeService.swift | 24 ++++++------ .../Services/NotificationDelegate.swift | 26 ++++++------- .../Services/NotificationService.swift | 4 +- TheNoiseClock/ViewModels/ClockViewModel.swift | 23 ++++++++++++ .../Clock/Components/TimeDisplayView.swift | 2 +- .../Views/Clock/Components/TimeSegment.swift | 4 +- 11 files changed, 126 insertions(+), 40 deletions(-) create mode 100644 TheNoiseClock/Core/Utilities/DebugLogger.swift diff --git a/TheNoiseClock/Core/Utilities/DebugLogger.swift b/TheNoiseClock/Core/Utilities/DebugLogger.swift new file mode 100644 index 0000000..a5f4555 --- /dev/null +++ b/TheNoiseClock/Core/Utilities/DebugLogger.swift @@ -0,0 +1,37 @@ +// +// DebugLogger.swift +// TheNoiseClock +// +// Created by Matt Bruce on 9/10/25. +// + +import Foundation + +/// Debug logging utility that can be toggled with build settings +struct DebugLogger { + + // MARK: - Log Categories + enum Category: String, CaseIterable { + case brightness = "BRIGHTNESS" + case ambient = "AMBIENT" + case nightMode = "NIGHTMODE" + case timer = "TIMER" + case settings = "SETTINGS" + case general = "DEBUG" + } + + // MARK: - Build Configuration + #if DEBUG + private static let isDebugEnabled = true + #else + private static let isDebugEnabled = false + #endif + + // MARK: - Logging Methods + + /// Log debug messages (only in DEBUG builds) + static func log(_ message: String, category: Category = .general) { + guard isDebugEnabled else { return } + print("🔍 [\(category.rawValue)] \(message)") + } +} diff --git a/TheNoiseClock/Core/Utilities/NotificationUtils.swift b/TheNoiseClock/Core/Utilities/NotificationUtils.swift index 08bd1aa..9272aa4 100644 --- a/TheNoiseClock/Core/Utilities/NotificationUtils.swift +++ b/TheNoiseClock/Core/Utilities/NotificationUtils.swift @@ -20,7 +20,7 @@ enum NotificationUtils { ) return granted } catch { - print("Error requesting notification permissions: \(error)") + DebugLogger.log("Error requesting notification permissions: \(error)", category: .general) return false } } @@ -38,12 +38,12 @@ enum NotificationUtils { if soundName == "default" { content.sound = UNNotificationSound.default - print("🔔 Using default notification sound") + DebugLogger.log("Using default notification sound", category: .settings) } else { // Use the sound name directly since sounds.json now references CAF files content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: soundName)) - print("🔔 Using custom alarm sound: \(soundName)") - print("🔔 Sound file should be in main bundle: \(soundName)") + DebugLogger.log("Using custom alarm sound: \(soundName)", category: .settings) + DebugLogger.log("Sound file should be in main bundle: \(soundName)", category: .settings) } return content @@ -74,7 +74,7 @@ enum NotificationUtils { try await UNUserNotificationCenter.current().add(request) return true } catch { - print("Error scheduling notification: \(error)") + DebugLogger.log("Error scheduling notification: \(error)", category: .general) return false } } diff --git a/TheNoiseClock/Models/ClockStyle.swift b/TheNoiseClock/Models/ClockStyle.swift index e5ca04a..3b50390 100644 --- a/TheNoiseClock/Models/ClockStyle.swift +++ b/TheNoiseClock/Models/ClockStyle.swift @@ -319,16 +319,20 @@ class ClockStyle: Codable, Equatable { /// Get the effective brightness considering color theme and night mode var effectiveBrightness: Double { if !autoBrightness { + DebugLogger.log("effectiveBrightness: Auto-brightness disabled, returning 1.0", category: .brightness) return 1.0 // Full brightness when auto-brightness is disabled } if isNightModeActive { + DebugLogger.log("effectiveBrightness: Night mode active, returning 0.3", category: .brightness) // Dim the display to 30% brightness in night mode return 0.3 } // Color-aware brightness adaptation - return getColorAwareBrightness() + let colorAwareBrightness = getColorAwareBrightness() + DebugLogger.log("effectiveBrightness: Color-aware brightness = \(String(format: "%.2f", colorAwareBrightness))", category: .brightness) + return colorAwareBrightness } /// Get brightness based on color theme and ambient light diff --git a/TheNoiseClock/Services/AlarmSoundService.swift b/TheNoiseClock/Services/AlarmSoundService.swift index 99128ab..beffe52 100644 --- a/TheNoiseClock/Services/AlarmSoundService.swift +++ b/TheNoiseClock/Services/AlarmSoundService.swift @@ -42,7 +42,7 @@ class AlarmSoundService { /// Load audio settings from SoundsSettings.json private func loadAudioSettings() -> AudioSettings { guard let url = Bundle.main.url(forResource: "SoundsSettings", withExtension: "json") else { - print("⚠️ Warning: SoundsSettings.json not found, using default alarm settings") + DebugLogger.log("Warning: SoundsSettings.json not found, using default alarm settings", category: .general) return AudioSettings( defaultVolume: 1.0, defaultLoopCount: -1, @@ -57,10 +57,10 @@ class AlarmSoundService { do { let data = try Data(contentsOf: url) let settings = try JSONDecoder().decode(AudioSettings.self, from: data) - print("✅ Loaded audio settings for alarms from SoundsSettings.json") + DebugLogger.log("Loaded audio settings for alarms from SoundsSettings.json", category: .settings) return settings } catch { - print("⚠️ Warning: Error loading audio settings for alarms, using defaults: \(error)") + DebugLogger.log("Warning: Error loading audio settings for alarms, using defaults: \(error)", category: .general) return AudioSettings( defaultVolume: 1.0, defaultLoopCount: -1, diff --git a/TheNoiseClock/Services/AmbientLightService.swift b/TheNoiseClock/Services/AmbientLightService.swift index f180973..bcdbf04 100644 --- a/TheNoiseClock/Services/AmbientLightService.swift +++ b/TheNoiseClock/Services/AmbientLightService.swift @@ -20,6 +20,9 @@ class AmbientLightService { // Timer for periodic brightness checks private var brightnessTimer: Timer? + // Callback for brightness changes + var onBrightnessChange: (() -> Void)? + // MARK: - Singleton static let shared = AmbientLightService() @@ -54,8 +57,18 @@ class AmbientLightService { /// Set screen brightness (0.0 to 1.0) func setBrightness(_ brightness: Double) { let clampedBrightness = max(0.0, min(1.0, brightness)) + let previousBrightness = UIScreen.main.brightness + + DebugLogger.log("AmbientLightService.setBrightness:", category: .ambient) + DebugLogger.log(" - Requested brightness: \(String(format: "%.2f", brightness))", category: .ambient) + DebugLogger.log(" - Clamped brightness: \(String(format: "%.2f", clampedBrightness))", category: .ambient) + DebugLogger.log(" - Previous screen brightness: \(String(format: "%.2f", previousBrightness))", category: .ambient) + UIScreen.main.brightness = clampedBrightness currentBrightness = clampedBrightness + + DebugLogger.log(" - New screen brightness: \(String(format: "%.2f", UIScreen.main.brightness))", category: .ambient) + DebugLogger.log(" - Service currentBrightness: \(String(format: "%.2f", currentBrightness))", category: .ambient) } /// Get current screen brightness @@ -71,6 +84,15 @@ class AmbientLightService { // MARK: - Private Methods private func updateCurrentBrightness() { - currentBrightness = UIScreen.main.brightness + let newBrightness = UIScreen.main.brightness + if abs(newBrightness - currentBrightness) > 0.05 { // Only update if significant change + let previousBrightness = currentBrightness + currentBrightness = newBrightness + + DebugLogger.log("AmbientLightService: Brightness changed from \(String(format: "%.2f", previousBrightness)) to \(String(format: "%.2f", newBrightness))", category: .ambient) + + // Notify that brightness changed + onBrightnessChange?() + } } } diff --git a/TheNoiseClock/Services/FocusModeService.swift b/TheNoiseClock/Services/FocusModeService.swift index e0538e5..d36a4fe 100644 --- a/TheNoiseClock/Services/FocusModeService.swift +++ b/TheNoiseClock/Services/FocusModeService.swift @@ -56,7 +56,7 @@ class FocusModeService { return granted } catch { - print("❌ Error requesting notification permissions: \(error)") + DebugLogger.log("Error requesting notification permissions: \(error)", category: .general) return false } } @@ -85,7 +85,7 @@ class FocusModeService { // Register the category UNUserNotificationCenter.current().setNotificationCategories([alarmCategory]) - print("🔔 Notification settings configured for Focus mode compatibility") + DebugLogger.log("Notification settings configured for Focus mode compatibility", category: .settings) } /// Schedule alarm notification with Focus mode awareness @@ -103,11 +103,11 @@ class FocusModeService { // Use the sound name directly since sounds.json now references CAF files if soundName == "default" { content.sound = UNNotificationSound.default - print("🔔 Using default notification sound") + DebugLogger.log("Using default notification sound", category: .settings) } else { content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: soundName)) - print("🔔 Using custom alarm sound: \(soundName)") - print("🔔 Sound file should be in main bundle: \(soundName)") + DebugLogger.log("Using custom alarm sound: \(soundName)", category: .settings) + DebugLogger.log("Sound file should be in main bundle: \(soundName)", category: .settings) } content.categoryIdentifier = "ALARM_CATEGORY" content.userInfo = [ @@ -139,9 +139,9 @@ class FocusModeService { // Schedule notification UNUserNotificationCenter.current().add(request) { error in if let error = error { - print("❌ Error scheduling alarm notification: \(error)") + DebugLogger.log("Error scheduling alarm notification: \(error)", category: .general) } else { - print("🔔 Alarm notification scheduled for \(date)") + DebugLogger.log("Alarm notification scheduled for \(date)", category: .settings) } } } @@ -149,13 +149,13 @@ class FocusModeService { /// Cancel alarm notification func cancelAlarmNotification(identifier: String) { UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifier]) - print("🔔 Cancelled alarm notification: \(identifier)") + DebugLogger.log("Cancelled alarm notification: \(identifier)", category: .settings) } /// Cancel all alarm notifications func cancelAllAlarmNotifications() { UNUserNotificationCenter.current().removeAllPendingNotificationRequests() - print("🔔 Cancelled all alarm notifications") + DebugLogger.log("Cancelled all alarm notifications", category: .settings) } // MARK: - Private Methods @@ -195,9 +195,9 @@ class FocusModeService { self.currentFocusMode = self.isFocusModeActive ? "Active" : nil if self.isFocusModeActive { - print("🎯 Focus mode is active") + DebugLogger.log("Focus mode is active", category: .settings) } else { - print("🎯 Focus mode is not active") + DebugLogger.log("Focus mode is not active", category: .settings) } } } @@ -226,7 +226,7 @@ extension FocusModeService { await configureNotificationSettings() } - print("🎯 App configured for Focus mode compatibility") + DebugLogger.log("App configured for Focus mode compatibility", category: .settings) } /// Provide user guidance for Focus mode settings diff --git a/TheNoiseClock/Services/NotificationDelegate.swift b/TheNoiseClock/Services/NotificationDelegate.swift index 646c000..5324e5b 100644 --- a/TheNoiseClock/Services/NotificationDelegate.swift +++ b/TheNoiseClock/Services/NotificationDelegate.swift @@ -26,7 +26,7 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { // MARK: - Setup private func setupNotificationCenter() { UNUserNotificationCenter.current().delegate = self - print("🔔 Notification delegate configured") + DebugLogger.log("Notification delegate configured", category: .settings) } /// Set the alarm service instance (called from AlarmViewModel) @@ -46,7 +46,7 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { let notification = response.notification let userInfo = notification.request.content.userInfo - print("🔔 Notification action received: \(actionIdentifier)") + DebugLogger.log("Notification action received: \(actionIdentifier)", category: .settings) switch actionIdentifier { case "SNOOZE_ACTION": @@ -57,7 +57,7 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { // User tapped the notification itself handleNotificationTap(userInfo: userInfo) default: - print("🔔 Unknown action: \(actionIdentifier)") + DebugLogger.log("Unknown action: \(actionIdentifier)", category: .settings) } completionHandler() @@ -80,16 +80,16 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { let alarmId = UUID(uuidString: alarmIdString), let alarmService = self.alarmService, let alarm = alarmService.getAlarm(id: alarmId) else { - print("❌ Could not find alarm for snooze action") + DebugLogger.log("Could not find alarm for snooze action", category: .general) return } - print("🔔 Snoozing alarm: \(alarm.label) for \(alarm.snoozeDuration) minutes") + DebugLogger.log("Snoozing alarm: \(alarm.label) for \(alarm.snoozeDuration) minutes", category: .settings) // Calculate snooze time (current time + snooze duration) let snoozeTime = Date().addingTimeInterval(TimeInterval(alarm.snoozeDuration * 60)) - print("🔔 Snooze time: \(snoozeTime)") - print("🔔 Current time: \(Date())") + DebugLogger.log("Snooze time: \(snoozeTime)", category: .settings) + DebugLogger.log("Current time: \(Date())", category: .settings) // Create a temporary alarm for the snooze let snoozeAlarm = Alarm( @@ -114,11 +114,11 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { private func handleStopAction(userInfo: [AnyHashable: Any]) { guard let alarmIdString = userInfo["alarmId"] as? String, let alarmId = UUID(uuidString: alarmIdString) else { - print("❌ Could not find alarm ID for stop action") + DebugLogger.log("Could not find alarm ID for stop action", category: .general) return } - print("🔔 Stopping alarm: \(alarmId)") + DebugLogger.log("Stopping alarm: \(alarmId)", category: .settings) // Cancel any pending notifications for this alarm UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [alarmIdString]) @@ -130,11 +130,11 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { private func handleNotificationTap(userInfo: [AnyHashable: Any]) { guard let alarmIdString = userInfo["alarmId"] as? String, let alarmId = UUID(uuidString: alarmIdString) else { - print("❌ Could not find alarm ID for notification tap") + DebugLogger.log("Could not find alarm ID for notification tap", category: .general) return } - print("🔔 Notification tapped for alarm: \(alarmId)") + DebugLogger.log("Notification tapped for alarm: \(alarmId)", category: .settings) // For now, just log the tap. In the future, this could open the alarm details // or perform some other action when the user taps the notification @@ -171,9 +171,9 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { // Schedule notification do { try await UNUserNotificationCenter.current().add(request) - print("🔔 Snooze notification scheduled for \(snoozeAlarm.time)") + DebugLogger.log("Snooze notification scheduled for \(snoozeAlarm.time)", category: .settings) } catch { - print("❌ Error scheduling snooze notification: \(error)") + DebugLogger.log("Error scheduling snooze notification: \(error)", category: .general) } } } diff --git a/TheNoiseClock/Services/NotificationService.swift b/TheNoiseClock/Services/NotificationService.swift index 05d7cd9..5028fc9 100644 --- a/TheNoiseClock/Services/NotificationService.swift +++ b/TheNoiseClock/Services/NotificationService.swift @@ -30,7 +30,7 @@ class NotificationService { isAuthorized = granted return granted } catch { - print("Error requesting notification permissions: \(error)") + DebugLogger.log("Error requesting notification permissions: \(error)", category: .general) isAuthorized = false return false } @@ -54,7 +54,7 @@ class NotificationService { date: Date ) async -> Bool { guard isAuthorized else { - print("Notifications not authorized") + DebugLogger.log("Notifications not authorized", category: .settings) return false } diff --git a/TheNoiseClock/ViewModels/ClockViewModel.swift b/TheNoiseClock/ViewModels/ClockViewModel.swift index 5155fe1..fd19346 100644 --- a/TheNoiseClock/ViewModels/ClockViewModel.swift +++ b/TheNoiseClock/ViewModels/ClockViewModel.swift @@ -166,6 +166,12 @@ class ClockViewModel { /// Start ambient light monitoring private func startAmbientLightMonitoring() { ambientLightService.startMonitoring() + + // Set up callback to respond to brightness changes + ambientLightService.onBrightnessChange = { [weak self] in + DebugLogger.log("ClockViewModel: Received brightness change notification", category: .brightness) + self?.updateBrightness() + } } /// Stop ambient light monitoring @@ -177,7 +183,24 @@ class ClockViewModel { private func updateBrightness() { if style.autoBrightness { let targetBrightness = style.effectiveBrightness + let currentScreenBrightness = UIScreen.main.brightness + let isNightMode = style.isNightModeActive + + DebugLogger.log("Auto Brightness Debug:", category: .brightness) + DebugLogger.log(" - Auto brightness enabled: \(style.autoBrightness)", category: .brightness) + DebugLogger.log(" - Current screen brightness: \(String(format: "%.2f", currentScreenBrightness))", category: .brightness) + DebugLogger.log(" - Target brightness: \(String(format: "%.2f", targetBrightness))", category: .brightness) + DebugLogger.log(" - Night mode active: \(isNightMode)", category: .brightness) + DebugLogger.log(" - Color theme: \(style.selectedColorTheme)", category: .brightness) + DebugLogger.log(" - Ambient light threshold: \(String(format: "%.2f", style.ambientLightThreshold))", category: .brightness) + ambientLightService.setBrightness(targetBrightness) + + DebugLogger.log(" - Brightness set to: \(String(format: "%.2f", targetBrightness))", category: .brightness) + DebugLogger.log(" - Actual screen brightness now: \(String(format: "%.2f", UIScreen.main.brightness))", category: .brightness) + DebugLogger.log("---", category: .brightness) + } else { + DebugLogger.log("Auto Brightness: DISABLED", category: .brightness) } } } diff --git a/TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift b/TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift index a21e874..5440b08 100644 --- a/TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift +++ b/TheNoiseClock/Views/Clock/Components/TimeDisplayView.swift @@ -123,7 +123,7 @@ struct TimeDisplayView: View { .minimumScaleFactor(0.1) .clipped() // Prevent overflow beyond bounds } - //.border(.yellow, width: 1) + .border(.yellow, width: 1) .frame(maxWidth: .infinity, maxHeight: .infinity) .onOrientationChange() // Force updates on orientation changes } diff --git a/TheNoiseClock/Views/Clock/Components/TimeSegment.swift b/TheNoiseClock/Views/Clock/Components/TimeSegment.swift index f79dbab..b0a153e 100644 --- a/TheNoiseClock/Views/Clock/Components/TimeSegment.swift +++ b/TheNoiseClock/Views/Clock/Components/TimeSegment.swift @@ -33,10 +33,10 @@ struct TimeSegment: View { fontDesign: fontDesign ) .frame(width: digitWidth) - //.border(.red, width: 1) + .border(.red, width: 1) } } - //.border(Color.green, width: 1) + .border(Color.green, width: 1) .frame(maxHeight: .infinity) }