import SwiftUI import AppKit /// Иконка монеты из готовых данных (виджет получает их от провайдера). /// Без данных — кружок с первой буквой в фирменном цвете монеты. struct CoinIconView: View { let currency: String let data: Data? let size: CGFloat var body: some View { Group { if let data, let image = NSImage(data: data) { Image(nsImage: image) .resizable() .aspectRatio(contentMode: .fit) .clipShape(Circle()) } else { fallback } } .frame(width: size, height: size) .overlay(Circle().strokeBorder(.white.opacity(0.08), lineWidth: 1)) } private var fallback: some View { ZStack { Circle() .fill( LinearGradient( colors: [ CoinPalette.color(for: currency), CoinPalette.color(for: currency).opacity(0.65), ], startPoint: .top, endPoint: .bottom ) ) Text(String(currency.prefix(1))) .font(.system(size: size * 0.44, weight: .bold, design: .rounded)) .foregroundStyle(.white) } } } /// Иконка с самостоятельной загрузкой через общий кэш — для окна настроек. struct RemoteCoinIcon: View { let currency: String var size: CGFloat = 30 @State private var data: Data? var body: some View { CoinIconView(currency: currency, data: data, size: size) .task(id: currency) { data = await IconStore.shared.data(for: currency) } } }