import SwiftUI import AppKit struct ModelCardRowView: View { let model: PredefinedModel let isDownloaded: Bool let isCurrent: Bool let downloadProgress: [String: Double] let modelURL: URL? // Actions var deleteAction: () -> Void var setDefaultAction: () -> Void var downloadAction: () -> Void private var isDownloading: Bool { downloadProgress.keys.contains(model.name + "_main") || downloadProgress.keys.contains(model.name + "_coreml") } var body: some View { HStack(alignment: .top, spacing: 16) { // Main Content VStack(alignment: .leading, spacing: 6) { headerSection metadataSection descriptionSection progressSection } .frame(maxWidth: .infinity, alignment: .leading) // Action Controls actionSection } .padding(16) .background( RoundedRectangle(cornerRadius: 14) .fill( LinearGradient( gradient: Gradient(colors: [ Color(NSColor.controlBackgroundColor).opacity(1.0), Color(NSColor.controlBackgroundColor).opacity(0.6) ]), startPoint: .topLeading, endPoint: .bottomTrailing ) ) .overlay( RoundedRectangle(cornerRadius: 14) .stroke( LinearGradient( gradient: Gradient(colors: [ Color.white.opacity(0.3), Color.white.opacity(0.05) ]), startPoint: .topLeading, endPoint: .bottomTrailing ), lineWidth: 1 ) ) .shadow( color: Color.primary.opacity(0.08), radius: 8, x: 0, y: 4 ) ) } // MARK: - Components private var headerSection: some View { HStack(alignment: .firstTextBaseline) { Text(model.displayName) .font(.system(size: 13, weight: .semibold)) .foregroundColor(Color(.labelColor)) statusBadge Spacer() } } private var statusBadge: some View { Group { if isCurrent { Text("Default") .font(.system(size: 11, weight: .medium)) .padding(.horizontal, 6) .padding(.vertical, 2) .background(Capsule().fill(Color.accentColor)) .foregroundColor(.white) } else if isDownloaded { Text("Downloaded") .font(.system(size: 11, weight: .medium)) .padding(.horizontal, 6) .padding(.vertical, 2) .background(Capsule().fill(Color(.quaternaryLabelColor))) .foregroundColor(Color(.labelColor)) } } } private var metadataSection: some View { HStack(spacing: 16) { // Language Label(model.language, systemImage: "globe") .font(.system(size: 11)) .foregroundColor(Color(.secondaryLabelColor)) // Size Label(model.size, systemImage: "internaldrive") .font(.system(size: 11)) .foregroundColor(Color(.secondaryLabelColor)) // Speed HStack(spacing: 4) { Text("Speed") .font(.system(size: 11, weight: .medium)) .foregroundColor(Color(.secondaryLabelColor)) progressDotsWithNumber(value: model.speed * 10) } // Accuracy HStack(spacing: 4) { Text("Accuracy") .font(.system(size: 11, weight: .medium)) .foregroundColor(Color(.secondaryLabelColor)) progressDotsWithNumber(value: model.accuracy * 10) } } } private var descriptionSection: some View { Text(model.description) .font(.system(size: 11)) .foregroundColor(Color(.secondaryLabelColor)) .lineLimit(2) .fixedSize(horizontal: false, vertical: true) .padding(.top, 4) } private var progressSection: some View { Group { if isDownloading { DownloadProgressView( modelName: model.name, downloadProgress: downloadProgress ) .padding(.top, 8) .frame(maxWidth: .infinity, alignment: .leading) } } } private var actionSection: some View { HStack(spacing: 8) { if isCurrent { Text("Default Model") .font(.system(size: 12)) .foregroundColor(Color(.secondaryLabelColor)) } else if isDownloaded { Button(action: setDefaultAction) { Text("Set as Default") .font(.system(size: 12)) } .buttonStyle(.bordered) .controlSize(.small) } else { Button(action: downloadAction) { HStack(spacing: 4) { Text(isDownloading ? "Downloading..." : "Download") .font(.system(size: 12, weight: .medium)) Image(systemName: "arrow.down.circle") .font(.system(size: 12, weight: .medium)) } .foregroundColor(.white) .padding(.horizontal, 12) .padding(.vertical, 6) .background( Capsule() .fill(Color(.controlAccentColor)) .shadow(color: Color(.controlAccentColor).opacity(0.2), radius: 2, x: 0, y: 1) ) } .buttonStyle(.plain) .disabled(isDownloading) } if isDownloaded { Menu { Button(action: deleteAction) { Label("Delete Model", systemImage: "trash") } if isDownloaded { Button { if let modelURL = modelURL { NSWorkspace.shared.selectFile(modelURL.path, inFileViewerRootedAtPath: "") } } label: { Label("Show in Finder", systemImage: "folder") } } } label: { Image(systemName: "ellipsis.circle") .font(.system(size: 14)) } .menuStyle(.borderlessButton) .menuIndicator(.hidden) .frame(width: 20, height: 20) } } } // MARK: - Helpers private var downloadComponents: [(String, Double)] { [ ("Model", downloadProgress[model.name + "_main"] ?? 0), ("CoreML", downloadProgress[model.name + "_coreml"] ?? 0) ].filter { $0.1 > 0 } } private func progressDotsWithNumber(value: Double) -> some View { HStack(spacing: 4) { progressDots(value: value) Text(String(format: "%.1f", value)) .font(.system(size: 10, weight: .medium, design: .monospaced)) .foregroundColor(Color(.secondaryLabelColor)) } } private func progressDots(value: Double) -> some View { HStack(spacing: 2) { ForEach(0..<5) { index in Circle() .fill(index < Int(value / 2) ? performanceColor(value: value / 10) : Color(.quaternaryLabelColor)) .frame(width: 6, height: 6) } } } private func performanceColor(value: Double) -> Color { switch value { case 0.8...1.0: return Color(.systemGreen) case 0.6..<0.8: return Color(.systemYellow) case 0.4..<0.6: return Color(.systemOrange) default: return Color(.systemRed) } } }