import SwiftUI import ProxyCore struct TrafficRowView: View { let traffic: CapturedTraffic var body: some View { VStack(alignment: .leading, spacing: 14) { HStack(alignment: .top, spacing: 10) { HStack(spacing: 6) { MethodBadge(method: traffic.method) StatusBadge(statusCode: traffic.statusCode) } Spacer(minLength: 12) VStack(alignment: .trailing, spacing: 4) { Text(traffic.startDate, format: .dateTime.hour().minute().second().secondFraction(.fractional(3))) .font(.caption.weight(.medium)) .foregroundStyle(.secondary) Text(traffic.formattedDuration) .font(.caption2.weight(.semibold)) .foregroundStyle(.secondary) } } VStack(alignment: .leading, spacing: 4) { Text(primaryLine) .font(.subheadline.weight(.semibold)) .foregroundStyle(.primary) .lineLimit(2) Text(secondaryLine) .font(.caption) .foregroundStyle(.secondary) .lineLimit(2) } HStack(spacing: 8) { TransferPill( systemImage: "arrow.up.circle.fill", text: formatBytes(traffic.requestBodySize), tint: .green ) TransferPill( systemImage: "arrow.down.circle.fill", text: responseSizeText, tint: .blue ) if let responseContentType = traffic.responseContentType { MetaPill(text: shortContentType(responseContentType)) } else if let requestContentType = traffic.requestContentType { MetaPill(text: shortContentType(requestContentType)) } if traffic.scheme == "https" && !traffic.isSslDecrypted { MetaPill(text: "Encrypted", tint: .orange) } Spacer(minLength: 0) if traffic.isPinned { Image(systemName: "pin.fill") .font(.caption) .foregroundStyle(.secondary) } } } .padding(16) .frame(maxWidth: .infinity, alignment: .leading) .background( RoundedRectangle(cornerRadius: 22, style: .continuous) .fill(Color(.secondarySystemGroupedBackground)) ) .overlay( RoundedRectangle(cornerRadius: 22, style: .continuous) .strokeBorder(Color.primary.opacity(0.05), lineWidth: 1) ) } private func formatBytes(_ bytes: Int) -> String { if bytes < 1024 { return "\(bytes) B" } if bytes < 1_048_576 { return String(format: "%.1f KB", Double(bytes) / 1024) } return String(format: "%.1f MB", Double(bytes) / 1_048_576) } private var primaryLine: String { let components = URLComponents(string: traffic.url) let path = components?.path ?? traffic.url let query = components?.percentEncodedQuery.map { "?\($0)" } ?? "" let route = path.isEmpty ? traffic.domain : path + query return route.isEmpty ? traffic.url : route } private var secondaryLine: String { if let statusText = traffic.statusText, let statusCode = traffic.statusCode { return "\(traffic.domain) • \(statusCode) \(statusText)" } return traffic.domain } private var responseSizeText: String { if traffic.responseBodySize > 0 { return formatBytes(traffic.responseBodySize) } if traffic.statusCode == nil { return "Pending" } return "0 B" } private func shortContentType(_ contentType: String) -> String { let base = contentType.split(separator: ";").first.map(String.init) ?? contentType return base.replacingOccurrences(of: "application/", with: "") .replacingOccurrences(of: "text/", with: "") } } private struct TransferPill: View { let systemImage: String let text: String let tint: Color var body: some View { Label(text, systemImage: systemImage) .font(.caption2.weight(.semibold)) .foregroundStyle(tint) .padding(.horizontal, 10) .padding(.vertical, 6) .background(tint.opacity(0.12), in: Capsule()) } } private struct MetaPill: View { let text: String var tint: Color = .secondary var body: some View { Text(text) .font(.caption2.weight(.semibold)) .foregroundStyle(tint) .padding(.horizontal, 10) .padding(.vertical, 6) .background(tint.opacity(0.10), in: Capsule()) } }