From 74ece5a71a3f46d1f47099c2e78791ebab211566 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Sat, 31 Jan 2026 11:23:02 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- PRD.md | 1 - .../Alarms/Services/AlarmSoundService.swift | 7 ++-- .../Alarms/Services/FocusModeService.swift | 26 ++++++------- .../Services/NotificationDelegate.swift | 27 +++++++------- .../Alarms/Services/NotificationService.swift | 5 ++- .../Features/Clock/Models/ClockStyle.swift | 7 ++-- .../Clock/Services/AmbientLightService.swift | 15 ++++---- .../Features/Clock/State/ClockViewModel.swift | 24 ++++++------ .../Shared/Utilities/DebugLogger.swift | 37 ------------------- .../Shared/Utilities/NotificationUtils.swift | 11 +++--- 10 files changed, 63 insertions(+), 97 deletions(-) delete mode 100644 TheNoiseClock/Shared/Utilities/DebugLogger.swift diff --git a/PRD.md b/PRD.md index e67ff36..3558b0c 100644 --- a/PRD.md +++ b/PRD.md @@ -391,7 +391,6 @@ TheNoiseClock/ │ │ │ └── SoundCategory.swift # Shared sound category definitions │ │ └── Utilities/ │ │ ├── ColorUtils.swift # Color manipulation utilities -│ │ ├── DebugLogger.swift # Debug logging helper │ │ └── NotificationUtils.swift # Notification helper functions │ ├── Features/ │ │ ├── Clock/ diff --git a/TheNoiseClock/Features/Alarms/Services/AlarmSoundService.swift b/TheNoiseClock/Features/Alarms/Services/AlarmSoundService.swift index beffe52..c73372a 100644 --- a/TheNoiseClock/Features/Alarms/Services/AlarmSoundService.swift +++ b/TheNoiseClock/Features/Alarms/Services/AlarmSoundService.swift @@ -7,6 +7,7 @@ import Foundation import AudioPlaybackKit +import Bedrock /// Extension service for alarm-specific sound functionality class AlarmSoundService { @@ -42,7 +43,7 @@ class AlarmSoundService { /// Load audio settings from SoundsSettings.json private func loadAudioSettings() -> AudioSettings { guard let url = Bundle.main.url(forResource: "SoundsSettings", withExtension: "json") else { - DebugLogger.log("Warning: SoundsSettings.json not found, using default alarm settings", category: .general) + Design.debugLog("[general] Warning: SoundsSettings.json not found, using default alarm settings") return AudioSettings( defaultVolume: 1.0, defaultLoopCount: -1, @@ -57,10 +58,10 @@ class AlarmSoundService { do { let data = try Data(contentsOf: url) let settings = try JSONDecoder().decode(AudioSettings.self, from: data) - DebugLogger.log("Loaded audio settings for alarms from SoundsSettings.json", category: .settings) + Design.debugLog("[settings] Loaded audio settings for alarms from SoundsSettings.json") return settings } catch { - DebugLogger.log("Warning: Error loading audio settings for alarms, using defaults: \(error)", category: .general) + Design.debugLog("[general] Warning: Error loading audio settings for alarms, using defaults: \(error)") return AudioSettings( defaultVolume: 1.0, defaultLoopCount: -1, diff --git a/TheNoiseClock/Features/Alarms/Services/FocusModeService.swift b/TheNoiseClock/Features/Alarms/Services/FocusModeService.swift index 241e593..f9a2a24 100644 --- a/TheNoiseClock/Features/Alarms/Services/FocusModeService.swift +++ b/TheNoiseClock/Features/Alarms/Services/FocusModeService.swift @@ -9,6 +9,7 @@ import Foundation import Observation import UIKit import UserNotifications +import Bedrock /// Service to align notifications with Focus mode behavior @Observable @@ -55,7 +56,7 @@ class FocusModeService { return granted } catch { - DebugLogger.log("Error requesting notification permissions: \(error)", category: .general) + Design.debugLog("[general] Error requesting notification permissions: \(error)") return false } } @@ -84,7 +85,7 @@ class FocusModeService { // Register the category UNUserNotificationCenter.current().setNotificationCategories([alarmCategory]) - DebugLogger.log("Notification settings configured for Focus mode compatibility", category: .settings) + Design.debugLog("[settings] Notification settings configured for Focus mode compatibility") } /// Schedule alarm notification with Focus mode awareness @@ -103,11 +104,11 @@ class FocusModeService { // Use the sound name directly since sounds.json now references CAF files if soundName == "default" { content.sound = UNNotificationSound.default - DebugLogger.log("Using default notification sound", category: .settings) + Design.debugLog("[settings] Using default notification sound") } else { content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: soundName)) - DebugLogger.log("Using custom alarm sound: \(soundName)", category: .settings) - DebugLogger.log("Sound file should be in main bundle: \(soundName)", category: .settings) + Design.debugLog("[settings] Using custom alarm sound: \(soundName)") + Design.debugLog("[settings] Sound file should be in main bundle: \(soundName)") } content.categoryIdentifier = "ALARM_CATEGORY" @@ -143,9 +144,9 @@ class FocusModeService { // Schedule notification UNUserNotificationCenter.current().add(request) { error in if let error = error { - DebugLogger.log("Error scheduling alarm notification: \(error)", category: .general) + Design.debugLog("[general] Error scheduling alarm notification: \(error)") } else { - DebugLogger.log("Alarm notification scheduled for \(date)", category: .settings) + Design.debugLog("[settings] Alarm notification scheduled for \(date)") } } } @@ -153,13 +154,13 @@ class FocusModeService { /// Cancel alarm notification func cancelAlarmNotification(identifier: String) { UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifier]) - DebugLogger.log("Cancelled alarm notification: \(identifier)", category: .settings) + Design.debugLog("[settings] Cancelled alarm notification: \(identifier)") } /// Cancel all alarm notifications func cancelAllAlarmNotifications() { UNUserNotificationCenter.current().removeAllPendingNotificationRequests() - DebugLogger.log("Cancelled all alarm notifications", category: .settings) + Design.debugLog("[settings] Cancelled all alarm notifications") } // MARK: - Private Methods @@ -193,10 +194,7 @@ class FocusModeService { timeSensitiveSetting = settings.timeSensitiveSetting scheduledDeliverySetting = settings.scheduledDeliverySetting - DebugLogger.log( - "Notification settings updated: auth=\(settings.authorizationStatus), timeSensitive=\(settings.timeSensitiveSetting), scheduledDelivery=\(settings.scheduledDeliverySetting)", - category: .settings - ) + Design.debugLog("[settings] Notification settings updated: auth=\(settings.authorizationStatus), timeSensitive=\(settings.timeSensitiveSetting), scheduledDelivery=\(settings.scheduledDeliverySetting)") } /// Get notification authorization status @@ -222,7 +220,7 @@ extension FocusModeService { await configureNotificationSettings() } - DebugLogger.log("App configured for Focus mode compatibility", category: .settings) + Design.debugLog("[settings] App configured for Focus mode compatibility") } /// Provide user guidance for Focus mode settings diff --git a/TheNoiseClock/Features/Alarms/Services/NotificationDelegate.swift b/TheNoiseClock/Features/Alarms/Services/NotificationDelegate.swift index 5324e5b..cad28a0 100644 --- a/TheNoiseClock/Features/Alarms/Services/NotificationDelegate.swift +++ b/TheNoiseClock/Features/Alarms/Services/NotificationDelegate.swift @@ -7,6 +7,7 @@ import UserNotifications import Foundation +import Bedrock /// Delegate to handle notification actions (snooze, stop, etc.) class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { @@ -26,7 +27,7 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { // MARK: - Setup private func setupNotificationCenter() { UNUserNotificationCenter.current().delegate = self - DebugLogger.log("Notification delegate configured", category: .settings) + Design.debugLog("[settings] Notification delegate configured") } /// Set the alarm service instance (called from AlarmViewModel) @@ -46,7 +47,7 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { let notification = response.notification let userInfo = notification.request.content.userInfo - DebugLogger.log("Notification action received: \(actionIdentifier)", category: .settings) + Design.debugLog("[settings] Notification action received: \(actionIdentifier)") switch actionIdentifier { case "SNOOZE_ACTION": @@ -57,7 +58,7 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { // User tapped the notification itself handleNotificationTap(userInfo: userInfo) default: - DebugLogger.log("Unknown action: \(actionIdentifier)", category: .settings) + Design.debugLog("[settings] Unknown action: \(actionIdentifier)") } completionHandler() @@ -80,16 +81,16 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { let alarmId = UUID(uuidString: alarmIdString), let alarmService = self.alarmService, let alarm = alarmService.getAlarm(id: alarmId) else { - DebugLogger.log("Could not find alarm for snooze action", category: .general) + Design.debugLog("[general] Could not find alarm for snooze action") return } - DebugLogger.log("Snoozing alarm: \(alarm.label) for \(alarm.snoozeDuration) minutes", category: .settings) + Design.debugLog("[settings] Snoozing alarm: \(alarm.label) for \(alarm.snoozeDuration) minutes") // Calculate snooze time (current time + snooze duration) let snoozeTime = Date().addingTimeInterval(TimeInterval(alarm.snoozeDuration * 60)) - DebugLogger.log("Snooze time: \(snoozeTime)", category: .settings) - DebugLogger.log("Current time: \(Date())", category: .settings) + Design.debugLog("[settings] Snooze time: \(snoozeTime)") + Design.debugLog("[settings] Current time: \(Date())") // Create a temporary alarm for the snooze let snoozeAlarm = Alarm( @@ -114,11 +115,11 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { private func handleStopAction(userInfo: [AnyHashable: Any]) { guard let alarmIdString = userInfo["alarmId"] as? String, let alarmId = UUID(uuidString: alarmIdString) else { - DebugLogger.log("Could not find alarm ID for stop action", category: .general) + Design.debugLog("[general] Could not find alarm ID for stop action") return } - DebugLogger.log("Stopping alarm: \(alarmId)", category: .settings) + Design.debugLog("[settings] Stopping alarm: \(alarmId)") // Cancel any pending notifications for this alarm UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [alarmIdString]) @@ -130,11 +131,11 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { private func handleNotificationTap(userInfo: [AnyHashable: Any]) { guard let alarmIdString = userInfo["alarmId"] as? String, let alarmId = UUID(uuidString: alarmIdString) else { - DebugLogger.log("Could not find alarm ID for notification tap", category: .general) + Design.debugLog("[general] Could not find alarm ID for notification tap") return } - DebugLogger.log("Notification tapped for alarm: \(alarmId)", category: .settings) + Design.debugLog("[settings] Notification tapped for alarm: \(alarmId)") // 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 +172,9 @@ class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate { // Schedule notification do { try await UNUserNotificationCenter.current().add(request) - DebugLogger.log("Snooze notification scheduled for \(snoozeAlarm.time)", category: .settings) + Design.debugLog("[settings] Snooze notification scheduled for \(snoozeAlarm.time)") } catch { - DebugLogger.log("Error scheduling snooze notification: \(error)", category: .general) + Design.debugLog("[general] Error scheduling snooze notification: \(error)") } } } diff --git a/TheNoiseClock/Features/Alarms/Services/NotificationService.swift b/TheNoiseClock/Features/Alarms/Services/NotificationService.swift index 5028fc9..732092c 100644 --- a/TheNoiseClock/Features/Alarms/Services/NotificationService.swift +++ b/TheNoiseClock/Features/Alarms/Services/NotificationService.swift @@ -8,6 +8,7 @@ import Foundation import UserNotifications import Observation +import Bedrock /// Service for managing system notifications @Observable @@ -30,7 +31,7 @@ class NotificationService { isAuthorized = granted return granted } catch { - DebugLogger.log("Error requesting notification permissions: \(error)", category: .general) + Design.debugLog("[general] Error requesting notification permissions: \(error)") isAuthorized = false return false } @@ -54,7 +55,7 @@ class NotificationService { date: Date ) async -> Bool { guard isAuthorized else { - DebugLogger.log("Notifications not authorized", category: .settings) + Design.debugLog("[settings] Notifications not authorized") return false } diff --git a/TheNoiseClock/Features/Clock/Models/ClockStyle.swift b/TheNoiseClock/Features/Clock/Models/ClockStyle.swift index 089dac0..4a490c5 100644 --- a/TheNoiseClock/Features/Clock/Models/ClockStyle.swift +++ b/TheNoiseClock/Features/Clock/Models/ClockStyle.swift @@ -7,6 +7,7 @@ import SwiftUI import Observation +import Bedrock /// Clock customization settings and data model @Observable @@ -341,19 +342,19 @@ 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) + Design.debugLog("[brightness] effectiveBrightness: Auto-brightness disabled, returning 1.0") return 1.0 // Full brightness when auto-brightness is disabled } if isNightModeActive { - DebugLogger.log("effectiveBrightness: Night mode active, returning 0.3", category: .brightness) + Design.debugLog("[brightness] effectiveBrightness: Night mode active, returning 0.3") // Dim the display to 30% brightness in night mode return 0.3 } // Color-aware brightness adaptation let colorAwareBrightness = getColorAwareBrightness() - DebugLogger.log("effectiveBrightness: Color-aware brightness = \(String(format: "%.2f", colorAwareBrightness))", category: .brightness) + Design.debugLog("[brightness] effectiveBrightness: Color-aware brightness = \(String(format: \"%.2f\", colorAwareBrightness))") return colorAwareBrightness } diff --git a/TheNoiseClock/Features/Clock/Services/AmbientLightService.swift b/TheNoiseClock/Features/Clock/Services/AmbientLightService.swift index bcdbf04..5b733d6 100644 --- a/TheNoiseClock/Features/Clock/Services/AmbientLightService.swift +++ b/TheNoiseClock/Features/Clock/Services/AmbientLightService.swift @@ -8,6 +8,7 @@ import Foundation import UIKit import Observation +import Bedrock /// Service for monitoring ambient light and managing brightness @Observable @@ -59,16 +60,16 @@ class AmbientLightService { 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) + Design.debugLog("[ambient] AmbientLightService.setBrightness:") + Design.debugLog("[ambient] - Requested brightness: \(String(format: \"%.2f\", brightness))") + Design.debugLog("[ambient] - Clamped brightness: \(String(format: \"%.2f\", clampedBrightness))") + Design.debugLog("[ambient] - Previous screen brightness: \(String(format: \"%.2f\", previousBrightness))") 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) + Design.debugLog("[ambient] - New screen brightness: \(String(format: \"%.2f\", UIScreen.main.brightness))") + Design.debugLog("[ambient] - Service currentBrightness: \(String(format: \"%.2f\", currentBrightness))") } /// Get current screen brightness @@ -89,7 +90,7 @@ class AmbientLightService { let previousBrightness = currentBrightness currentBrightness = newBrightness - DebugLogger.log("AmbientLightService: Brightness changed from \(String(format: "%.2f", previousBrightness)) to \(String(format: "%.2f", newBrightness))", category: .ambient) + Design.debugLog("[ambient] AmbientLightService: Brightness changed from \(String(format: \"%.2f\", previousBrightness)) to \(String(format: \"%.2f\", newBrightness))") // Notify that brightness changed onBrightnessChange?() diff --git a/TheNoiseClock/Features/Clock/State/ClockViewModel.swift b/TheNoiseClock/Features/Clock/State/ClockViewModel.swift index 0e0b6f3..4f9a2c7 100644 --- a/TheNoiseClock/Features/Clock/State/ClockViewModel.swift +++ b/TheNoiseClock/Features/Clock/State/ClockViewModel.swift @@ -202,7 +202,7 @@ class ClockViewModel { // Set up callback to respond to brightness changes ambientLightService.onBrightnessChange = { [weak self] in - DebugLogger.log("ClockViewModel: Received brightness change notification", category: .brightness) + Design.debugLog("[brightness] ClockViewModel: Received brightness change notification") self?.updateBrightness() } } @@ -219,21 +219,21 @@ class ClockViewModel { 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) + Design.debugLog("[brightness] Auto Brightness Debug:") + Design.debugLog("[brightness] - Auto brightness enabled: \(style.autoBrightness)") + Design.debugLog("[brightness] - Current screen brightness: \(String(format: \"%.2f\", currentScreenBrightness))") + Design.debugLog("[brightness] - Target brightness: \(String(format: \"%.2f\", targetBrightness))") + Design.debugLog("[brightness] - Night mode active: \(isNightMode)") + Design.debugLog("[brightness] - Color theme: \(style.selectedColorTheme)") + Design.debugLog("[brightness] - Ambient light threshold: \(String(format: \"%.2f\", style.ambientLightThreshold))") 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) + Design.debugLog("[brightness] - Brightness set to: \(String(format: \"%.2f\", targetBrightness))") + Design.debugLog("[brightness] - Actual screen brightness now: \(String(format: \"%.2f\", UIScreen.main.brightness))") + Design.debugLog("[brightness] ---") } else { - DebugLogger.log("Auto Brightness: DISABLED", category: .brightness) + Design.debugLog("[brightness] Auto Brightness: DISABLED") } } } diff --git a/TheNoiseClock/Shared/Utilities/DebugLogger.swift b/TheNoiseClock/Shared/Utilities/DebugLogger.swift deleted file mode 100644 index a5f4555..0000000 --- a/TheNoiseClock/Shared/Utilities/DebugLogger.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// 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/Shared/Utilities/NotificationUtils.swift b/TheNoiseClock/Shared/Utilities/NotificationUtils.swift index 9272aa4..01fddc8 100644 --- a/TheNoiseClock/Shared/Utilities/NotificationUtils.swift +++ b/TheNoiseClock/Shared/Utilities/NotificationUtils.swift @@ -7,6 +7,7 @@ import UserNotifications import Foundation +import Bedrock /// Notification helper functions enum NotificationUtils { @@ -20,7 +21,7 @@ enum NotificationUtils { ) return granted } catch { - DebugLogger.log("Error requesting notification permissions: \(error)", category: .general) + Design.debugLog("[general] Error requesting notification permissions: \(error)") return false } } @@ -38,12 +39,12 @@ enum NotificationUtils { if soundName == "default" { content.sound = UNNotificationSound.default - DebugLogger.log("Using default notification sound", category: .settings) + Design.debugLog("[settings] Using default notification sound") } else { // Use the sound name directly since sounds.json now references CAF files content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: soundName)) - DebugLogger.log("Using custom alarm sound: \(soundName)", category: .settings) - DebugLogger.log("Sound file should be in main bundle: \(soundName)", category: .settings) + Design.debugLog("[settings] Using custom alarm sound: \(soundName)") + Design.debugLog("[settings] Sound file should be in main bundle: \(soundName)") } return content @@ -74,7 +75,7 @@ enum NotificationUtils { try await UNUserNotificationCenter.current().add(request) return true } catch { - DebugLogger.log("Error scheduling notification: \(error)", category: .general) + Design.debugLog("[general] Error scheduling notification: \(error)") return false } }