This commit is contained in:
Michael Freno
2026-01-29 19:03:20 -05:00
parent 3425a2cdbb
commit 1a43a2a1a0
4 changed files with 105 additions and 81 deletions

View File

@@ -13,7 +13,9 @@ enum SettingsSection: Int, CaseIterable, Identifiable {
case blink = 2
case posture = 3
case userTimers = 4
case enforceMode = 5
#if ENFORCE_READY
case enforceMode = 5
#endif
case smartMode = 6
var id: Int { rawValue }
@@ -24,7 +26,9 @@ enum SettingsSection: Int, CaseIterable, Identifiable {
case .lookAway: return "Look Away"
case .blink: return "Blink"
case .posture: return "Posture"
case .enforceMode: return "Enforce Mode"
#if ENFORCE_READY
case .enforceMode: return "Enforce Mode"
#endif
case .userTimers: return "User Timers"
case .smartMode: return "Smart Mode"
}
@@ -36,7 +40,9 @@ enum SettingsSection: Int, CaseIterable, Identifiable {
case .lookAway: return "eye.fill"
case .blink: return "eye.circle.fill"
case .posture: return "figure.stand"
case .enforceMode: return "video.fill"
#if ENFORCE_READY
case .enforceMode: return "video.fill"
#endif
case .userTimers: return "plus.circle"
case .smartMode: return "brain.fill"
}

View File

@@ -39,15 +39,22 @@ struct AdditionalModifiersView: View {
.font(isCompact ? .subheadline : .title3)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
#if !ENFORCE_READY
Text("More to come soon")
.font(isCompact ? .subheadline : .title3)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
#endif
Spacer()
ZStack {
cardView(for: 0, width: cardWidth, height: cardHeight)
.zIndex(zIndex(for: 0))
.scaleEffect(scale(for: 0))
.offset(x: xOffset(for: 0), y: yOffset(for: 0))
#if ENFORCE_READY
cardView(for: 0, width: cardWidth, height: cardHeight)
.zIndex(zIndex(for: 0))
.scaleEffect(scale(for: 0))
.offset(x: xOffset(for: 0), y: yOffset(for: 0))
#endif
cardView(for: 1, width: cardWidth, height: cardHeight)
.zIndex(zIndex(for: 1))
.scaleEffect(scale(for: 1))
@@ -58,41 +65,42 @@ struct AdditionalModifiersView: View {
Spacer()
// Navigation controls
HStack(spacing: isCompact ? 12 : 20) {
Button(action: { swapCards() }) {
Image(systemName: "chevron.left")
.font(isCompact ? .body : .title2)
.frame(width: isCompact ? 36 : 44, height: isCompact ? 36 : 44)
.contentShape(.rect)
}
.buttonStyle(.plain)
.glassEffectIfAvailable(
GlassStyle.regular.interactive(), in: .rect(cornerRadius: 10)
)
.opacity(frontCardIndex == 0 ? 0.3 : 1.0)
.disabled(frontCardIndex == 0)
#if ENFORCE_READY
HStack(spacing: isCompact ? 12 : 20) {
Button(action: { swapCards() }) {
Image(systemName: "chevron.left")
.font(isCompact ? .body : .title2)
.frame(width: isCompact ? 36 : 44, height: isCompact ? 36 : 44)
.contentShape(.rect)
}
.buttonStyle(.plain)
.glassEffectIfAvailable(
GlassStyle.regular.interactive(), in: .rect(cornerRadius: 10)
)
.opacity(frontCardIndex == 0 ? 0.3 : 1.0)
.disabled(frontCardIndex == 0)
// Page indicators with labels
HStack(spacing: isCompact ? 10 : 16) {
cardIndicator(index: 0, icon: "video.fill", label: "Enforce")
cardIndicator(index: 1, icon: "brain.fill", label: "Smart")
}.padding(.all, 20)
// Page indicators with labels
HStack(spacing: isCompact ? 10 : 16) {
cardIndicator(index: 0, icon: "video.fill", label: "Enforce")
cardIndicator(index: 1, icon: "brain.fill", label: "Smart")
}.padding(.all, 20)
Button(action: { swapCards() }) {
Image(systemName: "chevron.right")
.font(isCompact ? .body : .title2)
.frame(width: isCompact ? 36 : 44, height: isCompact ? 36 : 44)
.contentShape(.rect)
Button(action: { swapCards() }) {
Image(systemName: "chevron.right")
.font(isCompact ? .body : .title2)
.frame(width: isCompact ? 36 : 44, height: isCompact ? 36 : 44)
.contentShape(.rect)
}
.buttonStyle(.plain)
.glassEffectIfAvailable(
GlassStyle.regular.interactive(), in: .rect(cornerRadius: 10)
)
.opacity(frontCardIndex == 1 ? 0.3 : 1.0)
.disabled(frontCardIndex == 1)
}
.buttonStyle(.plain)
.glassEffectIfAvailable(
GlassStyle.regular.interactive(), in: .rect(cornerRadius: 10)
)
.opacity(frontCardIndex == 1 ? 0.3 : 1.0)
.disabled(frontCardIndex == 1)
}
.padding(.bottom, isCompact ? 6 : 10)
.padding(.bottom, isCompact ? 6 : 10)
#endif
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding()
@@ -254,20 +262,23 @@ struct AdditionalModifiersView: View {
}
}
Spacer()
Toggle("", isOn: Binding(
get: {
settingsManager.isTimerEnabled(for: .lookAway) ||
settingsManager.isTimerEnabled(for: .blink) ||
settingsManager.isTimerEnabled(for: .posture)
},
set: { newValue in
if newValue {
Task { @MainActor in
try await cameraService.requestCameraAccess()
Toggle(
"",
isOn: Binding(
get: {
settingsManager.isTimerEnabled(for: .lookAway)
|| settingsManager.isTimerEnabled(for: .blink)
|| settingsManager.isTimerEnabled(for: .posture)
},
set: { newValue in
if newValue {
Task { @MainActor in
try await cameraService.requestCameraAccess()
}
}
}
}
))
)
)
.labelsHidden()
.disabled(!cameraService.hasCameraHardware)
.controlSize(isCompact ? .small : .regular)
@@ -364,13 +375,15 @@ struct AdditionalModifiersView: View {
isOn: $settingsManager.settings.smartMode.autoPauseOnIdle
)
smartModeToggle(
icon: "chart.line.uptrend.xyaxis",
iconColor: .green,
title: "Track Usage Statistics",
subtitle: "Monitor active and idle time",
isOn: $settingsManager.settings.smartMode.trackUsage
)
#if TRACK_READY
smartModeToggle(
icon: "chart.line.uptrend.xyaxis",
iconColor: .green,
title: "Track Usage Statistics",
subtitle: "Monitor active and idle time",
isOn: $settingsManager.settings.smartMode.trackUsage
)
#endif
}
Spacer()

View File

@@ -28,7 +28,7 @@ struct SettingsWindowView: View {
settingsContent
#if DEBUG
debugFooter(isCompact: isCompact)
debugFooter(isCompact: isCompact)
#endif
}
}
@@ -42,7 +42,8 @@ struct SettingsWindowView: View {
)
.onReceive(tabSwitchPublisher) { notification in
if let tab = notification.object as? Int,
let section = SettingsSection(rawValue: tab) {
let section = SettingsSection(rawValue: tab)
{
selectedSection = section
}
}
@@ -78,8 +79,10 @@ struct SettingsWindowView: View {
BlinkSetupView(settingsManager: settingsManager)
case .posture:
PostureSetupView(settingsManager: settingsManager)
case .enforceMode:
EnforceModeSetupView(settingsManager: settingsManager)
#if ENFORCE_READY
case .enforceMode:
EnforceModeSetupView(settingsManager: settingsManager)
#endif
case .userTimers:
UserTimersView(
userTimers: Binding(
@@ -99,27 +102,27 @@ struct SettingsWindowView: View {
}
#if DEBUG
@ViewBuilder
private func debugFooter(isCompact: Bool) -> some View {
Divider()
HStack {
Button("Retrigger Onboarding") {
retriggerOnboarding()
@ViewBuilder
private func debugFooter(isCompact: Bool) -> some View {
Divider()
HStack {
Button("Retrigger Onboarding") {
retriggerOnboarding()
}
.buttonStyle(.bordered)
.controlSize(isCompact ? .small : .regular)
Spacer()
}
.buttonStyle(.bordered)
.controlSize(isCompact ? .small : .regular)
Spacer()
.padding(isCompact ? 8 : 16)
}
.padding(isCompact ? 8 : 16)
}
private func retriggerOnboarding() {
SettingsWindowPresenter.shared.close()
settingsManager.settings.hasCompletedOnboarding = false
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
OnboardingWindowPresenter.shared.show(settingsManager: settingsManager)
private func retriggerOnboarding() {
SettingsWindowPresenter.shared.close()
settingsManager.settings.hasCompletedOnboarding = false
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
OnboardingWindowPresenter.shared.show(settingsManager: settingsManager)
}
}
}
#endif
}

View File

@@ -25,7 +25,9 @@ struct SmartModeSetupView: View {
VStack(spacing: 24) {
fullscreenSection
idleSection
usageTrackingSection
#if TRACK_READY
usageTrackingSection
#endif
}
.frame(maxWidth: 600)