Files
1jehuang--jcode/ios/Sources/JCodeMobile/Views/ConnectionBanner.swift
T
wehub-resource-sync a789495a98
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
CI / Quality Guardrails (push) Has been cancelled
CI / Build & Test (macos-latest) (push) Has been cancelled
CI / Build & Test (ubuntu-latest) (push) Has been cancelled
CI / Build & Test (windows-latest) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / PowerShell Syntax (push) Has been cancelled
CI / Windows Cross-Target Check (Linux) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:34 +08:00

91 lines
3.0 KiB
Swift

import JCodeKit
import SwiftUI
/// Inline banner shown while the connection is down, with a manual retry.
///
/// The automatic reconnect loop keeps running underneath; the button just
/// short-circuits the backoff wait for impatient humans.
struct ConnectionBanner: View {
let phase: ConnectionPhase
let onRetry: () -> Void
var body: some View {
HStack(spacing: 8) {
Image(systemName: "wifi.slash")
.font(.footnote)
.foregroundStyle(Theme.warning)
.accessibilityHidden(true)
Text(label)
.font(.footnote)
.foregroundStyle(Theme.textPrimary)
.lineLimit(2)
Spacer(minLength: 0)
Button(action: onRetry) {
Text("Retry")
.font(.footnote.weight(.semibold))
.foregroundStyle(Theme.mint)
.frame(minWidth: 44, minHeight: 44)
}
.accessibilityLabel("Retry connection")
.accessibilityHint("Reconnects to the server now")
}
.padding(.horizontal, 12)
.background(Theme.warning.opacity(0.12))
.clipShape(RoundedRectangle(cornerRadius: 14))
.overlay(
RoundedRectangle(cornerRadius: 14)
.stroke(Theme.warning.opacity(0.35), lineWidth: 1)
)
.padding(.horizontal)
.accessibilityElement(children: .combine)
}
private var label: String {
switch phase {
case .reconnecting(let attempt):
"Connection lost, retrying (attempt \(attempt))"
case .failed:
"Connection failed"
default:
"Offline"
}
}
}
/// Chip shown above the composer while soft-interrupt messages wait to be
/// injected into the running turn, with a cancel affordance.
struct QueuedInterruptChip: View {
let count: Int
let onCancel: () -> Void
var body: some View {
HStack(spacing: 8) {
Image(systemName: "clock")
.font(.footnote)
.foregroundStyle(Theme.mint)
.accessibilityHidden(true)
Text(count == 1 ? "1 message queued" : "\(count) messages queued")
.font(.footnote)
.foregroundStyle(Theme.textPrimary)
Spacer(minLength: 0)
Button(action: onCancel) {
Text("Cancel")
.font(.footnote.weight(.semibold))
.foregroundStyle(Theme.error)
.frame(minWidth: 44, minHeight: 44)
}
.accessibilityLabel("Cancel queued messages")
.accessibilityHint("Removes messages waiting to interrupt the response")
}
.padding(.horizontal, 12)
.background(Theme.mintTint)
.clipShape(RoundedRectangle(cornerRadius: 14))
.overlay(
RoundedRectangle(cornerRadius: 14)
.stroke(Theme.mint.opacity(0.35), lineWidth: 1)
)
.padding(.horizontal)
.accessibilityElement(children: .combine)
}
}