54 lines · 2.0 KB · Swift
RawDownload
import AppKit extension StatusItemController {    struct MenuCardHeightCacheKey: Hashable {        let id: String        let scope: String        let width: Int        let textScale: Int        let fingerprint: String    }     /// Measured card height also depends on the resolved font sizes, which the menu cards    /// derive from semantic text styles (`.body`, `.footnote`, …). Those scale with the    /// macOS system text-size / Dynamic Type setting, which is neither part of the content    /// fingerprint nor invalidated on rebuild. Fold the current resolved scale into the key    /// so a runtime text-size change forces a fresh measurement instead of returning a    /// height measured at the old scale (clipped / over-tall cards).    static func menuCardHeightTextScaleToken() -> Int {        Int((NSFont.preferredFont(forTextStyle: .body).pointSize * 100).rounded())    }     func cachedMenuCardHeight(        for id: String,        scope: String,        width: CGFloat,        fingerprint: String? = nil,        measure: () -> CGFloat) -> CGFloat    {        let key = MenuCardHeightCacheKey(            id: id,            scope: scope,            width: Int((width * 100).rounded()),            textScale: Self.menuCardHeightTextScaleToken(),            fingerprint: fingerprint ?? "version:\(self.menuSession.contentVersion)")        if let cached = self.menuCardHeightCache[key] {            return cached        }        let height = measure()        if self.menuCardHeightCache.count > 256 {            self.menuCardHeightCache.removeAll(keepingCapacity: true)        }        self.menuCardHeightCache[key] = height        return height    }     func pruneVersionScopedMenuCardHeightCache() {        let currentVersionFingerprint = "version:\(self.menuSession.contentVersion)"        for key in self.menuCardHeightCache.keys            where key.fingerprint.hasPrefix("version:") && key.fingerprint != currentVersionFingerprint        {            self.menuCardHeightCache.removeValue(forKey: key)        }    }}