diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c1fd66..b334e12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ TokenStep 各版本的更新内容,新版本在前。每个版本的完整说明在 [docs/RELEASE_NOTES_<版本号>.md](docs/)。 +## 0.2.18 更新:额度预警写明窗口 + +额度提前用完的提示会写出是哪个窗口,例如「7 天额度会提前用完」,不再和快要重置的 5 小时窗口混淆;面板里的排名可以直接打开 Token Rank 榜单和个人主页。详见 [0.2.18 发布说明](docs/RELEASE_NOTES_0.2.18.md)。 + ## 0.2.17 更新:修复刘海卡片闪烁 在有刘海的 Mac 上,鼠标放在 Token Island 边缘时,展开的卡片不再反复弹出又收起。详见 [0.2.17 发布说明](docs/RELEASE_NOTES_0.2.17.md)。 diff --git a/README.md b/README.md index 82c6d51..c0c4b92 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.17.dmg) +[下载 TokenStep 最新版](https://github.com/Backtthefuture/TokenStep/releases/latest/download/TokenStep-0.2.18.dmg) 也可以从 Release 页面查看所有版本: @@ -32,9 +32,9 @@ TokenStep 已使用 Developer ID 签名并通过 Apple 公证。首次打开时 Windows版本由十七做了移植,欢迎大家前往使用:https://github.com/canyexuanfan/TokenStep-Windows/releases -## 最新版本:0.2.17 +## 最新版本:0.2.18 -修复刘海 Mac 上鼠标放在 Token Island 边缘时卡片反复闪烁的问题。上一版 0.2.16 把菜单栏面板改成了一列紧凑面板,额度刷新也更及时。详见 [0.2.17 发布说明](docs/RELEASE_NOTES_0.2.17.md)。 +额度提前用完的提示会写出是哪个窗口,例如「7 天额度会提前用完」;面板里的排名可以直接打开 Token Rank 网页。0.2.16 起菜单栏面板改为一列紧凑面板,额度刷新也更及时。详见 [0.2.18 发布说明](docs/RELEASE_NOTES_0.2.18.md)。 历次更新(主题包、引力动效、自动更新等)见 [CHANGELOG.md](CHANGELOG.md)。 @@ -95,7 +95,7 @@ TokenStep 默认只做本地统计。 ## 安装方式 -1. 下载 [TokenStep 最新版 DMG](https://github.com/Backtthefuture/TokenStep/releases/latest/download/TokenStep-0.2.17.dmg)。 +1. 下载 [TokenStep 最新版 DMG](https://github.com/Backtthefuture/TokenStep/releases/latest/download/TokenStep-0.2.18.dmg)。 2. 打开 DMG。 3. 把 `TokenStep.app` 拖到「应用程序」。 4. 启动 TokenStep。 @@ -166,7 +166,7 @@ TokenStepSwift/dist/TokenStep.app 公开发布强制执行 Developer ID 签名、Apple 公证、票据装订、系统分发检查和隔离安装验证。不再生成可被误上传的“仅签名、未公证”发布包: ```bash -TOKENSTEP_VERSION=0.2.17 \ +TOKENSTEP_VERSION=0.2.18 \ CODE_SIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" \ TOKENSTEP_NOTARY_PROFILE="tokenstep-notary" \ ./script/package_release.sh --notarize diff --git a/TokenStepSwift/Sources/TokenStepSwift/Support/Localization.swift b/TokenStepSwift/Sources/TokenStepSwift/Support/Localization.swift index fa83236..5ecd824 100644 --- a/TokenStepSwift/Sources/TokenStepSwift/Support/Localization.swift +++ b/TokenStepSwift/Sources/TokenStepSwift/Support/Localization.swift @@ -516,6 +516,9 @@ enum TokenStepLocalization { "榜上 %@": "On board %@", "榜单 %@": "Board %@", "照此速度会提前用完": "Runs out early at this pace", + "%@额度会提前用完": "%@ runs out early", + "打开我的 Token Rank 主页": "Open my Token Rank page", + "在浏览器打开 Token Rank 榜单": "Open the Token Rank board in the browser", "已用 %@": "%@ used", "竖线是时间进度:已过 %@,已用 %@": "The tick marks time passed: %@ of the window gone, %@ used", "。用得比时间快,照此速度会在重置前用完": ". Usage is ahead of time and runs out before the reset at this pace", @@ -1211,6 +1214,9 @@ enum TokenStepLocalization { "榜上 %@": "榜上 %@", "榜单 %@": "榜單 %@", "照此速度会提前用完": "照此速度會提前用完", + "%@额度会提前用完": "%@額度會提前用完", + "打开我的 Token Rank 主页": "打開我的 Token Rank 主頁", + "在浏览器打开 Token Rank 榜单": "在瀏覽器打開 Token Rank 榜單", "已用 %@": "已用 %@", "竖线是时间进度:已过 %@,已用 %@": "豎線是時間進度:已過 %@,已用 %@", "。用得比时间快,照此速度会在重置前用完": "。用得比時間快,照此速度會在重置前用完", diff --git a/TokenStepSwift/Sources/TokenStepSwift/Views/Popover/CompactPopoverSections.swift b/TokenStepSwift/Sources/TokenStepSwift/Views/Popover/CompactPopoverSections.swift index 847f89c..02bed58 100644 --- a/TokenStepSwift/Sources/TokenStepSwift/Views/Popover/CompactPopoverSections.swift +++ b/TokenStepSwift/Sources/TokenStepSwift/Views/Popover/CompactPopoverSections.swift @@ -255,6 +255,15 @@ struct CompactQuotaSection: View { ) } + /// Names the window that runs out early, so a warning next to a window + /// about to reset is not read as being about that one. + private func runsOutEarlyBadge(_ provider: CompactPopoverModel.QuotaProviderRow) -> String { + let titles = provider.windows.filter(\.runsOutEarly).map(\.title) + guard !titles.isEmpty else { return L("照此速度会提前用完") } + let separator = TokenStepLocalization.language == .en ? ", " : "、" + return LFormat("%@额度会提前用完", titles.joined(separator: separator)) + } + /// Explains the bar's tick: how much of the window's time has passed. private func paceHelp(_ window: CompactPopoverModel.QuotaWindowRow) -> String { guard let elapsed = window.elapsedFraction else { @@ -277,8 +286,10 @@ struct CompactQuotaSection: View { .foregroundStyle(Color.tokenInk) Spacer(minLength: 4) if provider.runsOutEarly { - Text(L("照此速度会提前用完")) + Text(runsOutEarlyBadge(provider)) .font(.system(size: 11, weight: .semibold)) + .lineLimit(1) + .minimumScaleFactor(0.8) .foregroundStyle(CompactPopoverStyle.color(for: .warning)) .padding(.horizontal, 7) .padding(.vertical, 2) @@ -379,10 +390,20 @@ struct CompactTokenSection: View { struct CompactRankSection: View { var section: CompactPopoverModel.RankSection var fetchedAt: Date + /// Opens the Token Rank board in the browser. + var openBoard: (() -> Void)? + /// Opens the user's own Token Rank page. + var openMyPage: (() -> Void)? var body: some View { VStack(alignment: .leading, spacing: 10) { - CompactSectionHeader(title: L("今日排名"), trailing: LFormat("榜单 %@", CompactPopoverStyle.relative(fetchedAt))) + HStack(alignment: .firstTextBaseline) { + Text(L("今日排名")) + .font(.system(size: 12, weight: .bold)) + .foregroundStyle(Color.tokenInk.opacity(0.62)) + Spacer(minLength: 8) + boardLink + } HStack(alignment: .firstTextBaseline, spacing: 8) { if let rank = section.myRank { Text("#\(rank)") @@ -404,6 +425,13 @@ struct CompactRankSection: View { .foregroundStyle(.secondary) } } + .contentShape(Rectangle()) + .onTapGesture { openMyPage?() } + .onHover { hovering in + guard openMyPage != nil else { return } + if hovering { NSCursor.pointingHand.push() } else { NSCursor.pop() } + } + .help(openMyPage == nil ? "" : L("打开我的 Token Rank 主页")) ForEach(section.podium) { entry in HStack(spacing: 8) { Text("\(entry.rank)") @@ -433,6 +461,30 @@ struct CompactRankSection: View { } } + @ViewBuilder + private var boardLink: some View { + let label = HStack(spacing: 3) { + Text(LFormat("榜单 %@", CompactPopoverStyle.relative(fetchedAt))) + if openBoard != nil { + Image(systemName: "arrow.up.right") + .font(.system(size: 9, weight: .semibold)) + } + } + .font(.system(size: 11)) + .foregroundStyle(.secondary) + + if let openBoard { + Button(action: openBoard) { label.contentShape(Rectangle()) } + .buttonStyle(.plain) + .onHover { hovering in + if hovering { NSCursor.pointingHand.push() } else { NSCursor.pop() } + } + .help(L("在浏览器打开 Token Rank 榜单")) + } else { + label + } + } + private var rankCaption: String { if section.myRank == nil { // A full board may hide ranks past the limit; a short one lists diff --git a/TokenStepSwift/Sources/TokenStepSwift/Views/PopoverPanelView.swift b/TokenStepSwift/Sources/TokenStepSwift/Views/PopoverPanelView.swift index fc3461c..d6e6cc1 100644 --- a/TokenStepSwift/Sources/TokenStepSwift/Views/PopoverPanelView.swift +++ b/TokenStepSwift/Sources/TokenStepSwift/Views/PopoverPanelView.swift @@ -23,7 +23,12 @@ struct PopoverPanelView: View { if let rank = rankSection, let board = appState.tokenRank { sectionDivider section { - CompactRankSection(section: rank, fetchedAt: board.fetchedAt) + CompactRankSection( + section: rank, + fetchedAt: board.fetchedAt, + openBoard: { appState.openTokenRankLeaderboardPage() }, + openMyPage: { appState.openTokenRankUserPage() } + ) } } notices diff --git a/docs/RELEASE_NOTES_0.2.18.md b/docs/RELEASE_NOTES_0.2.18.md new file mode 100644 index 0000000..814caec --- /dev/null +++ b/docs/RELEASE_NOTES_0.2.18.md @@ -0,0 +1,8 @@ +# TokenStep 0.2.18 + +额度预警写明是哪个窗口会提前用完,面板里可以直接打开 Token Rank 网页。 + +- **预警更明确**:以前的提示只写「照此速度会提前用完」,放在服务名称旁边。如果 5 小时窗口快要重置,而实际跑快的是 7 天窗口,就容易被误读成在说 5 小时。现在提示会写出窗口名称,例如「7 天额度会提前用完」;多个窗口都会提前用完时一并列出。 +- **打开 Token Rank 网页**:面板「今日排名」右上角的「榜单 N 分钟前」可以点击,会在浏览器打开 Token Rank 榜单;点击自己的排名那一行,会打开你的 Token Rank 个人主页。 + +统计口径与 0.2.17 相同。 diff --git a/script/build_swiftui_and_run.sh b/script/build_swiftui_and_run.sh index 266c4a3..dd3e07b 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.17}" +VERSION="${TOKENSTEP_VERSION:-0.2.18}" LAUNCH=true VERIFY=false