guh
This commit is contained in:
@@ -10,8 +10,6 @@ import SwiftUI
|
|||||||
struct BlinkSetupView: View {
|
struct BlinkSetupView: View {
|
||||||
@Binding var enabled: Bool
|
@Binding var enabled: Bool
|
||||||
@Binding var intervalMinutes: Int
|
@Binding var intervalMinutes: Int
|
||||||
var onContinue: () -> Void
|
|
||||||
var onBack: (() -> Void)?
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 30) {
|
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")
|
InfoBox(text: "We blink much less when focusing on screens. Regular blink reminders help prevent dry eyes")
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 12) {
|
|
||||||
if let onBack = onBack {
|
|
||||||
Button(action: onBack) {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "chevron.left")
|
|
||||||
Text("Back")
|
|
||||||
}
|
}
|
||||||
.font(.headline)
|
.frame(width: 600, height: 450)
|
||||||
.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)
|
|
||||||
.padding()
|
.padding()
|
||||||
.background(.clear)
|
.background(.clear)
|
||||||
}
|
}
|
||||||
@@ -91,8 +63,6 @@ struct BlinkSetupView: View {
|
|||||||
#Preview {
|
#Preview {
|
||||||
BlinkSetupView(
|
BlinkSetupView(
|
||||||
enabled: .constant(true),
|
enabled: .constant(true),
|
||||||
intervalMinutes: .constant(5),
|
intervalMinutes: .constant(5)
|
||||||
onContinue: {},
|
|
||||||
onBack: {}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import SwiftUI
|
|||||||
|
|
||||||
struct CompletionView: View {
|
struct CompletionView: View {
|
||||||
var onComplete: () -> Void
|
var onComplete: () -> Void
|
||||||
var onBack: (() -> Void)?
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 30) {
|
VStack(spacing: 30) {
|
||||||
@@ -64,39 +63,13 @@ struct CompletionView: View {
|
|||||||
.glassEffect(in: .rect(cornerRadius: 12))
|
.glassEffect(in: .rect(cornerRadius: 12))
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 12) {
|
|
||||||
if let onBack = onBack {
|
|
||||||
Button(action: onBack) {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "chevron.left")
|
|
||||||
Text("Back")
|
|
||||||
}
|
}
|
||||||
.font(.headline)
|
.frame(width: 600, height: 450)
|
||||||
.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)
|
|
||||||
.padding()
|
.padding()
|
||||||
.background(.clear)
|
.background(.clear)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
CompletionView(onComplete: {}, onBack: {})
|
CompletionView(onComplete: {})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ struct LookAwaySetupView: View {
|
|||||||
@Binding var enabled: Bool
|
@Binding var enabled: Bool
|
||||||
@Binding var intervalMinutes: Int
|
@Binding var intervalMinutes: Int
|
||||||
@Binding var countdownSeconds: Int
|
@Binding var countdownSeconds: Int
|
||||||
var onContinue: () -> Void
|
|
||||||
var onBack: (() -> Void)?
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 30) {
|
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")
|
InfoBox(text: "Every \(intervalMinutes) minutes, look in the distance for \(countdownSeconds) seconds to reduce eye strain")
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 12) {
|
|
||||||
if let onBack = onBack {
|
|
||||||
Button(action: onBack) {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "chevron.left")
|
|
||||||
Text("Back")
|
|
||||||
}
|
}
|
||||||
.font(.headline)
|
.frame(width: 600, height: 450)
|
||||||
.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)
|
|
||||||
.padding()
|
.padding()
|
||||||
.background(.clear)
|
.background(.clear)
|
||||||
}
|
}
|
||||||
@@ -124,8 +96,6 @@ struct InfoBox: View {
|
|||||||
LookAwaySetupView(
|
LookAwaySetupView(
|
||||||
enabled: .constant(true),
|
enabled: .constant(true),
|
||||||
intervalMinutes: .constant(20),
|
intervalMinutes: .constant(20),
|
||||||
countdownSeconds: .constant(20),
|
countdownSeconds: .constant(20)
|
||||||
onContinue: {},
|
|
||||||
onBack: {}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
//
|
|
||||||
// OnboardingContainerView.swift
|
|
||||||
// Gaze
|
|
||||||
//
|
|
||||||
// Created by Mike Freno on 1/7/26.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import AppKit
|
import AppKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
// NSVisualEffectView wrapper for SwiftUI
|
|
||||||
struct VisualEffectView: NSViewRepresentable {
|
struct VisualEffectView: NSViewRepresentable {
|
||||||
let material: NSVisualEffectView.Material
|
let material: NSVisualEffectView.Material
|
||||||
let blendingMode: NSVisualEffectView.BlendingMode
|
let blendingMode: NSVisualEffectView.BlendingMode
|
||||||
@@ -43,10 +35,8 @@ struct OnboardingContainerView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
// Semi-transparent background with blur
|
|
||||||
VisualEffectView(material: .hudWindow, blendingMode: .behindWindow)
|
VisualEffectView(material: .hudWindow, blendingMode: .behindWindow)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
TabView(selection: $currentPage) {
|
TabView(selection: $currentPage) {
|
||||||
WelcomeView(
|
WelcomeView(
|
||||||
@@ -60,9 +50,7 @@ struct OnboardingContainerView: View {
|
|||||||
LookAwaySetupView(
|
LookAwaySetupView(
|
||||||
enabled: $lookAwayEnabled,
|
enabled: $lookAwayEnabled,
|
||||||
intervalMinutes: $lookAwayIntervalMinutes,
|
intervalMinutes: $lookAwayIntervalMinutes,
|
||||||
countdownSeconds: $lookAwayCountdownSeconds,
|
countdownSeconds: $lookAwayCountdownSeconds
|
||||||
onContinue: { currentPage = 2 },
|
|
||||||
onBack: { currentPage = 0 }
|
|
||||||
)
|
)
|
||||||
.tag(1)
|
.tag(1)
|
||||||
.tabItem {
|
.tabItem {
|
||||||
@@ -71,9 +59,7 @@ struct OnboardingContainerView: View {
|
|||||||
|
|
||||||
BlinkSetupView(
|
BlinkSetupView(
|
||||||
enabled: $blinkEnabled,
|
enabled: $blinkEnabled,
|
||||||
intervalMinutes: $blinkIntervalMinutes,
|
intervalMinutes: $blinkIntervalMinutes
|
||||||
onContinue: { currentPage = 3 },
|
|
||||||
onBack: { currentPage = 1 }
|
|
||||||
)
|
)
|
||||||
.tag(2)
|
.tag(2)
|
||||||
.tabItem {
|
.tabItem {
|
||||||
@@ -82,9 +68,7 @@ struct OnboardingContainerView: View {
|
|||||||
|
|
||||||
PostureSetupView(
|
PostureSetupView(
|
||||||
enabled: $postureEnabled,
|
enabled: $postureEnabled,
|
||||||
intervalMinutes: $postureIntervalMinutes,
|
intervalMinutes: $postureIntervalMinutes
|
||||||
onContinue: { currentPage = 4 },
|
|
||||||
onBack: { currentPage = 2 }
|
|
||||||
)
|
)
|
||||||
.tag(3)
|
.tag(3)
|
||||||
.tabItem {
|
.tabItem {
|
||||||
@@ -92,9 +76,7 @@ struct OnboardingContainerView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingsOnboardingView(
|
SettingsOnboardingView(
|
||||||
launchAtLogin: $launchAtLogin,
|
launchAtLogin: $launchAtLogin
|
||||||
onContinue: { currentPage = 5 },
|
|
||||||
onBack: { currentPage = 3 }
|
|
||||||
)
|
)
|
||||||
.tag(4)
|
.tag(4)
|
||||||
.tabItem {
|
.tabItem {
|
||||||
@@ -104,8 +86,7 @@ struct OnboardingContainerView: View {
|
|||||||
CompletionView(
|
CompletionView(
|
||||||
onComplete: {
|
onComplete: {
|
||||||
completeOnboarding()
|
completeOnboarding()
|
||||||
},
|
}
|
||||||
onBack: { currentPage = 4 }
|
|
||||||
)
|
)
|
||||||
.tag(5)
|
.tag(5)
|
||||||
.tabItem {
|
.tabItem {
|
||||||
@@ -113,6 +94,39 @@ struct OnboardingContainerView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tabViewStyle(.automatic)
|
.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)
|
.opacity(isAnimatingOut ? 0 : 1)
|
||||||
@@ -157,7 +171,11 @@ struct OnboardingContainerView: View {
|
|||||||
|
|
||||||
private func performVacuumAnimation() {
|
private func performVacuumAnimation() {
|
||||||
// Get the NSWindow reference
|
// 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
|
// Fallback: just dismiss without animation
|
||||||
dismiss()
|
dismiss()
|
||||||
return
|
return
|
||||||
@@ -194,19 +212,17 @@ struct OnboardingContainerView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Animate window frame using AppKit
|
// Animate window frame using AppKit
|
||||||
NSAnimationContext.runAnimationGroup({ context in
|
NSAnimationContext.runAnimationGroup(
|
||||||
|
{ context in
|
||||||
context.duration = 0.7
|
context.duration = 0.7
|
||||||
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
|
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
|
||||||
window.animator().setFrame(targetRect, display: true)
|
window.animator().setFrame(targetRect, display: true)
|
||||||
window.animator().alphaValue = 0
|
window.animator().alphaValue = 0
|
||||||
}, completionHandler: {
|
},
|
||||||
|
completionHandler: {
|
||||||
// Close window after animation completes
|
// Close window after animation completes
|
||||||
self.dismiss()
|
self.dismiss()
|
||||||
window.close()
|
window.close()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
|
||||||
OnboardingContainerView(settingsManager: SettingsManager.shared)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import SwiftUI
|
|||||||
struct PostureSetupView: View {
|
struct PostureSetupView: View {
|
||||||
@Binding var enabled: Bool
|
@Binding var enabled: Bool
|
||||||
@Binding var intervalMinutes: Int
|
@Binding var intervalMinutes: Int
|
||||||
var onContinue: () -> Void
|
|
||||||
var onBack: (() -> Void)?
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 30) {
|
VStack(spacing: 30) {
|
||||||
@@ -55,34 +53,8 @@ struct PostureSetupView: View {
|
|||||||
InfoBox(text: "Regular posture checks help prevent back and neck pain from prolonged sitting")
|
InfoBox(text: "Regular posture checks help prevent back and neck pain from prolonged sitting")
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 12) {
|
|
||||||
if let onBack = onBack {
|
|
||||||
Button(action: onBack) {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "chevron.left")
|
|
||||||
Text("Back")
|
|
||||||
}
|
}
|
||||||
.font(.headline)
|
.frame(width: 600, height: 450)
|
||||||
.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)
|
|
||||||
.padding()
|
.padding()
|
||||||
.background(.clear)
|
.background(.clear)
|
||||||
}
|
}
|
||||||
@@ -91,8 +63,6 @@ struct PostureSetupView: View {
|
|||||||
#Preview {
|
#Preview {
|
||||||
PostureSetupView(
|
PostureSetupView(
|
||||||
enabled: .constant(true),
|
enabled: .constant(true),
|
||||||
intervalMinutes: .constant(30),
|
intervalMinutes: .constant(30)
|
||||||
onContinue: {},
|
|
||||||
onBack: {}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import SwiftUI
|
|||||||
|
|
||||||
struct SettingsOnboardingView: View {
|
struct SettingsOnboardingView: View {
|
||||||
@Binding var launchAtLogin: Bool
|
@Binding var launchAtLogin: Bool
|
||||||
var onContinue: () -> Void
|
|
||||||
var onBack: (() -> Void)?
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 30) {
|
VStack(spacing: 30) {
|
||||||
@@ -116,34 +114,8 @@ struct SettingsOnboardingView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 12) {
|
|
||||||
if let onBack = onBack {
|
|
||||||
Button(action: onBack) {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "chevron.left")
|
|
||||||
Text("Back")
|
|
||||||
}
|
}
|
||||||
.font(.headline)
|
.frame(width: 600, height: 450)
|
||||||
.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)
|
|
||||||
.padding()
|
.padding()
|
||||||
.background(.clear)
|
.background(.clear)
|
||||||
}
|
}
|
||||||
@@ -163,8 +135,6 @@ struct SettingsOnboardingView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
SettingsOnboardingView(
|
SettingsOnboardingView(
|
||||||
launchAtLogin: .constant(false),
|
launchAtLogin: .constant(false)
|
||||||
onContinue: {},
|
|
||||||
onBack: {}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
15
run
15
run
@@ -4,7 +4,7 @@
|
|||||||
# Usage: ./run [build|test|run]
|
# Usage: ./run [build|test|run]
|
||||||
|
|
||||||
# Default action is build and run
|
# Default action is build and run
|
||||||
ACTION=${1:-build}
|
ACTION=${1:-run}
|
||||||
VERBOSE=false
|
VERBOSE=false
|
||||||
OUTPUT_FILE=""
|
OUTPUT_FILE=""
|
||||||
|
|
||||||
@@ -71,20 +71,17 @@ elif [ "$ACTION" = "test" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
elif [ "$ACTION" = "run" ]; then
|
elif [ "$ACTION" = "run" ]; then
|
||||||
echo "Running Gaze application..."
|
echo "Building and running Gaze application..."
|
||||||
# First ensure we have a built app
|
# Always build first, then run
|
||||||
if [ -d "build/Debug/Gaze.app" ]; then
|
|
||||||
run_with_output "open -a \"Gaze\""
|
|
||||||
else
|
|
||||||
echo "⚠️ No built app found. Building first..."
|
|
||||||
run_with_output "xcodebuild -project Gaze.xcodeproj -scheme Gaze -configuration Debug build"
|
run_with_output "xcodebuild -project Gaze.xcodeproj -scheme Gaze -configuration Debug build"
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "✅ Build succeeded!"
|
||||||
run_with_output "open -a \"Gaze\""
|
run_with_output "open -a \"Gaze\""
|
||||||
else
|
else
|
||||||
echo "❌ Build failed during run attempt!"
|
echo "❌ Build failed!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "Usage: $0 [build|test|run] [-v|--verbose] [-o|--output <file_name>]"
|
echo "Usage: $0 [build|test|run] [-v|--verbose] [-o|--output <file_name>]"
|
||||||
|
|||||||
Reference in New Issue
Block a user