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

View File

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

View File

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

View File

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