This commit is contained in:
Michael Freno
2026-01-08 10:37:03 -05:00
parent 3d8f4674dc
commit 650f5b2b15
7 changed files with 94 additions and 228 deletions

View File

@@ -10,8 +10,6 @@ import SwiftUI
struct BlinkSetupView: View {
@Binding var enabled: Bool
@Binding var intervalMinutes: Int
var onContinue: () -> Void
var onBack: (() -> Void)?
var body: some View {
VStack(spacing: 30) {
@@ -55,34 +53,8 @@ struct BlinkSetupView: View {
InfoBox(text: "We blink much less when focusing on screens. Regular blink reminders help prevent dry eyes")
Spacer()
HStack(spacing: 12) {
if let onBack = onBack {
Button(action: onBack) {
HStack {
Image(systemName: "chevron.left")
Text("Back")
}
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.interactive())
}
Button(action: onContinue) {
Text("Continue")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.tint(.blue).interactive())
}
.padding(.horizontal, 40)
}
.frame(width: 600, height: 500)
.frame(width: 600, height: 450)
.padding()
.background(.clear)
}
@@ -91,8 +63,6 @@ struct BlinkSetupView: View {
#Preview {
BlinkSetupView(
enabled: .constant(true),
intervalMinutes: .constant(5),
onContinue: {},
onBack: {}
intervalMinutes: .constant(5)
)
}

View File

@@ -9,7 +9,6 @@ import SwiftUI
struct CompletionView: View {
var onComplete: () -> Void
var onBack: (() -> Void)?
var body: some View {
VStack(spacing: 30) {
@@ -64,39 +63,13 @@ struct CompletionView: View {
.glassEffect(in: .rect(cornerRadius: 12))
Spacer()
HStack(spacing: 12) {
if let onBack = onBack {
Button(action: onBack) {
HStack {
Image(systemName: "chevron.left")
Text("Back")
}
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.interactive())
}
Button(action: onComplete) {
Text("Get Started")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.tint(.green).interactive())
}
.padding(.horizontal, 40)
}
.frame(width: 600, height: 500)
.frame(width: 600, height: 450)
.padding()
.background(.clear)
}
}
#Preview {
CompletionView(onComplete: {}, onBack: {})
CompletionView(onComplete: {})
}

View File

@@ -11,8 +11,6 @@ struct LookAwaySetupView: View {
@Binding var enabled: Bool
@Binding var intervalMinutes: Int
@Binding var countdownSeconds: Int
var onContinue: () -> Void
var onBack: (() -> Void)?
var body: some View {
VStack(spacing: 30) {
@@ -71,34 +69,8 @@ struct LookAwaySetupView: View {
InfoBox(text: "Every \(intervalMinutes) minutes, look in the distance for \(countdownSeconds) seconds to reduce eye strain")
Spacer()
HStack(spacing: 12) {
if let onBack = onBack {
Button(action: onBack) {
HStack {
Image(systemName: "chevron.left")
Text("Back")
}
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.interactive())
}
Button(action: onContinue) {
Text("Continue")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.tint(.blue).interactive())
}
.padding(.horizontal, 40)
}
.frame(width: 600, height: 500)
.frame(width: 600, height: 450)
.padding()
.background(.clear)
}
@@ -124,8 +96,6 @@ struct InfoBox: View {
LookAwaySetupView(
enabled: .constant(true),
intervalMinutes: .constant(20),
countdownSeconds: .constant(20),
onContinue: {},
onBack: {}
countdownSeconds: .constant(20)
)
}

View File

@@ -1,14 +1,6 @@
//
// OnboardingContainerView.swift
// Gaze
//
// Created by Mike Freno on 1/7/26.
//
import SwiftUI
import AppKit
import SwiftUI
// NSVisualEffectView wrapper for SwiftUI
struct VisualEffectView: NSViewRepresentable {
let material: NSVisualEffectView.Material
let blendingMode: NSVisualEffectView.BlendingMode
@@ -43,10 +35,8 @@ struct OnboardingContainerView: View {
var body: some View {
ZStack {
// Semi-transparent background with blur
VisualEffectView(material: .hudWindow, blendingMode: .behindWindow)
.ignoresSafeArea()
VStack(spacing: 0) {
TabView(selection: $currentPage) {
WelcomeView(
@@ -60,9 +50,7 @@ struct OnboardingContainerView: View {
LookAwaySetupView(
enabled: $lookAwayEnabled,
intervalMinutes: $lookAwayIntervalMinutes,
countdownSeconds: $lookAwayCountdownSeconds,
onContinue: { currentPage = 2 },
onBack: { currentPage = 0 }
countdownSeconds: $lookAwayCountdownSeconds
)
.tag(1)
.tabItem {
@@ -71,9 +59,7 @@ struct OnboardingContainerView: View {
BlinkSetupView(
enabled: $blinkEnabled,
intervalMinutes: $blinkIntervalMinutes,
onContinue: { currentPage = 3 },
onBack: { currentPage = 1 }
intervalMinutes: $blinkIntervalMinutes
)
.tag(2)
.tabItem {
@@ -82,9 +68,7 @@ struct OnboardingContainerView: View {
PostureSetupView(
enabled: $postureEnabled,
intervalMinutes: $postureIntervalMinutes,
onContinue: { currentPage = 4 },
onBack: { currentPage = 2 }
intervalMinutes: $postureIntervalMinutes
)
.tag(3)
.tabItem {
@@ -92,9 +76,7 @@ struct OnboardingContainerView: View {
}
SettingsOnboardingView(
launchAtLogin: $launchAtLogin,
onContinue: { currentPage = 5 },
onBack: { currentPage = 3 }
launchAtLogin: $launchAtLogin
)
.tag(4)
.tabItem {
@@ -104,8 +86,7 @@ struct OnboardingContainerView: View {
CompletionView(
onComplete: {
completeOnboarding()
},
onBack: { currentPage = 4 }
}
)
.tag(5)
.tabItem {
@@ -113,6 +94,39 @@ struct OnboardingContainerView: View {
}
}
.tabViewStyle(.automatic)
if currentPage >= 1 {
HStack(spacing: 12) {
Button(action: { currentPage -= 1 }) {
HStack {
Image(systemName: "chevron.left")
Text("Back")
}
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.interactive())
Button(action: {
if currentPage == 5 {
completeOnboarding()
} else {
currentPage += 1
}
}) {
Text(currentPage == 5 ? "Get Started" : "Continue")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.tint(currentPage == 5 ? .green : .blue).interactive())
}
.padding(.horizontal, 40)
.padding(.bottom, 20)
}
}
}
.opacity(isAnimatingOut ? 0 : 1)
@@ -157,7 +171,11 @@ struct OnboardingContainerView: View {
private func performVacuumAnimation() {
// Get the NSWindow reference
guard let window = NSApplication.shared.windows.first(where: { $0.isVisible && $0.contentView != nil }) else {
guard
let window = NSApplication.shared.windows.first(where: {
$0.isVisible && $0.contentView != nil
})
else {
// Fallback: just dismiss without animation
dismiss()
return
@@ -194,19 +212,17 @@ struct OnboardingContainerView: View {
}
// Animate window frame using AppKit
NSAnimationContext.runAnimationGroup({ context in
NSAnimationContext.runAnimationGroup(
{ context in
context.duration = 0.7
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
window.animator().setFrame(targetRect, display: true)
window.animator().alphaValue = 0
}, completionHandler: {
},
completionHandler: {
// Close window after animation completes
self.dismiss()
window.close()
})
}
}
#Preview {
OnboardingContainerView(settingsManager: SettingsManager.shared)
}

View File

@@ -10,8 +10,6 @@ import SwiftUI
struct PostureSetupView: View {
@Binding var enabled: Bool
@Binding var intervalMinutes: Int
var onContinue: () -> Void
var onBack: (() -> Void)?
var body: some View {
VStack(spacing: 30) {
@@ -55,34 +53,8 @@ struct PostureSetupView: View {
InfoBox(text: "Regular posture checks help prevent back and neck pain from prolonged sitting")
Spacer()
HStack(spacing: 12) {
if let onBack = onBack {
Button(action: onBack) {
HStack {
Image(systemName: "chevron.left")
Text("Back")
}
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.interactive())
}
Button(action: onContinue) {
Text("Continue")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.tint(.blue).interactive())
}
.padding(.horizontal, 40)
}
.frame(width: 600, height: 500)
.frame(width: 600, height: 450)
.padding()
.background(.clear)
}
@@ -91,8 +63,6 @@ struct PostureSetupView: View {
#Preview {
PostureSetupView(
enabled: .constant(true),
intervalMinutes: .constant(30),
onContinue: {},
onBack: {}
intervalMinutes: .constant(30)
)
}

View File

@@ -9,8 +9,6 @@ import SwiftUI
struct SettingsOnboardingView: View {
@Binding var launchAtLogin: Bool
var onContinue: () -> Void
var onBack: (() -> Void)?
var body: some View {
VStack(spacing: 30) {
@@ -116,34 +114,8 @@ struct SettingsOnboardingView: View {
}
Spacer()
HStack(spacing: 12) {
if let onBack = onBack {
Button(action: onBack) {
HStack {
Image(systemName: "chevron.left")
Text("Back")
}
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.interactive())
}
Button(action: onContinue) {
Text("Continue")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.plain)
.glassEffect(.regular.tint(.blue).interactive())
}
.padding(.horizontal, 40)
}
.frame(width: 600, height: 500)
.frame(width: 600, height: 450)
.padding()
.background(.clear)
}
@@ -163,8 +135,6 @@ struct SettingsOnboardingView: View {
#Preview {
SettingsOnboardingView(
launchAtLogin: .constant(false),
onContinue: {},
onBack: {}
launchAtLogin: .constant(false)
)
}

15
run
View File

@@ -4,7 +4,7 @@
# Usage: ./run [build|test|run]
# Default action is build and run
ACTION=${1:-build}
ACTION=${1:-run}
VERBOSE=false
OUTPUT_FILE=""
@@ -71,20 +71,17 @@ elif [ "$ACTION" = "test" ]; then
fi
elif [ "$ACTION" = "run" ]; then
echo "Running Gaze application..."
# First ensure we have a built app
if [ -d "build/Debug/Gaze.app" ]; then
run_with_output "open -a \"Gaze\""
else
echo "⚠️ No built app found. Building first..."
echo "Building and running Gaze application..."
# Always build first, then run
run_with_output "xcodebuild -project Gaze.xcodeproj -scheme Gaze -configuration Debug build"
if [ $? -eq 0 ]; then
echo "✅ Build succeeded!"
run_with_output "open -a \"Gaze\""
else
echo "❌ Build failed during run attempt!"
echo "❌ Build failed!"
exit 1
fi
fi
else
echo "Usage: $0 [build|test|run] [-v|--verbose] [-o|--output <file_name>]"