general: logging cleanup
This commit is contained in:
@@ -14,55 +14,40 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
|||||||
@Published var timerEngine: TimerEngine?
|
@Published var timerEngine: TimerEngine?
|
||||||
private let settingsManager: SettingsManager = .shared
|
private let settingsManager: SettingsManager = .shared
|
||||||
private var updateManager: UpdateManager?
|
private var updateManager: UpdateManager?
|
||||||
private var reminderWindowController: NSWindowController?
|
private var overlayReminderWindowController: NSWindowController?
|
||||||
|
private var subtleReminderWindowController: NSWindowController?
|
||||||
private var settingsWindowController: NSWindowController?
|
private var settingsWindowController: NSWindowController?
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
private var hasStartedTimers = false
|
private var hasStartedTimers = false
|
||||||
|
|
||||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||||
print("🚀 Gaze: applicationDidFinishLaunching")
|
|
||||||
|
|
||||||
// Set activation policy to hide dock icon
|
// Set activation policy to hide dock icon
|
||||||
NSApplication.shared.setActivationPolicy(.accessory)
|
NSApplication.shared.setActivationPolicy(.accessory)
|
||||||
print("✓ Activation policy set to accessory")
|
|
||||||
|
|
||||||
timerEngine = TimerEngine(settingsManager: settingsManager)
|
timerEngine = TimerEngine(settingsManager: settingsManager)
|
||||||
print("✓ TimerEngine initialized")
|
|
||||||
|
|
||||||
// Initialize update manager after onboarding is complete
|
// Initialize update manager after onboarding is complete
|
||||||
if settingsManager.settings.hasCompletedOnboarding {
|
if settingsManager.settings.hasCompletedOnboarding {
|
||||||
print("✓ Onboarding completed, initializing UpdateManager")
|
|
||||||
updateManager = UpdateManager.shared
|
updateManager = UpdateManager.shared
|
||||||
} else {
|
|
||||||
print("ℹ️ Onboarding not completed, skipping UpdateManager")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect App Store version asynchronously at launch
|
// Detect App Store version asynchronously at launch
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
print("🔍 Detecting App Store version...")
|
|
||||||
await settingsManager.detectAppStoreVersion()
|
await settingsManager.detectAppStoreVersion()
|
||||||
print("✓ App Store detection complete: \(settingsManager.settings.isAppStoreVersion)")
|
|
||||||
} catch {
|
} catch {
|
||||||
print("⚠️ Failed to detect App Store version: \(error)")
|
// Handle error silently in production
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupLifecycleObservers()
|
setupLifecycleObservers()
|
||||||
print("✓ Lifecycle observers set up")
|
|
||||||
|
|
||||||
observeSettingsChanges()
|
observeSettingsChanges()
|
||||||
print("✓ Settings change observer set up")
|
|
||||||
|
|
||||||
// Start timers if onboarding is complete
|
// Start timers if onboarding is complete
|
||||||
if settingsManager.settings.hasCompletedOnboarding {
|
if settingsManager.settings.hasCompletedOnboarding {
|
||||||
print("▶️ Starting timers (onboarding complete)")
|
|
||||||
startTimers()
|
startTimers()
|
||||||
} else {
|
|
||||||
print("⏸️ Timers not started (onboarding incomplete)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print("✅ Gaze: Launch complete")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func onboardingCompleted() {
|
func onboardingCompleted() {
|
||||||
@@ -130,7 +115,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
|||||||
timerEngine?.$activeReminder
|
timerEngine?.$activeReminder
|
||||||
.sink { [weak self] reminder in
|
.sink { [weak self] reminder in
|
||||||
guard let reminder = reminder else {
|
guard let reminder = reminder else {
|
||||||
self?.dismissReminder()
|
self?.dismissOverlayReminder()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self?.showReminder(reminder)
|
self?.showReminder(reminder)
|
||||||
@@ -185,10 +170,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showReminderWindow(contentView, requiresFocus: requiresFocus)
|
showReminderWindow(contentView, requiresFocus: requiresFocus, isOverlay: requiresFocus)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func showReminderWindow(_ content: AnyView, requiresFocus: Bool) {
|
private func showReminderWindow(_ content: AnyView, requiresFocus: Bool, isOverlay: Bool) {
|
||||||
guard let screen = NSScreen.main else { return }
|
guard let screen = NSScreen.main else { return }
|
||||||
|
|
||||||
let window: NSWindow
|
let window: NSWindow
|
||||||
@@ -229,12 +214,24 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
|||||||
window.orderFront(nil)
|
window.orderFront(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
reminderWindowController = windowController
|
// Track overlay and subtle reminders separately
|
||||||
|
if isOverlay {
|
||||||
|
overlayReminderWindowController?.close()
|
||||||
|
overlayReminderWindowController = windowController
|
||||||
|
} else {
|
||||||
|
subtleReminderWindowController?.close()
|
||||||
|
subtleReminderWindowController = windowController
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func dismissReminder() {
|
private func dismissOverlayReminder() {
|
||||||
reminderWindowController?.close()
|
overlayReminderWindowController?.close()
|
||||||
reminderWindowController = nil
|
overlayReminderWindowController = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dismissSubtleReminder() {
|
||||||
|
subtleReminderWindowController?.close()
|
||||||
|
subtleReminderWindowController = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public method to open settings window
|
// Public method to open settings window
|
||||||
|
|||||||
@@ -13,18 +13,12 @@ struct GazeApp: App {
|
|||||||
@StateObject private var settingsManager = SettingsManager.shared
|
@StateObject private var settingsManager = SettingsManager.shared
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
print("🚀 GazeApp: init")
|
|
||||||
|
|
||||||
// Handle test launch arguments
|
// Handle test launch arguments
|
||||||
if TestingEnvironment.shouldSkipOnboarding {
|
if TestingEnvironment.shouldSkipOnboarding {
|
||||||
print("ℹ️ Test mode: Skipping onboarding")
|
|
||||||
SettingsManager.shared.settings.hasCompletedOnboarding = true
|
SettingsManager.shared.settings.hasCompletedOnboarding = true
|
||||||
} else if TestingEnvironment.shouldResetOnboarding {
|
} else if TestingEnvironment.shouldResetOnboarding {
|
||||||
print("ℹ️ Test mode: Resetting onboarding")
|
|
||||||
SettingsManager.shared.settings.hasCompletedOnboarding = false
|
SettingsManager.shared.settings.hasCompletedOnboarding = false
|
||||||
}
|
}
|
||||||
|
|
||||||
print("✓ GazeApp initialized")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
|
|||||||
@@ -17,53 +17,38 @@ enum AppStoreDetector {
|
|||||||
/// This method is asynchronous due to the use of StoreKit's async API.
|
/// This method is asynchronous due to the use of StoreKit's async API.
|
||||||
static func isAppStoreVersion() async -> Bool {
|
static func isAppStoreVersion() async -> Bool {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
print("🔍 AppStoreDetector: DEBUG build, returning false")
|
|
||||||
return false
|
return false
|
||||||
#else
|
#else
|
||||||
print("🔍 AppStoreDetector: Checking App Store status...")
|
|
||||||
if #available(macOS 15.0, *) {
|
if #available(macOS 15.0, *) {
|
||||||
print(" ℹ️ Using macOS 15+ AppTransaction API")
|
|
||||||
do {
|
do {
|
||||||
let transaction = try await AppTransaction.shared
|
let transaction = try await AppTransaction.shared
|
||||||
print(" ✅ AppTransaction found: This is an App Store version")
|
|
||||||
return true
|
return true
|
||||||
} catch {
|
} catch {
|
||||||
print(" ⚠️ AppTransaction error: \(error.localizedDescription)")
|
|
||||||
print(" → Assuming NOT an App Store version")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fallback for older macOS: use legacy receipt check
|
// Fallback for older macOS: use legacy receipt check
|
||||||
print(" ℹ️ Using legacy receipt check (macOS <15)")
|
|
||||||
|
|
||||||
guard let receiptURL = Bundle.main.appStoreReceiptURL else {
|
guard let receiptURL = Bundle.main.appStoreReceiptURL else {
|
||||||
print(" ⚠️ No receipt URL available")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
print(" 📄 Receipt URL: \(receiptURL.path)")
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let fileExists = FileManager.default.fileExists(atPath: receiptURL.path)
|
let fileExists = FileManager.default.fileExists(atPath: receiptURL.path)
|
||||||
guard fileExists else {
|
guard fileExists else {
|
||||||
print(" ⚠️ Receipt file does not exist")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
print(" ✓ Receipt file exists")
|
|
||||||
|
|
||||||
guard let receiptData = try? Data(contentsOf: receiptURL),
|
guard let receiptData = try? Data(contentsOf: receiptURL),
|
||||||
receiptData.count > 2
|
receiptData.count > 2
|
||||||
else {
|
else {
|
||||||
print(" ⚠️ Receipt file is empty or unreadable")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
print(" ✓ Receipt data loaded (\(receiptData.count) bytes)")
|
|
||||||
|
|
||||||
let bytes = [UInt8](receiptData.prefix(2))
|
let bytes = [UInt8](receiptData.prefix(2))
|
||||||
let isValid = bytes[0] == 0x30 && bytes[1] == 0x82
|
let isValid = bytes[0] == 0x30 && bytes[1] == 0x82
|
||||||
print(" \(isValid ? "✅" : "⚠️") Receipt validation: \(isValid)")
|
|
||||||
return isValid
|
return isValid
|
||||||
} catch {
|
} catch {
|
||||||
print(" ❌ Receipt check error: \(error.localizedDescription)")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ class SettingsManager: ObservableObject {
|
|||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
self.settings = Self.loadSettings()
|
self.settings = Self.loadSettings()
|
||||||
#if DEBUG
|
|
||||||
validateTimerConfigMappings()
|
|
||||||
#endif
|
|
||||||
setupDebouncedSave()
|
setupDebouncedSave()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,34 +46,13 @@ class SettingsManager: ObservableObject {
|
|||||||
|
|
||||||
private static func loadSettings() -> AppSettings {
|
private static func loadSettings() -> AppSettings {
|
||||||
guard let data = UserDefaults.standard.data(forKey: "gazeAppSettings") else {
|
guard let data = UserDefaults.standard.data(forKey: "gazeAppSettings") else {
|
||||||
#if DEBUG
|
|
||||||
print("ℹ️ No saved settings found, using defaults")
|
|
||||||
#endif
|
|
||||||
return .defaults
|
return .defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let settings = try JSONDecoder().decode(AppSettings.self, from: data)
|
let settings = try JSONDecoder().decode(AppSettings.self, from: data)
|
||||||
#if DEBUG
|
|
||||||
print("✅ Settings loaded successfully (\(data.count) bytes)")
|
|
||||||
#endif
|
|
||||||
return settings
|
return settings
|
||||||
} catch {
|
} catch {
|
||||||
print("⚠️ Failed to decode settings, using defaults: \(error.localizedDescription)")
|
|
||||||
if let decodingError = error as? DecodingError {
|
|
||||||
switch decodingError {
|
|
||||||
case .keyNotFound(let key, let context):
|
|
||||||
print(" Missing key: \(key.stringValue) at path: \(context.codingPath)")
|
|
||||||
case .typeMismatch(let type, let context):
|
|
||||||
print(" Type mismatch for type: \(type) at path: \(context.codingPath)")
|
|
||||||
case .valueNotFound(let type, let context):
|
|
||||||
print(" Value not found for type: \(type) at path: \(context.codingPath)")
|
|
||||||
case .dataCorrupted(let context):
|
|
||||||
print(" Data corrupted at path: \(context.codingPath)")
|
|
||||||
@unknown default:
|
|
||||||
print(" Unknown decoding error: \(decodingError)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return .defaults
|
return .defaults
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,20 +66,7 @@ class SettingsManager: ObservableObject {
|
|||||||
encoder.outputFormatting = .prettyPrinted
|
encoder.outputFormatting = .prettyPrinted
|
||||||
let data = try encoder.encode(settings)
|
let data = try encoder.encode(settings)
|
||||||
userDefaults.set(data, forKey: settingsKey)
|
userDefaults.set(data, forKey: settingsKey)
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
print("✅ Settings saved successfully (\(data.count) bytes)")
|
|
||||||
#endif
|
|
||||||
} catch {
|
} catch {
|
||||||
print("❌ Failed to encode settings: \(error.localizedDescription)")
|
|
||||||
if let encodingError = error as? EncodingError {
|
|
||||||
switch encodingError {
|
|
||||||
case .invalidValue(let value, let context):
|
|
||||||
print(" Invalid value: \(value) at path: \(context.codingPath)")
|
|
||||||
default:
|
|
||||||
print(" Encoding error: \(encodingError)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ class UpdateManager: NSObject, ObservableObject {
|
|||||||
)
|
)
|
||||||
|
|
||||||
guard let updater = updaterController?.updater else {
|
guard let updater = updaterController?.updater else {
|
||||||
print("Failed to initialize Sparkle updater")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,12 +68,10 @@ class UpdateManager: NSObject, ObservableObject {
|
|||||||
func checkForUpdates() {
|
func checkForUpdates() {
|
||||||
#if !APPSTORE
|
#if !APPSTORE
|
||||||
guard let updater = updaterController?.updater else {
|
guard let updater = updaterController?.updater else {
|
||||||
print("Updater not initialized")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
updater.checkForUpdates()
|
updater.checkForUpdates()
|
||||||
#else
|
#else
|
||||||
print("Updates are managed by the App Store")
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ struct GeneralSetupView: View {
|
|||||||
try LaunchAtLoginManager.disable()
|
try LaunchAtLoginManager.disable()
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
print("Failed to set launch at login: \(error)")
|
// Failed to set launch at login - handled silently in production
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user