diff --git a/NotchIA.xcodeproj/project.pbxproj b/NotchIA.xcodeproj/project.pbxproj index db02305..6fc7c80 100644 --- a/NotchIA.xcodeproj/project.pbxproj +++ b/NotchIA.xcodeproj/project.pbxproj @@ -1277,7 +1277,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20809; + CURRENT_PROJECT_VERSION = 20900; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = NO; GENERATE_INFOPLIST_FILE = YES; @@ -1285,7 +1285,7 @@ INFOPLIST_KEY_CFBundleDisplayName = NotchIAXPCHelper; INFOPLIST_KEY_NSHumanReadableCopyright = ""; MACOSX_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 2.8.9; + MARKETING_VERSION = 2.9.0; PRODUCT_BUNDLE_IDENTIFIER = com.coaxel2.notchia.NotchIAXPCHelper; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; @@ -1303,7 +1303,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20809; + CURRENT_PROJECT_VERSION = 20900; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = NO; GENERATE_INFOPLIST_FILE = YES; @@ -1311,7 +1311,7 @@ INFOPLIST_KEY_CFBundleDisplayName = NotchIAXPCHelper; INFOPLIST_KEY_NSHumanReadableCopyright = ""; MACOSX_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 2.8.9; + MARKETING_VERSION = 2.9.0; PRODUCT_BUNDLE_IDENTIFIER = com.coaxel2.notchia.NotchIAXPCHelper; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; @@ -1462,7 +1462,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20809; + CURRENT_PROJECT_VERSION = 20900; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"NotchIA/Preview Content\""; DEVELOPMENT_TEAM = ""; @@ -1490,7 +1490,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 2.8.9; + MARKETING_VERSION = 2.9.0; PRODUCT_BUNDLE_IDENTIFIER = com.coaxel2.notchia; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1518,7 +1518,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 20809; + CURRENT_PROJECT_VERSION = 20900; DEAD_CODE_STRIPPING = YES; DEPLOYMENT_POSTPROCESSING = YES; DEVELOPMENT_ASSET_PATHS = "\"NotchIA/Preview Content\""; @@ -1546,7 +1546,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 15.0; - MARKETING_VERSION = 2.8.9; + MARKETING_VERSION = 2.9.0; PRODUCT_BUNDLE_IDENTIFIER = com.coaxel2.notchia; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/NotchIA/animations/drop.swift b/NotchIA/animations/drop.swift index 520d975..f7e8789 100644 --- a/NotchIA/animations/drop.swift +++ b/NotchIA/animations/drop.swift @@ -17,8 +17,14 @@ public class NotchIAAnimations { } var animation: Animation { + // Spring tuné pour donner le sentiment d'une encoche qui "émerge" + // du notch hardware : durée allongée à ~0.55s + damping légèrement + // sous-amorti (0.72) pour un petit overshoot organique en fin + // de course, qui rend l'ouverture moins "directe" et plus fluide. + // Ferme aussi avec la même courbe (close() utilise withAnimation + // sans override explicite, c'est cette animation qui sert). if #available(macOS 14.0, *), notchStyle == .notch { - Animation.spring(.bouncy(duration: 0.4)) + Animation.spring(response: 0.5, dampingFraction: 0.72, blendDuration: 0.1) } else { Animation.timingCurve(0.16, 1, 0.3, 1, duration: 0.7) } diff --git a/NotchIA/managers/ClaudeCodeManager.swift b/NotchIA/managers/ClaudeCodeManager.swift index 7243419..7659f8e 100644 --- a/NotchIA/managers/ClaudeCodeManager.swift +++ b/NotchIA/managers/ClaudeCodeManager.swift @@ -592,7 +592,6 @@ final class ClaudeCodeManager: ObservableObject { } log.info("Watching session file: \(jsonlFile.lastPathComponent)") - NSLog("[NotchIA-Diag] startWatching session=\(session.id) file=\(jsonlFile.path)") // Seed UI from recent history first (50KB tail), then start tailing. // Order matters: loadRecent happens before start() so the watcher @@ -603,22 +602,16 @@ final class ClaudeCodeManager: ObservableObject { let started = reader.start( file: jsonlFile, onLine: { [weak self] line in - NSLog("[NotchIA-Diag] LIVE line received (\(line.count) chars) from selected session") self?.parseJSONLLine(line) }, onChunkComplete: { [weak self] in guard let self else { return } - NSLog("[NotchIA-Diag] chunk complete — state.activityStartedAt=\(self.state.activityStartedAt as Any), state.promptTokensTotal=\(self.state.promptTokensTotal)") self.state.lastUpdateTime = Date() self.loadRateLimitsSnapshot() self.resetIdleTimer() } ) - guard started else { - NSLog("[NotchIA-Diag] ❌ reader.start() returned false — TCC denied or file unreadable") - return - } - NSLog("[NotchIA-Diag] ✅ reader armed for \(jsonlFile.lastPathComponent)") + guard started else { return } selectedSessionReader = reader state.isConnected = true @@ -1363,7 +1356,6 @@ final class ClaudeCodeManager: ObservableObject { // isThinking=true unless `stop_reason == end_turn` // is observed (handled below). if let role = message["role"] as? String { - NSLog("[NotchIA-Diag] parseJSONLLine role=\(role) isLoadingHistory=\(isLoadingHistory)") if role == "user" && !isLoadingHistory { state.latestThinking = "" state.isThinking = true @@ -1372,7 +1364,6 @@ final class ClaudeCodeManager: ObservableObject { state.lastCompletedDuration = 0 state.promptTokensTotal = 0 lastActivityTime = Date() - NSLog("[NotchIA-Diag] ⏱ CHRONO STARTED — activityStartedAt=\(state.activityStartedAt!)") } else if role == "assistant" { state.isThinking = true markSelectedStateActive() diff --git a/NotchIA/models/NotchIAViewModel.swift b/NotchIA/models/NotchIAViewModel.swift index 4a14928..dd27a96 100644 --- a/NotchIA/models/NotchIAViewModel.swift +++ b/NotchIA/models/NotchIAViewModel.swift @@ -162,16 +162,24 @@ class NotchIAViewModel: NSObject, ObservableObject { let horizontalPadding: CGFloat = extendForClosedTrigger ? 30 : 0 let verticalPadding: CGFloat = extendForClosedTrigger && size.height <= 0 ? 10 : 0 + // FIX bord supérieur d'écran : macOS clamp le curseur à `frame.maxY` + // quand l'utilisateur monte la souris contre le haut de l'écran. + // `CGRect.contains` est demi-ouvert sur maxY → un curseur à + // `position.y == frame.maxY` était EXCLU du rect dont le maxY + // était exactement à `frame.maxY`. Résultat : la notch ne s'ouvrait + // pas si la souris tapait le bord. On étire le rect de 6pt + // vers le haut (au-delà du bord visible) pour absorber le clamp. + let topClampMargin: CGFloat = 6 let hoverRect = CGRect( x: frame.midX - size.width / 2 - horizontalPadding, y: frame.maxY - size.height - verticalPadding, width: size.width + (horizontalPadding * 2), - height: max(size.height + verticalPadding, 1) + height: max(size.height + verticalPadding + topClampMargin, 1) ) return hoverRect.contains(position) } - + return false } diff --git a/updater/appcast.xml b/updater/appcast.xml index 53f9eb6..6f2a792 100644 --- a/updater/appcast.xml +++ b/updater/appcast.xml @@ -32,6 +32,16 @@ --> + + 2.9.0 + Tue, 26 May 2026 01:13:07 +0000 + https://github.com/coaxel2/NotchIA/releases + 20900 + 2.9.0 + 15.0 + + + 2.8.9 Tue, 26 May 2026 00:50:13 +0000 @@ -52,16 +62,6 @@ 30s.]]> - - 2.8.7 - Mon, 25 May 2026 23:52:28 +0000 - https://github.com/coaxel2/NotchIA/releases - 20807 - 2.8.7 - 15.0 - - - 2.7.3 Mon, 24 Nov 2025 08:07:37 +0000