From 5194957564e1924f005d58a0cef5b7295e40d7fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI=E4=BA=A7=E5=93=81=E9=BB=84=E5=8F=94?= Date: Fri, 25 Sep 2026 21:20:59 -0700 Subject: [PATCH 1/2] fix(island): stop the card flickering when hovering the island's edge The card window kept a 26pt shadow margin on every side. Its card hangs 6pt below the menu bar, so the top margin reached 10pt up over the island's lower edge. With the mouse there, the shadow took the hover: the island read it as the mouse leaving, the card closed, the island got the hover back and reopened it, over and over. The card window now has no top margin, and the island sits one window level above the card so an overlap can never steal its hover again. Co-Authored-By: Claude Opus 5.5 --- .../Support/TokenIslandWindowPresenter.swift | 10 ++++++++-- .../Sources/TokenStepSwift/Views/TokenIslandView.swift | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/TokenStepSwift/Sources/TokenStepSwift/Support/TokenIslandWindowPresenter.swift b/TokenStepSwift/Sources/TokenStepSwift/Support/TokenIslandWindowPresenter.swift index 0368a4c..0cef5f1 100644 --- a/TokenStepSwift/Sources/TokenStepSwift/Support/TokenIslandWindowPresenter.swift +++ b/TokenStepSwift/Sources/TokenStepSwift/Support/TokenIslandWindowPresenter.swift @@ -181,13 +181,17 @@ final class TokenIslandWindowPresenter { ) .environmentObject(appState) - return makePanel( + let panel = makePanel( title: "TokenStep Island", identifier: "token-island", size: Self.collapsedSize, rootView: rootView, hasShadow: false ) + // One level above the card window, so if the two ever overlap the + // island keeps its hover and the card cannot flicker. + panel.level = NSWindow.Level(rawValue: NSWindow.Level.statusBar.rawValue + 1) + return panel } private func makePopoverPanel(appState: AppState) -> TokenIslandPanel { @@ -294,9 +298,11 @@ final class TokenIslandWindowPresenter { max(anchorX, screen.visibleFrame.minX + 8), screen.visibleFrame.maxX - cardSize.width - 8 ) + // No top margin (see TokenIslandMetrics.expandedWindowSize): the + // window's top edge is the card's top edge. let frame = NSRect( x: cardX - margin, - y: topY - cardSize.height - margin, + y: topY - size.height, width: size.width, height: size.height ) diff --git a/TokenStepSwift/Sources/TokenStepSwift/Views/TokenIslandView.swift b/TokenStepSwift/Sources/TokenStepSwift/Views/TokenIslandView.swift index c0243a1..2634217 100644 --- a/TokenStepSwift/Sources/TokenStepSwift/Views/TokenIslandView.swift +++ b/TokenStepSwift/Sources/TokenStepSwift/Views/TokenIslandView.swift @@ -10,10 +10,15 @@ enum TokenIslandMetrics { /// Used before the card reports its measured height. static let initialCardHeight: CGFloat = 420 + /// The window has no margin above the card: the card hangs just below the + /// island, and a top margin would cover the island's lower edge. The + /// shadow's alpha there then takes the hover, the island reads it as the + /// mouse leaving, the card closes, the island gets the hover back, and the + /// card flickers open and shut. static func expandedWindowSize(cardHeight: CGFloat) -> NSSize { NSSize( width: expandedCardWidth + expandedShadowMargin * 2, - height: cardHeight + expandedShadowMargin * 2 + height: cardHeight + expandedShadowMargin ) } } @@ -75,7 +80,7 @@ struct TokenIslandPopoverWindowView: View { .onHover { hovering in onHoverChanged(hovering) } - .padding(TokenIslandMetrics.expandedShadowMargin) + .padding([.horizontal, .bottom], TokenIslandMetrics.expandedShadowMargin) .frame(maxHeight: .infinity, alignment: .top) .environment(\.colorScheme, appState.settings.theme.colorScheme) .id(appState.appearanceID) From e2cf4097174d395b69bbf057305f02481c427088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI=E4=BA=A7=E5=93=81=E9=BB=84=E5=8F=94?= Date: Fri, 25 Sep 2026 21:24:48 -0700 Subject: [PATCH 2/2] chore: prepare TokenStep 0.2.17 Add release notes, the CHANGELOG entry, README download links, and the default build version. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 ++++ README.md | 10 +++++----- docs/RELEASE_NOTES_0.2.17.md | 7 +++++++ script/build_swiftui_and_run.sh | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 docs/RELEASE_NOTES_0.2.17.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c363c6..8c1fd66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ TokenStep 各版本的更新内容,新版本在前。每个版本的完整说明在 [docs/RELEASE_NOTES_<版本号>.md](docs/)。 +## 0.2.17 更新:修复刘海卡片闪烁 + +在有刘海的 Mac 上,鼠标放在 Token Island 边缘时,展开的卡片不再反复弹出又收起。详见 [0.2.17 发布说明](docs/RELEASE_NOTES_0.2.17.md)。 + ## 0.2.16 更新:紧凑面板,额度刷新更及时 菜单栏面板改为一列 340pt,只放额度、今日 Token、今日排名,13 寸屏幕上不再被截掉;刘海旁的 Token Island 打开同一个面板。额度在面板打开时最多每 5 分钟刷新,刷新按钮会一并刷新额度;只用 Claude Code CLI 时也显示 Claude 图标。详见 [0.2.16 发布说明](docs/RELEASE_NOTES_0.2.16.md)。 diff --git a/README.md b/README.md index b15471f..82c6d51 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ TokenStep 是一个 macOS 菜单栏 App,用来本地统计你在 Codex、Claud 下载最新版 DMG,打开后把 `TokenStep.app` 拖进「应用程序」即可使用: -[下载 TokenStep 最新版](https://github.com/Backtthefuture/TokenStep/releases/latest/download/TokenStep-0.2.16.dmg) +[下载 TokenStep 最新版](https://github.com/Backtthefuture/TokenStep/releases/latest/download/TokenStep-0.2.17.dmg) 也可以从 Release 页面查看所有版本: @@ -32,9 +32,9 @@ TokenStep 已使用 Developer ID 签名并通过 Apple 公证。首次打开时 Windows版本由十七做了移植,欢迎大家前往使用:https://github.com/canyexuanfan/TokenStep-Windows/releases -## 最新版本:0.2.16 +## 最新版本:0.2.17 -菜单栏面板改为一列紧凑面板,13 寸屏幕上不再被截掉,刘海旁的 Token Island 打开同一个面板;额度在面板打开时最多每 5 分钟刷新,刷新按钮会一并刷新额度。详见 [0.2.16 发布说明](docs/RELEASE_NOTES_0.2.16.md)。 +修复刘海 Mac 上鼠标放在 Token Island 边缘时卡片反复闪烁的问题。上一版 0.2.16 把菜单栏面板改成了一列紧凑面板,额度刷新也更及时。详见 [0.2.17 发布说明](docs/RELEASE_NOTES_0.2.17.md)。 历次更新(主题包、引力动效、自动更新等)见 [CHANGELOG.md](CHANGELOG.md)。 @@ -95,7 +95,7 @@ TokenStep 默认只做本地统计。 ## 安装方式 -1. 下载 [TokenStep 最新版 DMG](https://github.com/Backtthefuture/TokenStep/releases/latest/download/TokenStep-0.2.16.dmg)。 +1. 下载 [TokenStep 最新版 DMG](https://github.com/Backtthefuture/TokenStep/releases/latest/download/TokenStep-0.2.17.dmg)。 2. 打开 DMG。 3. 把 `TokenStep.app` 拖到「应用程序」。 4. 启动 TokenStep。 @@ -166,7 +166,7 @@ TokenStepSwift/dist/TokenStep.app 公开发布强制执行 Developer ID 签名、Apple 公证、票据装订、系统分发检查和隔离安装验证。不再生成可被误上传的“仅签名、未公证”发布包: ```bash -TOKENSTEP_VERSION=0.2.16 \ +TOKENSTEP_VERSION=0.2.17 \ CODE_SIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" \ TOKENSTEP_NOTARY_PROFILE="tokenstep-notary" \ ./script/package_release.sh --notarize diff --git a/docs/RELEASE_NOTES_0.2.17.md b/docs/RELEASE_NOTES_0.2.17.md new file mode 100644 index 0000000..3a1b799 --- /dev/null +++ b/docs/RELEASE_NOTES_0.2.17.md @@ -0,0 +1,7 @@ +# TokenStep 0.2.17 + +修复刘海 Mac 上展开卡片反复闪烁的问题。 + +- **修复卡片闪烁**:在有刘海的 Mac 上,把鼠标放在刘海旁 Token Island 的边缘,或点击它的边缘时,展开的卡片会不停地弹出又收起。原因是卡片窗口的阴影区域盖住了 Island 的下边缘,两者互相抢鼠标悬停。现在卡片窗口不再伸到 Island 上方,Island 也始终位于卡片之上。 + +统计口径与 0.2.16 相同。 diff --git a/script/build_swiftui_and_run.sh b/script/build_swiftui_and_run.sh index 8b25522..266c4a3 100755 --- a/script/build_swiftui_and_run.sh +++ b/script/build_swiftui_and_run.sh @@ -23,7 +23,7 @@ HELPER_EXECUTABLE="$BUILD_DIR/$HELPER_NAME" ICON_FILE="$ROOT_DIR/TokenUsageMenuApp/assets/TokenStepIcon.icns" ODYSSEY_ASSET_DIR="$ROOT_DIR/TokenUsageMenuApp/assets/odyssey" INTERSTELLAR_ASSET_DIR="$ROOT_DIR/TokenUsageMenuApp/assets/interstellar" -VERSION="${TOKENSTEP_VERSION:-0.2.16}" +VERSION="${TOKENSTEP_VERSION:-0.2.17}" LAUNCH=true VERIFY=false