@@ -3,6 +3,26 @@ import CodexBarCore
33import QuartzCore
44import SwiftUI
55
6+ enum HostedSubviewContentFingerprint : Equatable {
7+ case text( String )
8+ case costHistory( CostHistoryChartMenuView . RenderFingerprint )
9+ }
10+
11+ struct HostedSubviewRenderSignature : Equatable {
12+ let chartID : String
13+ let providerRawValue : String ?
14+ let widthBitPattern : UInt64
15+ let content : HostedSubviewContentFingerprint
16+ }
17+
18+ final class HostedSubviewRenderSignatureBox : NSObject {
19+ let signature : HostedSubviewRenderSignature
20+
21+ init ( _ signature: HostedSubviewRenderSignature ) {
22+ self . signature = signature
23+ }
24+ }
25+
626extension StatusItemController {
727 private struct HostedSubviewIdentity {
828 let chartID : String
@@ -153,7 +173,7 @@ extension StatusItemController {
153173 return
154174 }
155175 let signature = self . hostedSubviewRenderSignature ( identity: identity, width: width)
156- if self . hostedSubviewRenderSignatures. object ( forKey: menu) as String ? == signature {
176+ if self . hostedSubviewRenderSignatures. object ( forKey: menu) ? . signature == signature {
157177 if identity. chartID == Self . zaiHourlyUsageChartID {
158178 self . refreshHostedSubviewHeights ( in: menu)
159179 }
@@ -210,7 +230,9 @@ extension StatusItemController {
210230 chartID: identity. chartID,
211231 providerRawValue: identity. provider? . rawValue ?? identity. providerRawValue)
212232 }
213- self . hostedSubviewRenderSignatures. setObject ( signature as NSString , forKey: menu)
233+ self . hostedSubviewRenderSignatures. setObject (
234+ HostedSubviewRenderSignatureBox ( signature) ,
235+ forKey: menu)
214236 }
215237
216238 private func hostedSubviewIdentity( for menu: NSMenu )
@@ -240,51 +262,51 @@ extension StatusItemController {
240262 width: CGFloat )
241263 {
242264 let signature = self . hostedSubviewRenderSignature ( identity: identity, width: width)
243- self . hostedSubviewRenderSignatures. setObject ( signature as NSString , forKey: menu)
265+ self . hostedSubviewRenderSignatures. setObject (
266+ HostedSubviewRenderSignatureBox ( signature) ,
267+ forKey: menu)
244268 }
245269
246270 private func hostedSubviewRenderSignature(
247271 identity: HostedSubviewIdentity ,
248- width: CGFloat ) -> String
272+ width: CGFloat ) -> HostedSubviewRenderSignature
249273 {
250- let contentSignature : String = switch identity. chartID {
274+ let contentSignature : HostedSubviewContentFingerprint = switch identity. chartID {
251275 case Self . usageBreakdownChartID:
252- Self . dashboardBreakdownReadinessSignature (
276+ . text ( Self . dashboardBreakdownReadinessSignature (
253277 OpenAIDashboardDailyBreakdown . removingSkillUsageServices (
254- from: self . store. openAIDashboard? . usageBreakdown ?? [ ] ) )
278+ from: self . store. openAIDashboard? . usageBreakdown ?? [ ] ) ) )
255279 case Self . creditsHistoryChartID:
256- Self . dashboardBreakdownReadinessSignature ( self . store. openAIDashboard? . dailyBreakdown ?? [ ] )
280+ . text ( Self . dashboardBreakdownReadinessSignature ( self . store. openAIDashboard? . dailyBreakdown ?? [ ] ) )
257281 case Self . costHistoryChartID:
258- identity. provider. map ( self . costHistoryRenderSignature ( for: ) ) ?? " missing-provider "
282+ if let provider = identity. provider {
283+ self . costHistoryRenderFingerprint ( for: provider)
284+ } else {
285+ . text( " missing-provider " )
286+ }
259287 case Self . usageHistoryChartID:
260- identity. provider. map ( self . usageHistoryRenderSignature ( for: ) ) ?? " missing-provider "
288+ . text ( identity. provider. map ( self . usageHistoryRenderSignature ( for: ) ) ?? " missing-provider " )
261289 case Self . storageBreakdownID:
262- identity. provider. map ( self . storageBreakdownRenderSignature ( for: ) ) ?? " missing-provider "
290+ . text ( identity. provider. map ( self . storageBreakdownRenderSignature ( for: ) ) ?? " missing-provider " )
263291 case Self . statusComponentsID:
264- identity. provider. map ( self . statusComponentsRenderSignature ( for: ) ) ?? " missing-provider "
292+ . text ( identity. provider. map ( self . statusComponentsRenderSignature ( for: ) ) ?? " missing-provider " )
265293 case Self . zaiHourlyUsageChartID:
266- identity. provider. map ( self . zaiHourlyUsageRenderSignature ( for: ) ) ?? " missing-provider "
294+ . text ( identity. provider. map ( self . zaiHourlyUsageRenderSignature ( for: ) ) ?? " missing-provider " )
267295 default :
268- " unknown "
296+ . text ( " unknown " )
269297 }
270- return [
271- identity. chartID,
272- identity. providerRawValue ?? " " ,
273- String ( Double ( width) . bitPattern, radix: 16 ) ,
274- contentSignature,
275- ] . joined ( separator: " | " )
298+ return HostedSubviewRenderSignature (
299+ chartID: identity. chartID,
300+ providerRawValue: identity. providerRawValue,
301+ widthBitPattern: Double ( width) . bitPattern,
302+ content: contentSignature)
276303 }
277304
278- private func costHistoryRenderSignature( for provider: UsageProvider ) -> String {
279- guard let snapshot = self . tokenSnapshotForCostHistorySubmenu ( provider: provider) else { return " none " }
280- return [
281- snapshot. currencyCode,
282- " \( snapshot. historyDays) " ,
283- snapshot. historyLabel ?? " " ,
284- snapshot. last30DaysCostUSD. map { String ( $0. bitPattern, radix: 16 ) } ?? " nil " ,
285- String ( reflecting: snapshot. daily) ,
286- String ( reflecting: snapshot. projects) ,
287- ] . joined ( separator: " | " )
305+ private func costHistoryRenderFingerprint( for provider: UsageProvider ) -> HostedSubviewContentFingerprint {
306+ guard let snapshot = self . tokenSnapshotForCostHistorySubmenu ( provider: provider) else {
307+ return . text( " none " )
308+ }
309+ return . costHistory( CostHistoryChartMenuView . renderFingerprint ( from: snapshot) )
288310 }
289311
290312 private func usageHistoryRenderSignature( for provider: UsageProvider ) -> String {
@@ -626,3 +648,16 @@ extension StatusItemController {
626648 return true
627649 }
628650}
651+
652+ #if DEBUG
653+ extension StatusItemController {
654+ func _hostedSubviewRenderSignatureForTesting( menu: NSMenu , width: CGFloat ) -> HostedSubviewRenderSignature ? {
655+ guard let identity = self . hostedSubviewIdentity ( for: menu) else { return nil }
656+ return self . hostedSubviewRenderSignature ( identity: identity, width: width)
657+ }
658+
659+ func _storedHostedSubviewRenderSignatureForTesting( menu: NSMenu ) -> HostedSubviewRenderSignature ? {
660+ self . hostedSubviewRenderSignatures. object ( forKey: menu) ? . signature
661+ }
662+ }
663+ #endif
0 commit comments