diff --git a/Gaze.icon/Assets/Ellipse 1 4.svg b/Gaze.icon/Assets/Ellipse 1 4.svg
new file mode 100644
index 0000000..4c4862c
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 1 4.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Ellipse 10 3.svg b/Gaze.icon/Assets/Ellipse 10 3.svg
new file mode 100644
index 0000000..0483ea5
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 10 3.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Ellipse 11.svg b/Gaze.icon/Assets/Ellipse 11.svg
new file mode 100644
index 0000000..df185ff
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 11.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Ellipse 3 3.svg b/Gaze.icon/Assets/Ellipse 3 3.svg
new file mode 100644
index 0000000..fc5bf24
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 3 3.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Ellipse 4 3.svg b/Gaze.icon/Assets/Ellipse 4 3.svg
new file mode 100644
index 0000000..3783d84
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 4 3.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Ellipse 5 3.svg b/Gaze.icon/Assets/Ellipse 5 3.svg
new file mode 100644
index 0000000..c9032bd
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 5 3.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Ellipse 7 3.svg b/Gaze.icon/Assets/Ellipse 7 3.svg
new file mode 100644
index 0000000..fce0bf0
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 7 3.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Ellipse 8 3.svg b/Gaze.icon/Assets/Ellipse 8 3.svg
new file mode 100644
index 0000000..501fe19
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 8 3.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Ellipse 9 3.svg b/Gaze.icon/Assets/Ellipse 9 3.svg
new file mode 100644
index 0000000..9006935
--- /dev/null
+++ b/Gaze.icon/Assets/Ellipse 9 3.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Line 7.svg b/Gaze.icon/Assets/Line 7.svg
new file mode 100644
index 0000000..dfc9be9
--- /dev/null
+++ b/Gaze.icon/Assets/Line 7.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/Assets/Line 8.svg b/Gaze.icon/Assets/Line 8.svg
new file mode 100644
index 0000000..e8a68dc
--- /dev/null
+++ b/Gaze.icon/Assets/Line 8.svg
@@ -0,0 +1,3 @@
+
diff --git a/Gaze.icon/icon.json b/Gaze.icon/icon.json
new file mode 100644
index 0000000..7efc4f6
--- /dev/null
+++ b/Gaze.icon/icon.json
@@ -0,0 +1,313 @@
+{
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "groups" : [
+ {
+ "layers" : [
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "image-name" : "Ellipse 3 3.svg",
+ "name" : "Ellipse 3 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ 0,
+ 250
+ ]
+ }
+ },
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "image-name" : "Ellipse 4 3.svg",
+ "name" : "Ellipse 4 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ 0,
+ -250
+ ]
+ }
+ },
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "hidden" : true,
+ "image-name" : "Ellipse 5 3.svg",
+ "name" : "Ellipse 5 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ 0,
+ 0
+ ]
+ }
+ },
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "hidden" : true,
+ "image-name" : "Ellipse 5 3.svg",
+ "name" : "Ellipse 5 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ 250,
+ 0
+ ]
+ }
+ },
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "hidden" : true,
+ "image-name" : "Ellipse 5 3.svg",
+ "name" : "Ellipse 5 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ -250,
+ 0
+ ]
+ }
+ },
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "image-name" : "Ellipse 7 3.svg",
+ "name" : "Ellipse 7 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ 185,
+ -185
+ ]
+ }
+ },
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "image-name" : "Ellipse 8 3.svg",
+ "name" : "Ellipse 8 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ 185,
+ 185
+ ]
+ }
+ },
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "image-name" : "Ellipse 9 3.svg",
+ "name" : "Ellipse 9 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ -185,
+ 185
+ ]
+ }
+ },
+ {
+ "blend-mode" : "multiply",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "image-name" : "Ellipse 10 3.svg",
+ "name" : "Ellipse 10 3",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ -185,
+ -185
+ ]
+ }
+ }
+ ],
+ "shadow" : {
+ "kind" : "neutral",
+ "opacity" : 0.5
+ },
+ "translucency" : {
+ "enabled" : true,
+ "value" : 0.5
+ }
+ },
+ {
+ "hidden" : false,
+ "layers" : [
+ {
+ "glass" : false,
+ "image-name" : "Line 7.svg",
+ "name" : "Line 7",
+ "position" : {
+ "scale" : 1.08,
+ "translation-in-points" : [
+ 5.838429928574556,
+ 82.99998474120002
+ ]
+ }
+ },
+ {
+ "blend-mode" : "darken",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : false,
+ "image-name" : "Line 8.svg",
+ "name" : "Line 8",
+ "position" : {
+ "scale" : 1.21,
+ "translation-in-points" : [
+ -0.1999973177900074,
+ -82.12440000000004
+ ]
+ }
+ }
+ ],
+ "shadow" : {
+ "kind" : "neutral",
+ "opacity" : 0.5
+ },
+ "translucency" : {
+ "enabled" : true,
+ "value" : 0.5
+ }
+ },
+ {
+ "layers" : [
+ {
+ "blend-mode" : "plus-darker",
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : true,
+ "hidden" : false,
+ "image-name" : "Ellipse 11.svg",
+ "name" : "Ellipse 11",
+ "position" : {
+ "scale" : 1.32,
+ "translation-in-points" : [
+ 0,
+ 0
+ ]
+ }
+ },
+ {
+ "blend-mode" : "hard-light",
+ "fill" : {
+ "solid" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ },
+ "glass" : true,
+ "image-name" : "Ellipse 11.svg",
+ "name" : "Ellipse 11",
+ "position" : {
+ "scale" : 0.99,
+ "translation-in-points" : [
+ 0,
+ 0
+ ]
+ }
+ }
+ ],
+ "shadow" : {
+ "kind" : "neutral",
+ "opacity" : 0.5
+ },
+ "translucency" : {
+ "enabled" : true,
+ "value" : 0.5
+ }
+ },
+ {
+ "blend-mode" : "plus-darker",
+ "blur-material" : 0.5,
+ "layers" : [
+ {
+ "blend-mode-specializations" : [
+ {
+ "value" : "darken"
+ },
+ {
+ "appearance" : "tinted",
+ "value" : "lighten"
+ }
+ ],
+ "fill-specializations" : [
+ {
+ "value" : {
+ "linear-gradient" : [
+ "display-p3:0.38403,0.64839,1.04685,1.00000",
+ "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ ],
+ "orientation" : {
+ "start" : {
+ "x" : 0.5,
+ "y" : 0
+ },
+ "stop" : {
+ "x" : 0.5,
+ "y" : 0.7
+ }
+ }
+ }
+ },
+ {
+ "appearance" : "dark",
+ "value" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
+ }
+ }
+ ],
+ "glass" : true,
+ "image-name" : "Ellipse 1 4.svg",
+ "name" : "Ellipse 1 4"
+ }
+ ],
+ "shadow" : {
+ "kind" : "neutral",
+ "opacity" : 0.5
+ },
+ "specular" : true,
+ "translucency" : {
+ "enabled" : true,
+ "value" : 0.5
+ }
+ }
+ ],
+ "supported-platforms" : {
+ "circles" : [
+ "watchOS"
+ ],
+ "squares" : "shared"
+ }
+}
\ No newline at end of file
diff --git a/Gaze.xcodeproj/project.pbxproj b/Gaze.xcodeproj/project.pbxproj
index 837d900..1de8326 100644
--- a/Gaze.xcodeproj/project.pbxproj
+++ b/Gaze.xcodeproj/project.pbxproj
@@ -6,6 +6,11 @@
objectVersion = 77;
objects = {
+/* Begin PBXBuildFile section */
+ 275915892F132A9200D0E60D /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 27AE10B12F10B1FC00E00DBC /* Lottie */; };
+ 2759160C2F132C7A00D0E60D /* Gaze.icon in Resources */ = {isa = PBXBuildFile; fileRef = 2759160B2F132C7A00D0E60D /* Gaze.icon */; };
+/* End PBXBuildFile section */
+
/* Begin PBXContainerItemProxy section */
27A21B4A2F0F69DD0018C4F3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
@@ -24,6 +29,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
+ 2759160B2F132C7A00D0E60D /* Gaze.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = Gaze.icon; sourceTree = ""; };
27A21B3C2F0F69DC0018C4F3 /* Gaze.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gaze.app; sourceTree = BUILT_PRODUCTS_DIR; };
27A21B492F0F69DD0018C4F3 /* GazeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GazeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
27A21B532F0F69DD0018C4F3 /* GazeUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GazeUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -52,6 +58,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 275915892F132A9200D0E60D /* Lottie in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -75,6 +82,7 @@
27A21B332F0F69DC0018C4F3 = {
isa = PBXGroup;
children = (
+ 2759160B2F132C7A00D0E60D /* Gaze.icon */,
27A21B3E2F0F69DC0018C4F3 /* Gaze */,
27A21B4C2F0F69DD0018C4F3 /* GazeTests */,
27A21B562F0F69DD0018C4F3 /* GazeUITests */,
@@ -216,6 +224,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 2759160C2F132C7A00D0E60D /* Gaze.icon in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -396,7 +405,6 @@
27A21B5E2F0F69DD0018C4F3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
@@ -428,7 +436,6 @@
27A21B5F2F0F69DD0018C4F3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
@@ -588,6 +595,7 @@
};
};
/* End XCRemoteSwiftPackageReference section */
+
/* Begin XCSwiftPackageProductDependency section */
27AE10B12F10B1FC00E00DBC /* Lottie */ = {
isa = XCSwiftPackageProductDependency;
@@ -595,7 +603,6 @@
productName = Lottie;
};
/* End XCSwiftPackageProductDependency section */
-
};
rootObject = 27A21B342F0F69DC0018C4F3 /* Project object */;
}
diff --git a/Gaze/AppDelegate.swift b/Gaze/AppDelegate.swift
index c9b8f98..5a7dfe8 100644
--- a/Gaze/AppDelegate.swift
+++ b/Gaze/AppDelegate.swift
@@ -158,7 +158,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
showReminderWindow(contentView)
}
-private func showReminderWindow(_ content: AnyView) {
+ private func showReminderWindow(_ content: AnyView) {
guard let screen = NSScreen.main else { return }
let window = KeyableWindow(
@@ -266,12 +266,15 @@ private func showReminderWindow(_ content: AnyView) {
// Observe when window is closed to clean up reference
NotificationCenter.default.addObserver(
- forName: NSWindow.willCloseNotification,
- object: window,
- queue: .main
- ) { [weak self] _ in
- self?.settingsWindowController = nil
- }
+ self,
+ selector: #selector(settingsWindowWillCloseNotification(_:)),
+ name: NSWindow.willCloseNotification,
+ object: window
+ )
+ }
+
+ @objc private func settingsWindowWillCloseNotification(_ notification: Notification) {
+ settingsWindowController = nil
}
}
@@ -284,4 +287,4 @@ class KeyableWindow: NSWindow {
override var canBecomeMain: Bool {
return true
}
-}
\ No newline at end of file
+}
diff --git a/Gaze/Assets.xcassets/AppIcon.appiconset/Contents.json b/Gaze/Assets.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644
index 3f00db4..0000000
--- a/Gaze/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "16x16"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "16x16"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "32x32"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "32x32"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "128x128"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "128x128"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "256x256"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "256x256"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "512x512"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "512x512"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/Gaze/GazeApp.swift b/Gaze/GazeApp.swift
index b909fc2..7e72991 100644
--- a/Gaze/GazeApp.swift
+++ b/Gaze/GazeApp.swift
@@ -22,7 +22,7 @@ struct GazeApp: App {
}
} else {
OnboardingContainerView(settingsManager: settingsManager)
- .onChange(of: settingsManager.settings.hasCompletedOnboarding) { completed in
+ .onChange(of: settingsManager.settings.hasCompletedOnboarding) { _, completed in
if completed {
closeAllWindows()
appDelegate.onboardingCompleted()
@@ -56,4 +56,4 @@ struct GazeApp: App {
window.close()
}
}
-}
\ No newline at end of file
+}
diff --git a/Gaze/Views/MenuBar/MenuBarContentView.swift b/Gaze/Views/MenuBar/MenuBarContentView.swift
index 5158dc0..4b330ab 100644
--- a/Gaze/Views/MenuBar/MenuBarContentView.swift
+++ b/Gaze/Views/MenuBar/MenuBarContentView.swift
@@ -64,7 +64,7 @@ struct MenuBarContentView: View {
EmptyView()
}
}
-
+
private var onboardingIncompleteView: some View {
VStack(alignment: .leading, spacing: 0) {
// Header
@@ -79,15 +79,15 @@ struct MenuBarContentView: View {
.padding()
Divider()
-
+
// Message
VStack(alignment: .leading, spacing: 12) {
Text("Welcome to Gaze!")
.font(.headline)
.padding(.horizontal)
.padding(.top, 16)
-
- Text("Please complete the onboarding to start using Gaze.")
+
+ Text("Complete the onboarding to start using Gaze!")
.font(.subheadline)
.foregroundColor(.secondary)
.padding(.horizontal)
@@ -133,11 +133,13 @@ struct MenuBarContentView: View {
.padding(.vertical, 8)
}
.frame(width: 300)
- .onReceive(NotificationCenter.default.publisher(for: Notification.Name("CloseMenuBarPopover"))) { _ in
+ .onReceive(
+ NotificationCenter.default.publisher(for: Notification.Name("CloseMenuBarPopover"))
+ ) { _ in
dismiss()
}
}
-
+
private func fullMenuBarView(timerEngine: TimerEngine) -> some View {
VStack(alignment: .leading, spacing: 0) {
// Header
@@ -185,14 +187,15 @@ struct MenuBarContentView: View {
)
}
}
-
+
// Show user timers if any exist and are enabled
- ForEach(settingsManager.settings.userTimers.filter { $0.enabled }, id: \.id) { userTimer in
+ ForEach(settingsManager.settings.userTimers.filter { $0.enabled }, id: \.id) {
+ userTimer in
UserTimerStatusRow(
timer: userTimer,
- state: nil, // We'll implement proper state tracking later
+ state: nil, // We'll implement proper state tracking later
onTap: {
- onOpenSettingsTab(3) // Switch to User Timers tab
+ onOpenSettingsTab(3) // Switch to User Timers tab
}
)
}
@@ -211,8 +214,12 @@ struct MenuBarContentView: View {
}
}) {
HStack {
- Image(systemName: isPaused(timerEngine: timerEngine) ? "play.circle" : "pause.circle")
- Text(isPaused(timerEngine: timerEngine) ? "Resume All Timers" : "Pause All Timers")
+ Image(
+ systemName: isPaused(timerEngine: timerEngine)
+ ? "play.circle" : "pause.circle")
+ Text(
+ isPaused(timerEngine: timerEngine)
+ ? "Resume All Timers" : "Pause All Timers")
Spacer()
}
.padding(.horizontal, 8)
@@ -254,7 +261,9 @@ struct MenuBarContentView: View {
.padding(.vertical, 8)
}
.frame(width: 300)
- .onReceive(NotificationCenter.default.publisher(for: Notification.Name("CloseMenuBarPopover"))) { _ in
+ .onReceive(
+ NotificationCenter.default.publisher(for: Notification.Name("CloseMenuBarPopover"))
+ ) { _ in
dismiss()
}
}
@@ -430,7 +439,7 @@ struct UserTimerStatusRow: View {
Circle()
.fill(timer.color)
.frame(width: 8, height: 8)
-
+
Image(systemName: "clock.fill")
.foregroundColor(timer.color)
.frame(width: 20)
@@ -440,7 +449,7 @@ struct UserTimerStatusRow: View {
.font(.subheadline)
.fontWeight(.medium)
.lineLimit(1)
-
+
if let state = state {
Text(timeRemaining(state))
.font(.caption)