From cc0f0a9513f292d5b37ec7dbc55d0d18eb5afe4f Mon Sep 17 00:00:00 2001 From: Qiu Yuzhou Date: Fri, 16 Oct 2026 00:10:15 +0800 Subject: [PATCH] style(home): refine control card presentation --- .../App/Resources/Localizable.xcstrings | 35 +++---- .../App/UI/Home/HomeComponents.swift | 4 +- .../App/UI/Home/RuntimeControlCard.swift | 95 +++++++++---------- .../Home/TerminalProxyEnvironmentCard.swift | 4 +- 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/ShadowsocksX-NG2/App/Resources/Localizable.xcstrings b/ShadowsocksX-NG2/App/Resources/Localizable.xcstrings index ac5a5168..7b1bc84f 100644 --- a/ShadowsocksX-NG2/App/Resources/Localizable.xcstrings +++ b/ShadowsocksX-NG2/App/Resources/Localizable.xcstrings @@ -4168,23 +4168,6 @@ } } }, - "后台代理客户端与系统代理设置相互独立控制": { - "extractionState": "manual", - "localizations": { - "zh-Hans": { - "stringUnit": { - "state": "translated", - "value": "后台代理客户端与系统代理设置相互独立控制" - } - }, - "en": { - "stringUnit": { - "state": "translated", - "value": "Control the background proxy client and system proxy settings independently" - } - } - } - }, "启动失败": { "extractionState": "manual", "localizations": { @@ -8749,6 +8732,24 @@ } } } + }, + "运行后台代理客户端": { + "extractionState": "manual", + "comment": "首页运行控制卡片中用于启动或停止后台代理客户端的开关标题。", + "localizations": { + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "运行后台代理客户端" + } + }, + "en": { + "stringUnit": { + "state": "translated", + "value": "Run background proxy client" + } + } + } } }, "version": "1.0" diff --git a/ShadowsocksX-NG2/App/UI/Home/HomeComponents.swift b/ShadowsocksX-NG2/App/UI/Home/HomeComponents.swift index f50662df..c6d0a74c 100644 --- a/ShadowsocksX-NG2/App/UI/Home/HomeComponents.swift +++ b/ShadowsocksX-NG2/App/UI/Home/HomeComponents.swift @@ -8,11 +8,11 @@ struct HomeCard: View { @ViewBuilder var content: () -> Content var body: some View { - VStack(alignment: .leading, spacing: 0) { + VStack(alignment: .leading, spacing: 8) { HStack(alignment: .firstTextBaseline) { VStack(alignment: .leading, spacing: 2) { Text(title) - .font(.title3.weight(.semibold)) + .font(.title2.weight(.semibold)) if let subtitle { Text(subtitle) .font(.subheadline) diff --git a/ShadowsocksX-NG2/App/UI/Home/RuntimeControlCard.swift b/ShadowsocksX-NG2/App/UI/Home/RuntimeControlCard.swift index 69e8f8ef..3fdcf234 100644 --- a/ShadowsocksX-NG2/App/UI/Home/RuntimeControlCard.swift +++ b/ShadowsocksX-NG2/App/UI/Home/RuntimeControlCard.swift @@ -11,61 +11,60 @@ struct RuntimeControlCard: View { let summary = StatusMenuModel.summary(from: control.snapshot) HomeCard( title: String(localized: "运行控制"), - subtitle: String(localized: "后台代理客户端与系统代理设置相互独立控制"), + subtitle: nil, trailing: { EmptyView() }, content: { - VStack(alignment: .leading, spacing: 14) { - VStack(alignment: .leading, spacing: 6) { - HStack { - Toggle("后台代理客户端", isOn: agentBinding) - .toggleStyle(.switch) - Spacer(minLength: 0) - Text(summary.status) - .font(.callout.weight(.medium)) - .foregroundStyle(.secondary) - .lineLimit(1) - } - if let detail = summary.detail { - Text(detail) - .font(.caption) - .foregroundStyle(.orange) - .fixedSize(horizontal: false, vertical: true) - } + VStack(alignment: .leading, spacing: 6) { + Toggle(isOn: agentBinding) { + Text("运行后台代理客户端") + .font(.title3) + .frame(maxWidth: .infinity, alignment: .leading) } - Divider() - VStack(alignment: .leading, spacing: 6) { - HStack { - Toggle("设置系统代理", isOn: systemProxyBinding) - .toggleStyle(.switch) - Spacer(minLength: 0) - Text(summary.systemProxyStateLabel) - .font(.callout.weight(.medium)) - .foregroundStyle(.secondary) - .lineLimit(1) - } - Text(systemProxyHint) + .toggleStyle(.switch) + Text(summary.status) + .font(.body.weight(.medium)) + .foregroundStyle(.secondary) + .lineLimit(1) + if let detail = summary.detail { + Text(detail) .font(.caption) - .foregroundStyle(.secondary) + .foregroundStyle(.orange) + .fixedSize(horizontal: false, vertical: true) + } + } + Divider() + VStack(alignment: .leading, spacing: 6) { + Toggle(isOn: systemProxyBinding) { + Text("设置系统代理") + .font(.title3) + .frame(maxWidth: .infinity, alignment: .leading) + } + .toggleStyle(.switch) + Text(summary.systemProxyStateLabel) + .font(.body.weight(.medium)) + .foregroundStyle(.secondary) + .lineLimit(1) + Text(systemProxyHint) + .font(.caption) + .foregroundStyle(.secondary) + .fixedSize(horizontal: false, vertical: true) + if systemProxyApprovalNeeded { + Button("在登录项中批准…") { + Task { await control.openSystemProxyHelperApproval() } + } + .controlSize(.small) + } + SystemProxyDifferenceView(control: control) + if let systemProxyDetail = summary.systemProxyDetail, + control.snapshot.systemProxyApplication != .paused + { + + Text(systemProxyDetail) + .font(.caption) + .foregroundStyle(.orange) .fixedSize(horizontal: false, vertical: true) - if systemProxyApprovalNeeded { - Button("在登录项中批准…") { - Task { await control.openSystemProxyHelperApproval() } - } - .controlSize(.small) - } - SystemProxyDifferenceView(control: control) - if let systemProxyDetail = summary.systemProxyDetail, - control.snapshot.systemProxyApplication != .paused - { - - Text(systemProxyDetail) - .font(.caption) - .foregroundStyle(.orange) - .fixedSize(horizontal: false, vertical: true) - } } } - .padding(.top, 6) }) } diff --git a/ShadowsocksX-NG2/App/UI/Home/TerminalProxyEnvironmentCard.swift b/ShadowsocksX-NG2/App/UI/Home/TerminalProxyEnvironmentCard.swift index e68d45fe..fbdf7b78 100644 --- a/ShadowsocksX-NG2/App/UI/Home/TerminalProxyEnvironmentCard.swift +++ b/ShadowsocksX-NG2/App/UI/Home/TerminalProxyEnvironmentCard.swift @@ -93,14 +93,14 @@ struct TerminalProxyEnvironmentCard: View { Image(systemName: isCopied ? "checkmark" : "doc.on.doc") .foregroundStyle(isCopied ? Color.green : Color.accentColor) Text(isCopied ? String(localized: "已复制") : shell.title) - .font(.callout.weight(.medium)) + .font(.body.weight(.medium).monospaced()) .foregroundStyle(.primary) .lineLimit(1) Spacer(minLength: 0) } .padding(.horizontal, 12) .padding(.vertical, 10) - .frame(maxWidth: .infinity, alignment: .leading) + .frame(maxWidth: .infinity, minHeight: 40, alignment: .leading) .contentShape(Rectangle()) } .buttonStyle(.plain)