import SwiftUI import CoreGraphics // Hex color helpers shared by the Mac app and the iPhone app. // Views ask for the same few dozen hex colours on every frame: parse each string once. private enum HexCache { nonisolated(unsafe) static var colors: [String: Color] = [:] nonisolated(unsafe) static var cgColors: [String: CGColor] = [:] static let lock = NSLock() } // MARK: - Color from hex string extension Color { init(hex: String) { HexCache.lock.lock() if let c = HexCache.colors[hex] { HexCache.lock.unlock(); self = c; return } HexCache.lock.unlock() let h = hex.trimmingCharacters(in: CharacterSet(charactersIn: "#")) let val = UInt64(h, radix: 16) ?? 0 let r = Double((val >> 16) & 0xFF) / 255 let g = Double((val >> 8) & 0xFF) / 255 let b = Double( val & 0xFF) / 255 self.init(red: r, green: g, blue: b) HexCache.lock.lock(); HexCache.colors[hex] = self; HexCache.lock.unlock() } } // MARK: - CGColor from hex string func cgColorFromHex(_ hex: String) -> CGColor? { HexCache.lock.lock() if let c = HexCache.cgColors[hex] { HexCache.lock.unlock(); return c } HexCache.lock.unlock() let h = hex.trimmingCharacters(in: CharacterSet(charactersIn: "#")) guard let val = UInt64(h, radix: 16) else { return nil } let r = CGFloat((val >> 16) & 0xFF) / 255 let g = CGFloat((val >> 8) & 0xFF) / 255 let b = CGFloat( val & 0xFF) / 255 let c = CGColor(red: r, green: g, blue: b, alpha: 1) HexCache.lock.lock(); HexCache.cgColors[hex] = c; HexCache.lock.unlock() return c } extension CGColor { static func from(_ hex: String) -> CGColor { cgColorFromHex(hex) ?? CGColor(gray: 0.5, alpha: 1) } } #if !os(macOS) // CGColor.white / .black / .clear only exist on macOS; BotEngine uses them. extension CGColor { static var white: CGColor { CGColor(gray: 1, alpha: 1) } static var black: CGColor { CGColor(gray: 0, alpha: 1) } static var clear: CGColor { CGColor(gray: 0, alpha: 0) } } #endif