mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-13 01:15:08 +00:00
106 lines
3.5 KiB
Swift
106 lines
3.5 KiB
Swift
import SwiftUI
|
|
|
|
/// A reserved toolbar row keeps feedback from resizing or replacing the rule table.
|
|
struct RulesOperationStatusView: View {
|
|
@ObservedObject var workflow: RulesWorkflow
|
|
@State private var showsDetails = false
|
|
|
|
var body: some View {
|
|
HStack(spacing: 8) {
|
|
Spacer(minLength: 0)
|
|
switch workflow.snapshot.operationStatus {
|
|
case .idle, .initialLoading:
|
|
EmptyView()
|
|
case .updating:
|
|
progress("正在更新规则…")
|
|
case .refreshing:
|
|
progress("正在加载规则…")
|
|
case .collectionIncomplete:
|
|
Label(RulesCopy.text("集合不完整"), systemImage: "exclamationmark.triangle")
|
|
.foregroundStyle(.orange)
|
|
detailsButton
|
|
refreshButton
|
|
case .feedback(let feedback):
|
|
Label {
|
|
Text(verbatim: feedback.summary).lineLimit(1).truncationMode(.middle)
|
|
} icon: {
|
|
Image(
|
|
systemName: feedback.outcome.isSuccess ? "checkmark.circle" : "exclamationmark.triangle"
|
|
)
|
|
.foregroundStyle(feedback.outcome.isSuccess ? Color.secondary : Color.orange)
|
|
}
|
|
.help(feedback.summary)
|
|
if !feedback.outcome.isSuccess {
|
|
detailsButton
|
|
Button(RulesCopy.text("关闭"), systemImage: "xmark") {
|
|
workflow.dismissFeedback()
|
|
}.labelStyle(.iconOnly)
|
|
}
|
|
}
|
|
}
|
|
.font(.caption)
|
|
.controlSize(.small)
|
|
.frame(maxWidth: .infinity, minHeight: 22, maxHeight: 22)
|
|
.onChange(of: workflow.snapshot.operationStatus) { _, _ in showsDetails = false }
|
|
}
|
|
|
|
private func progress(_ key: String) -> some View {
|
|
HStack(spacing: 6) {
|
|
ProgressView().controlSize(.mini)
|
|
Text(RulesCopy.text(key))
|
|
}.accessibilityElement(children: .combine)
|
|
}
|
|
|
|
private var detailsButton: some View {
|
|
Button(RulesCopy.text("查看详情")) { showsDetails = true }
|
|
.popover(isPresented: $showsDetails) { details }
|
|
}
|
|
|
|
private var refreshButton: some View {
|
|
Button(RulesCopy.text("刷新规则")) {
|
|
showsDetails = false
|
|
Task { await workflow.refresh(retryFailedSources: true) }
|
|
}
|
|
}
|
|
|
|
private var details: some View {
|
|
ScrollView {
|
|
VStack(alignment: .leading, spacing: 10) {
|
|
if let feedback = workflow.snapshot.commitFeedback {
|
|
Text(verbatim: feedback.summary).font(.headline)
|
|
if let detail = feedback.outcome.failureDetail {
|
|
Text(verbatim: detail).textSelection(.enabled)
|
|
}
|
|
if let nextStep = feedback.outcome.nextStep {
|
|
Text(RulesCopy.text(nextStep))
|
|
}
|
|
}
|
|
if !workflow.snapshot.issues.isEmpty {
|
|
Text(RulesCopy.text("规则列表未更新,请刷新规则。"))
|
|
RulesCollectionIssuesView(issues: workflow.snapshot.issues)
|
|
}
|
|
}.frame(maxWidth: .infinity, alignment: .leading).padding()
|
|
}.frame(width: 380).frame(maxHeight: 300)
|
|
}
|
|
}
|
|
|
|
struct RulesCollectionIssuesView: View {
|
|
let issues: [RulesPageSnapshot.Issue]
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 6) {
|
|
Text(RulesCopy.text("集合不完整时,覆盖解释仅基于已加载来源。"))
|
|
ForEach(issues, id: \.self) { issue in
|
|
Text(verbatim: description(issue)).textSelection(.enabled)
|
|
}
|
|
}.font(.caption)
|
|
}
|
|
|
|
private func description(_ issue: RulesPageSnapshot.Issue) -> String {
|
|
switch issue {
|
|
case .userDocument(let detail): "\(RulesCopy.text("自定义规则")): \(detail)"
|
|
case .builtin(let source, let detail): "\(source.label): \(detail)"
|
|
}
|
|
}
|
|
}
|