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 .sink { [weak self] smartMode in
self?.idleService?.updateThreshold(minutes: smartMode.idleThresholdMinutes) self?.idleService?.updateThreshold(minutes: smartMode.idleThresholdMinutes)
self?.usageTrackingService?.updateResetThreshold(minutes: smartMode.usageResetAfterMinutes) self?.usageTrackingService?.updateResetThreshold(minutes: smartMode.usageResetAfterMinutes)
// Force state check when settings change to apply immediately
self?.fullscreenService?.forceUpdate()
self?.idleService?.forceUpdate()
} }
.store(in: &cancellables) .store(in: &cancellables)
} }

View File

@@ -20,7 +20,7 @@ enum EyeTrackingConstants {
// MARK: - Face Pose Thresholds // MARK: - Face Pose Thresholds
/// Maximum yaw (left/right head turn) in radians before considering user looking away /// Maximum yaw (left/right head turn) in radians before considering user looking away
/// 0.20 radians 11.5 degrees (Tightened from 0.35) /// 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). /// Pitch threshold for looking UP (above screen).
/// Since camera is at top, looking at screen is negative pitch. /// 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). /// Pitch threshold for looking DOWN (at keyboard/lap).
/// Values < -0.45 imply looking too far down. /// Values < -0.45 imply looking too far down.
static let pitchDownThreshold: Double = -0.45 static let pitchDownThreshold: Double = -0.2
// MARK: - Pupil Tracking Thresholds // MARK: - Pupil Tracking Thresholds
/// Minimum horizontal pupil ratio (0.0 = right edge, 1.0 = left edge) /// 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) label: "com.gaze.videoDataOutput", qos: .userInitiated)
private var _previewLayer: AVCaptureVideoPreviewLayer? private var _previewLayer: AVCaptureVideoPreviewLayer?
// Logging throttle
private var lastLogTime: Date = .distantPast
private let logInterval: TimeInterval = EyeTrackingConstants.logInterval
var previewLayer: AVCaptureVideoPreviewLayer? { var previewLayer: AVCaptureVideoPreviewLayer? {
guard let session = captureSession else { guard let session = captureSession else {
_previewLayer = nil _previewLayer = nil
@@ -190,7 +186,9 @@ class EyeTrackingService: NSObject, ObservableObject {
// - Camera at top = looking at screen is negative pitch // - Camera at top = looking at screen is negative pitch
// - Looking above screen (straight ahead) is ~0 or positive -> Look Away // - Looking above screen (straight ahead) is ~0 or positive -> Look Away
// - Looking at keyboard/lap is very negative -> 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 let poseLookingAway = abs(yaw) > yawThreshold || pitchLookingAway

View File

@@ -18,87 +18,18 @@ struct SettingsWindowView: View {
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
if #available(macOS 15.0, *) { NavigationSplitView {
TabView(selection: $selectedSection) { List(SettingsSection.allCases, selection: $selectedSection) { section in
Tab( NavigationLink(value: section) {
SettingsSection.general.title, Label(section.title, systemImage: section.iconName)
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)
} }
} }
.tabViewStyle(.sidebarAdaptable) .navigationTitle("Settings")
} else { .listStyle(.sidebar)
// Fallback for macOS 14 and earlier - use a consistent sidebar approach without collapse button } detail: {
NavigationSplitView { detailView(for: selectedSection)
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)
} }
.navigationSplitViewColumnWidth(min: 200, ideal: 250, max: 300)
Divider() Divider()
@@ -178,16 +109,27 @@ struct SettingsWindowView: View {
#if DEBUG #if DEBUG
private func retriggerOnboarding() { 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() closeWindow()
// Get AppDelegate and open onboarding // Step 3: Reset onboarding state with a delay to ensure settings window is closed
if let appDelegate = NSApplication.shared.delegate as? AppDelegate { DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
// Reset onboarding state so it shows as fresh self.settingsManager.settings.hasCompletedOnboarding = false
settingsManager.settings.hasCompletedOnboarding = false
// Open onboarding window // Step 4: Open onboarding window with another delay to ensure state is saved
appDelegate.openOnboarding() DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
appDelegate.openOnboarding()
}
} }
} }
#endif #endif