general: testing and simplifying

This commit is contained in:
Michael Freno
2026-01-14 19:59:45 -05:00
parent 2aaffd5df0
commit 8815315059
4 changed files with 43 additions and 99 deletions

View File

@@ -76,6 +76,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
.sink { [weak self] smartMode in
self?.idleService?.updateThreshold(minutes: smartMode.idleThresholdMinutes)
self?.usageTrackingService?.updateResetThreshold(minutes: smartMode.usageResetAfterMinutes)
// Force state check when settings change to apply immediately
self?.fullscreenService?.forceUpdate()
self?.idleService?.forceUpdate()
}
.store(in: &cancellables)
}

View File

@@ -20,7 +20,7 @@ enum EyeTrackingConstants {
// MARK: - Face Pose Thresholds
/// Maximum yaw (left/right head turn) in radians before considering user looking away
/// 0.20 radians 11.5 degrees (Tightened from 0.35)
static let yawThreshold: Double = 0.20
static let yawThreshold: Double = 0.1
/// Pitch threshold for looking UP (above screen).
/// Since camera is at top, looking at screen is negative pitch.
@@ -29,7 +29,7 @@ enum EyeTrackingConstants {
/// Pitch threshold for looking DOWN (at keyboard/lap).
/// Values < -0.45 imply looking too far down.
static let pitchDownThreshold: Double = -0.45
static let pitchDownThreshold: Double = -0.2
// MARK: - Pupil Tracking Thresholds
/// Minimum horizontal pupil ratio (0.0 = right edge, 1.0 = left edge)

View File

@@ -24,10 +24,6 @@ class EyeTrackingService: NSObject, ObservableObject {
label: "com.gaze.videoDataOutput", qos: .userInitiated)
private var _previewLayer: AVCaptureVideoPreviewLayer?
// Logging throttle
private var lastLogTime: Date = .distantPast
private let logInterval: TimeInterval = EyeTrackingConstants.logInterval
var previewLayer: AVCaptureVideoPreviewLayer? {
guard let session = captureSession else {
_previewLayer = nil
@@ -190,7 +186,9 @@ class EyeTrackingService: NSObject, ObservableObject {
// - Camera at top = looking at screen is negative pitch
// - Looking above screen (straight ahead) is ~0 or positive -> Look Away
// - Looking at keyboard/lap is very negative -> Look Away
let pitchLookingAway = pitch > EyeTrackingConstants.pitchUpThreshold || pitch < EyeTrackingConstants.pitchDownThreshold
let pitchLookingAway =
pitch > EyeTrackingConstants.pitchUpThreshold
|| pitch < EyeTrackingConstants.pitchDownThreshold
let poseLookingAway = abs(yaw) > yawThreshold || pitchLookingAway

View File

@@ -18,87 +18,18 @@ struct SettingsWindowView: View {
var body: some View {
VStack(spacing: 0) {
if #available(macOS 15.0, *) {
TabView(selection: $selectedSection) {
Tab(
SettingsSection.general.title,
systemImage: SettingsSection.general.iconName,
value: SettingsSection.general
) {
GeneralSetupView(
settingsManager: settingsManager,
isOnboarding: false
)
}
Tab(
SettingsSection.lookAway.title,
systemImage: SettingsSection.lookAway.iconName,
value: SettingsSection.lookAway
) {
LookAwaySetupView(settingsManager: settingsManager)
}
Tab(
SettingsSection.blink.title, systemImage: SettingsSection.blink.iconName,
value: SettingsSection.blink
) {
BlinkSetupView(settingsManager: settingsManager)
}
Tab(
SettingsSection.posture.title,
systemImage: SettingsSection.posture.iconName,
value: SettingsSection.posture
) {
PostureSetupView(settingsManager: settingsManager)
}
Tab(
SettingsSection.userTimers.title,
systemImage: SettingsSection.userTimers.iconName,
value: SettingsSection.userTimers
) {
UserTimersView(
userTimers: Binding(
get: { settingsManager.settings.userTimers },
set: { settingsManager.settings.userTimers = $0 }
)
)
}
Tab(
SettingsSection.enforceMode.title,
systemImage: SettingsSection.enforceMode.iconName,
value: SettingsSection.enforceMode
) {
EnforceModeSetupView(settingsManager: settingsManager)
}
Tab(
SettingsSection.smartMode.title,
systemImage: SettingsSection.smartMode.iconName,
value: SettingsSection.smartMode
) {
SmartModeSetupView(settingsManager: settingsManager)
NavigationSplitView {
List(SettingsSection.allCases, selection: $selectedSection) { section in
NavigationLink(value: section) {
Label(section.title, systemImage: section.iconName)
}
}
.tabViewStyle(.sidebarAdaptable)
} else {
// Fallback for macOS 14 and earlier - use a consistent sidebar approach without collapse button
NavigationSplitView {
List(SettingsSection.allCases, selection: $selectedSection) { section in
NavigationLink(value: section) {
Label(section.title, systemImage: section.iconName)
}
}
.navigationTitle("Settings")
.listStyle(.sidebar)
} detail: {
detailView(for: selectedSection)
}
// Disable the ability to collapse the sidebar by explicitly setting a fixed width
.navigationSplitViewColumnWidth(min: 200, ideal: 250, max: 300)
.navigationTitle("Settings")
.listStyle(.sidebar)
} detail: {
detailView(for: selectedSection)
}
.navigationSplitViewColumnWidth(min: 200, ideal: 250, max: 300)
Divider()
@@ -178,16 +109,27 @@ struct SettingsWindowView: View {
#if DEBUG
private func retriggerOnboarding() {
// Close settings window first
// Get AppDelegate reference first
guard let appDelegate = NSApplication.shared.delegate as? AppDelegate else { return }
// Step 1: Close any existing onboarding window
if let onboardingWindow = NSApplication.shared.windows.first(where: {
$0.identifier == WindowIdentifiers.onboarding
}) {
onboardingWindow.close()
}
// Step 2: Close settings window
closeWindow()
// Get AppDelegate and open onboarding
if let appDelegate = NSApplication.shared.delegate as? AppDelegate {
// Reset onboarding state so it shows as fresh
settingsManager.settings.hasCompletedOnboarding = false
// Step 3: Reset onboarding state with a delay to ensure settings window is closed
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
self.settingsManager.settings.hasCompletedOnboarding = false
// Open onboarding window
appDelegate.openOnboarding()
// Step 4: Open onboarding window with another delay to ensure state is saved
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
appDelegate.openOnboarding()
}
}
}
#endif