mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-12 01:55:06 +00:00
The home run-control card and the menu-bar status card render the agent and system-proxy status rows straight from snapshot replacements, so fast operations (e.g. proxy mode switches) flash transient states like "applying" before settling. Add a presentation-layer debounce shared by both surfaces: - TransientDelayGate: per-stream gate where stable values display immediately, transient values (starting/applying/repairing) display after 400 ms and are dropped when superseded, and displayed transients are held for at least 400 ms. - StatusDisplayModel: app-level shared model deriving agent and system-proxy payloads (row + detail + hint) from workflow snapshots through two independent gates; domain facts keep their cadence. - Wire the model through the composition root into RuntimeControlCard and StatusCardView; toggles, approval actions, the difference view and target/mode rows keep reading the raw snapshot.
49 lines
1.4 KiB
Swift
49 lines
1.4 KiB
Swift
import SwiftUI
|
||
|
||
/// 菜单栏面板代理状态卡。状态行经 StatusDisplayModel 的瞬态门控呈现
|
||
/// (与首页运行控制卡同一 debounce 口径);活动目标与模式行仍从 control
|
||
/// 的整体 snapshot 直接派生。
|
||
struct StatusCardView: View {
|
||
@ObservedObject var control: ProxyControlWorkflow
|
||
let statusDisplay: StatusDisplayModel
|
||
|
||
var body: some View {
|
||
let card = StatusCardModel.card(from: control.snapshot)
|
||
row(statusDisplay.agent.row)
|
||
if let detail = statusDisplay.agent.detail {
|
||
detailLine(detail)
|
||
}
|
||
row(statusDisplay.systemProxy.row)
|
||
if let detail = statusDisplay.systemProxy.detail {
|
||
detailLine(detail)
|
||
}
|
||
|
||
Text(card.target.text)
|
||
.truncationMode(.middle)
|
||
.help(card.target.help)
|
||
.accessibilityElement(children: .ignore)
|
||
.accessibilityLabel("活动目标:\(card.target.text)")
|
||
|
||
Text("模式:\(card.modeText)").accessibilityElement(children: .combine)
|
||
}
|
||
|
||
private func row(_ row: StatusCardModel.Row) -> some View {
|
||
Text("\(row.label):\(row.text)").accessibilityElement(children: .combine)
|
||
}
|
||
|
||
private func detailLine(_ detail: StatusCardModel.DetailLine) -> some View {
|
||
Text(detail.text)
|
||
.lineLimit(2)
|
||
.help(detail.text)
|
||
}
|
||
|
||
private func color(_ tone: StatusCardModel.Tone) -> Color {
|
||
switch tone {
|
||
case .positive: .green
|
||
case .attention: .orange
|
||
case .failure: .red
|
||
case .neutral: .secondary
|
||
}
|
||
}
|
||
}
|