summaryrefslogtreecommitdiff
path: root/DomainDig/ContentView.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-03 17:14:00 -0500
committerChristian Cleberg <[email protected]>2026-04-03 17:14:00 -0500
commit2c38b5edee339e5fe9060a835d9772a71606dc85 (patch)
treeedc223bd3782b638c0b3d3575b6013ea4a5a4425 /DomainDig/ContentView.swift
parent8465ef359f88ddef7cad68a0c2e361bb0bfe58ff (diff)
downloaddomain-dig-1.6.0.tar.gz
domain-dig-1.6.0.tar.bz2
domain-dig-1.6.0.zip
Add HTTP header grading and protocol metadatav1.6.0
Diffstat (limited to 'DomainDig/ContentView.swift')
-rw-r--r--DomainDig/ContentView.swift70
1 files changed, 69 insertions, 1 deletions
diff --git a/DomainDig/ContentView.swift b/DomainDig/ContentView.swift
index bb93789..482d3bc 100644
--- a/DomainDig/ContentView.swift
+++ b/DomainDig/ContentView.swift
@@ -544,7 +544,19 @@ struct ContentView: View {
private var httpHeadersSection: some View {
VStack(alignment: .leading, spacing: 12) {
- sectionHeader("HTTP Headers")
+ HStack(spacing: 8) {
+ sectionHeader("HTTP Headers")
+ if let grade = viewModel.httpSecurityGrade {
+ Text(grade)
+ .font(.system(.caption, design: .monospaced))
+ .foregroundStyle(httpSecurityGradeColor(for: grade))
+ .padding(.horizontal, 8)
+ .padding(.vertical, 2)
+ .background(httpSecurityGradeColor(for: grade).opacity(0.18))
+ .clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous))
+ }
+ Spacer()
+ }
if viewModel.httpHeadersLoading {
ProgressView("Fetching headers…")
@@ -554,6 +566,26 @@ struct ContentView: View {
errorLabel(error)
} else {
horizontallyScrollableCard {
+ if !httpStatusSummaryParts.isEmpty || http3AvailabilityNote != nil {
+ HStack(alignment: .top, spacing: 0) {
+ ForEach(Array(httpStatusSummaryParts.enumerated()), id: \.offset) { index, part in
+ if index > 0 {
+ Text(" ")
+ .font(.system(.caption, design: .monospaced))
+ }
+ Text(part.text)
+ .font(.system(.caption, design: .monospaced))
+ .foregroundStyle(part.color)
+ }
+ if let http3AvailabilityNote {
+ Text(" ")
+ .font(.system(.caption, design: .monospaced))
+ Text(http3AvailabilityNote)
+ .font(.system(.caption, design: .monospaced))
+ .foregroundStyle(.secondary)
+ }
+ }
+ }
ForEach(viewModel.httpHeaders) { header in
HStack(alignment: .top, spacing: 4) {
Text(header.name + ":")
@@ -750,6 +782,42 @@ struct ContentView: View {
.padding(8)
}
+ private var httpStatusSummaryParts: [(text: String, color: Color)] {
+ var parts: [(text: String, color: Color)] = []
+
+ if let statusCode = viewModel.httpStatusCode {
+ parts.append(("HTTP \(statusCode)", .cyan))
+ }
+ if let responseTimeMs = viewModel.httpResponseTimeMs {
+ parts.append(("\(responseTimeMs)ms", .secondary))
+ }
+ if let httpProtocol = viewModel.httpProtocol {
+ parts.append((httpProtocol, .secondary))
+ }
+
+ return parts
+ }
+
+ private var http3AvailabilityNote: String? {
+ guard viewModel.http3Advertised, viewModel.httpProtocol != "HTTP/3" else {
+ return nil
+ }
+ return "(HTTP/3 available)"
+ }
+
+ private func httpSecurityGradeColor(for grade: String) -> Color {
+ switch grade {
+ case "A", "B":
+ .green
+ case "C":
+ .yellow
+ case "D", "F":
+ .red
+ default:
+ .secondary
+ }
+ }
+
private func expiryColor(_ days: Int) -> Color {
if days < 30 { return .red }
if days < 60 { return .yellow }