on master help sign in
feat: use provider emoji ๐Ÿ…ฒ Claude, ๐Ÿ…‰ z.ai in menu bar

Replace per-window clock emojis with one provider emoji per segment. Windows within a segment are bare percentages. โšก42 ยท ๐Ÿ…ฒ62% 8% ยท ๐Ÿ…‰12% 3%

commitabde53a36b0c0d15f06436d68878e681c49a70d7 authoriko <mail@iko.soy> dateFri 17 Jul 2026, 14:04 (3 months ago) parenta655a7c
3 files changed+31โˆ’31
UsageMenubar/MenuView.swift+2โˆ’2 UsageMenubar/ViewModel.swift+12โˆ’12 UsageMenubarTests/StatusBarTextTests.swift+17โˆ’17
UsageMenubar/MenuView.swift+2โˆ’2
@@ -259,7 +259,7 @@ struct MenuView: View {
259259 VStack(spacing: 8) {
260260 HStack(alignment: .firstTextBaseline, spacing: 8) {
261261 headlineNumber(
262โˆ’ text: "๐Ÿ• \(percent)%",
262+ text: "๐Ÿ…ฒ \(percent)%",
263263 color: Self.usageColor(percent),
264264 trend: viewModel.claudeTrend,
265265 copiedConfirmation: viewModel.copiedClaudeConfirmation,
@@ -379,7 +379,7 @@ struct MenuView: View {
379379 VStack(spacing: 8) {
380380 HStack(alignment: .firstTextBaseline, spacing: 8) {
381381 headlineNumber(
382โˆ’ text: "๐Ÿ•‘ \(fiveHour)%",
382+ text: "๐Ÿ…‰ \(fiveHour)%",
383383 color: Self.usageColor(fiveHour),
384384 trend: viewModel.zaiTrend,
385385 copiedConfirmation: viewModel.copiedZaiConfirmation,
UsageMenubar/ViewModel.swift+12โˆ’12
@@ -238,11 +238,11 @@ final class ViewModel: ObservableObject {
238238 }
239239
240240 /// The text to show in the menu bar. Each configured provider contributes a
241โˆ’ /// segment; segments are separated by ` ยท ` (middle dot). Within a segment,
242โˆ’ /// windows are separated by a space. An unconfigured service produces no
243โˆ’ /// segment โ€” no placeholder, no icon.
241+ /// segment prefixed with a provider emoji; segments are separated by ` ยท `
242+ /// (middle dot). Within a segment, windows are listed as bare percentages
243+ /// separated by spaces. An unconfigured service produces no segment.
244244 ///
245โˆ’ /// Example: `โšก42 ยท ๐Ÿ•62% ๐Ÿ“…8% ยท ๐Ÿ•‘12% ๐Ÿ“†3%`
245+ /// Example: `โšก42 ยท ๐Ÿ…ฒ62% 8% ยท ๐Ÿ…‰12% 3%`
246246 ///
247247 /// Takes its values as parameters rather than reading the properties: `@Published`
248248 /// publishes in `willSet`, so a Combine subscriber that called back into the view
@@ -263,28 +263,28 @@ final class ViewModel: ObservableObject {
263263 segments.append("โšก\(formatBalance(balance))")
264264 }
265265
266โˆ’ // Claude โ€” windows joined by space within the segment
266+ // Claude โ€” provider emoji + bare percentages
267267 var claudeWindows: [String] = []
268268 if let fiveHour = claudeFiveHourPercent, fiveHour > 0 {
269โˆ’ claudeWindows.append("๐Ÿ•\(fiveHour)%")
269+ claudeWindows.append("\(fiveHour)%")
270270 }
271271 if let sevenDay = claudeSevenDayPercent, sevenDay > 0 {
272โˆ’ claudeWindows.append("๐Ÿ“…\(sevenDay)%")
272+ claudeWindows.append("\(sevenDay)%")
273273 }
274274 if !claudeWindows.isEmpty {
275โˆ’ segments.append(claudeWindows.joined(separator: " "))
275+ segments.append("๐Ÿ…ฒ" + claudeWindows.joined(separator: " "))
276276 }
277277
278โˆ’ // z.ai โ€” windows joined by space within the segment
278+ // z.ai โ€” provider emoji + bare percentages
279279 var zaiWindows: [String] = []
280280 if let zaiFiveHour = zaiFiveHourPercent, zaiFiveHour > 0 {
281โˆ’ zaiWindows.append("๐Ÿ•‘\(zaiFiveHour)%")
281+ zaiWindows.append("\(zaiFiveHour)%")
282282 }
283283 if let zaiWeekly = zaiWeeklyPercent, zaiWeekly > 0 {
284โˆ’ zaiWindows.append("๐Ÿ“†\(zaiWeekly)%")
284+ zaiWindows.append("\(zaiWeekly)%")
285285 }
286286 if !zaiWindows.isEmpty {
287โˆ’ segments.append(zaiWindows.joined(separator: " "))
287+ segments.append("๐Ÿ…‰" + zaiWindows.joined(separator: " "))
288288 }
289289
290290 if segments.isEmpty {
UsageMenubarTests/StatusBarTextTests.swift+17โˆ’17
@@ -17,7 +17,7 @@ final class StatusBarTextTests: XCTestCase {
1717 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
1818 zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
1919 )
20โˆ’ XCTAssertEqual(title, "โšก42 ยท ๐Ÿ•62% ๐Ÿ“…8%")
20+ XCTAssertEqual(title, "โšก42 ยท \u{1F172}62% 8%")
2121 }
2222
2323 func testHyperOnly() {
@@ -37,7 +37,7 @@ final class StatusBarTextTests: XCTestCase {
3737 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
3838 zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
3939 )
40โˆ’ XCTAssertEqual(title, "๐Ÿ•62% ๐Ÿ“…8%")
40+ XCTAssertEqual(title, "\u{1F172}62% 8%")
4141 }
4242
4343 func testLoadingWithNothingToShow() {
@@ -70,7 +70,7 @@ final class StatusBarTextTests: XCTestCase {
7070 claudeFiveHourPercent: 62, claudeSevenDayPercent: nil,
7171 zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
7272 )
73โˆ’ XCTAssertEqual(title, "๐Ÿ•62%")
73+ XCTAssertEqual(title, "\u{1F172}62%")
7474 }
7575
7676 func testLoadingKeepsAStaleBalanceOnScreen() {
@@ -80,7 +80,7 @@ final class StatusBarTextTests: XCTestCase {
8080 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
8181 zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
8282 )
83โˆ’ XCTAssertEqual(title, "โšก42 ยท ๐Ÿ•62% ๐Ÿ“…8%")
83+ XCTAssertEqual(title, "โšก42 ยท \u{1F172}62% 8%")
8484 }
8585
8686 func testZeroPercentIsShownRatherThanOmitted() {
@@ -90,7 +90,7 @@ final class StatusBarTextTests: XCTestCase {
9090 claudeFiveHourPercent: 0, claudeSevenDayPercent: 8,
9191 zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
9292 )
93โˆ’ XCTAssertEqual(title, "โšก42 ยท ๐Ÿ“…8%")
93+ XCTAssertEqual(title, "โšก42 ยท \u{1F172}8%")
9494 }
9595
9696 func testBothClaudeWindowsZero() {
@@ -110,7 +110,7 @@ final class StatusBarTextTests: XCTestCase {
110110 claudeFiveHourPercent: 62, claudeSevenDayPercent: nil,
111111 zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
112112 )
113โˆ’ XCTAssertEqual(title, "๐Ÿ•62%")
113+ XCTAssertEqual(title, "\u{1F172}62%")
114114 }
115115
116116 func testSevenDayOnly() {
@@ -120,7 +120,7 @@ final class StatusBarTextTests: XCTestCase {
120120 claudeFiveHourPercent: nil, claudeSevenDayPercent: 8,
121121 zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
122122 )
123โˆ’ XCTAssertEqual(title, "๐Ÿ“…8%")
123+ XCTAssertEqual(title, "\u{1F172}8%")
124124 }
125125
126126 // MARK: - Hyper not configured
@@ -154,7 +154,7 @@ final class StatusBarTextTests: XCTestCase {
154154 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
155155 zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
156156 )
157โˆ’ XCTAssertEqual(title, "๐Ÿ•62% ๐Ÿ“…8%")
157+ XCTAssertEqual(title, "\u{1F172}62% 8%")
158158 }
159159
160160 // MARK: - z.ai in Title
@@ -166,7 +166,7 @@ final class StatusBarTextTests: XCTestCase {
166166 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
167167 zaiFiveHourPercent: 12, zaiWeeklyPercent: nil
168168 )
169โˆ’ XCTAssertEqual(title, "๐Ÿ•‘12%")
169+ XCTAssertEqual(title, "\u{1F169}12%")
170170 }
171171
172172 func testZaiWithHyper() {
@@ -176,7 +176,7 @@ final class StatusBarTextTests: XCTestCase {
176176 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
177177 zaiFiveHourPercent: 12, zaiWeeklyPercent: nil
178178 )
179โˆ’ XCTAssertEqual(title, "โšก42 ยท ๐Ÿ•‘12%")
179+ XCTAssertEqual(title, "โšก42 ยท \u{1F169}12%")
180180 }
181181
182182 func testZaiWithClaude() {
@@ -186,7 +186,7 @@ final class StatusBarTextTests: XCTestCase {
186186 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
187187 zaiFiveHourPercent: 12, zaiWeeklyPercent: nil
188188 )
189โˆ’ XCTAssertEqual(title, "๐Ÿ•62% ๐Ÿ“…8% ยท ๐Ÿ•‘12%")
189+ XCTAssertEqual(title, "\u{1F172}62% 8% ยท \u{1F169}12%")
190190 }
191191
192192 func testAllThreeServices() {
@@ -196,7 +196,7 @@ final class StatusBarTextTests: XCTestCase {
196196 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
197197 zaiFiveHourPercent: 12, zaiWeeklyPercent: 3
198198 )
199โˆ’ XCTAssertEqual(title, "โšก42 ยท ๐Ÿ•62% ๐Ÿ“…8% ยท ๐Ÿ•‘12% ๐Ÿ“†3%")
199+ XCTAssertEqual(title, "โšก42 ยท \u{1F172}62% 8% ยท \u{1F169}12% 3%")
200200 }
201201
202202 func testZaiZeroIsOmitted() {
@@ -216,7 +216,7 @@ final class StatusBarTextTests: XCTestCase {
216216 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
217217 zaiFiveHourPercent: 12, zaiWeeklyPercent: nil
218218 )
219โˆ’ XCTAssertEqual(title, "๐Ÿ•‘12%")
219+ XCTAssertEqual(title, "\u{1F169}12%")
220220 }
221221
222222 // MARK: - z.ai Weekly
@@ -228,7 +228,7 @@ final class StatusBarTextTests: XCTestCase {
228228 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
229229 zaiFiveHourPercent: nil, zaiWeeklyPercent: 3
230230 )
231โˆ’ XCTAssertEqual(title, "๐Ÿ“†3%")
231+ XCTAssertEqual(title, "\u{1F169}3%")
232232 }
233233
234234 func testZaiWeeklyWithFiveHour() {
@@ -238,7 +238,7 @@ final class StatusBarTextTests: XCTestCase {
238238 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
239239 zaiFiveHourPercent: 12, zaiWeeklyPercent: 3
240240 )
241โˆ’ XCTAssertEqual(title, "๐Ÿ•‘12% ๐Ÿ“†3%")
241+ XCTAssertEqual(title, "\u{1F169}12% 3%")
242242 }
243243
244244 func testZaiWeeklyZeroIsOmitted() {
@@ -248,7 +248,7 @@ final class StatusBarTextTests: XCTestCase {
248248 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
249249 zaiFiveHourPercent: 12, zaiWeeklyPercent: 0
250250 )
251โˆ’ XCTAssertEqual(title, "๐Ÿ•‘12%")
251+ XCTAssertEqual(title, "\u{1F169}12%")
252252 }
253253
254254 func testLoadingKeepsZaiWeeklyOnScreen() {
@@ -258,7 +258,7 @@ final class StatusBarTextTests: XCTestCase {
258258 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
259259 zaiFiveHourPercent: nil, zaiWeeklyPercent: 3
260260 )
261โˆ’ XCTAssertEqual(title, "๐Ÿ“†3%")
261+ XCTAssertEqual(title, "\u{1F169}3%")
262262 }
263263
264264 // MARK: - Claude Window Percentages