IP 纯净度标题行重新排版:置信度改为浅色小字,完整报告、刷新、收起并成一组按钮
- 置信度不再是带框徽章,改为标题旁的 12pt 浅灰文字,百分比按高低着色(confidenceTone → confidenceColor) - “查看完整报告 / 完整报告”文字链接与 ReportLink、ReportStyle、ViewThatFits 三档标题行一并去掉,改为外链图标 - 新增 HeaderActionGroup:一组小图标按钮在 macOS 26 上合成一颗玻璃胶囊,更早系统为浅灰胶囊;组内的 MiniIconButton 不再各自带玻璃 - 译文与更新日志同步
This commit is contained in:
1 parent
4099ec636e
commit
84542374bc
7 files changed
+59
-69
No files matched your search
@@ -84,6 +84,7 @@ VPN / 代理 VPN / Proxy
|
||||
VPN 隧道 VPN Tunnel
|
||||
Xcode 归档 Xcode Archives
|
||||
Xcode 编译缓存 Xcode Build Cache
|
||||
cleanip.io 对这次评分的把握:各数据源结论越一致越高 How sure cleanip.io is about this score: the more its sources agree, the higher
|
||||
macOS 系统目录(系统组件) macOS system folder (system component)
|
||||
npm 缓存 npm Cache
|
||||
{} {} 英寸 {} {}-inch
|
||||
@@ -394,7 +395,6 @@ npm 缓存 npm Cache
|
||||
安装失败:{} Install failed: {}
|
||||
安装辅助工具 Install Helper
|
||||
安静 Quiet
|
||||
完整报告 Full report
|
||||
定时 ping 一个地址,记录网络是否通畅 Pings an address regularly to record whether the network is reachable
|
||||
定时探测网络 Connectivity Probe
|
||||
家目录 Home folder
|
||||
@@ -642,7 +642,6 @@ npm 缓存 npm Cache
|
||||
查看 View
|
||||
查看全部进程 All Processes
|
||||
查看包含的项目 Show items
|
||||
查看完整报告 View full report
|
||||
查看完整更新日志 Full Changelog
|
||||
查看清理日志 View Cleanup Log
|
||||
查询中… Looking up…
|
||||
@@ -871,7 +870,7 @@ npm 缓存 npm Cache
|
||||
网络:{} Network: {}
|
||||
网页数据 Web Data
|
||||
网页缓存与脚本缓存,不涉及 Cookie、历史记录和密码 Web and script caches; cookies, history and passwords are untouched
|
||||
置信度 {}% Confidence {}%
|
||||
置信度 Confidence
|
||||
联动 Wired
|
||||
能效核 Efficiency
|
||||
腾讯 DNSPod Tencent
|
||||
|
||||
@@ -336,9 +336,6 @@ private struct PuritySection: View {
|
||||
@Environment(AppModel.self) private var model
|
||||
@Environment(\.isPopover) private var isPopover
|
||||
|
||||
/// 标题行里“查看完整报告”链接的三种长度
|
||||
enum ReportStyle { case full, short, icon }
|
||||
|
||||
var body: some View {
|
||||
// 菜单栏弹窗里默认收起成一行,只显示分数与等级
|
||||
if isPopover, !model.settings.isExpanded(.networkPurity) {
|
||||
@@ -369,12 +366,7 @@ private struct PuritySection: View {
|
||||
let hint = tr("纯净度看信誉、来路、邻居与网络类型四项;机房 IP 常见信誉高、来路和类型偏低。数据来自 cleanip.io")
|
||||
|
||||
Card(padding: DS.Space.s3, spacing: DS.Space.s2) {
|
||||
// 标题、地址族徽章、置信度、报告链接、刷新按钮排成一行;宽度不够时报告链接依次缩成“完整报告”、只剩图标
|
||||
ViewThatFits(in: .horizontal) {
|
||||
header(addresses, report: .full)
|
||||
header(addresses, report: .short)
|
||||
header(addresses, report: .icon)
|
||||
}
|
||||
header(addresses)
|
||||
if let purity = addresses?.purity {
|
||||
// 分数在左、cleanip.io 字标在右,色带在下占满整行
|
||||
HStack(spacing: DS.Space.s2) {
|
||||
@@ -420,44 +412,54 @@ private struct PuritySection: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// 标题行:IP 纯净度 · [IPv4] · [置信度 92%] · 查看完整报告 ↗ ……… ⟳
|
||||
private func header(_ addresses: PublicAddresses?, report: ReportStyle) -> some View {
|
||||
/// 标题行:IP 纯净度 [IPv4] 置信度 92% ……… [↗ ⟳ ⌃]
|
||||
/// 置信度是标题旁的一行浅色小字,不再用带框徽章;右侧的完整报告、刷新、收起并成一组按钮
|
||||
private func header(_ addresses: PublicAddresses?) -> some View {
|
||||
let network = model.network
|
||||
// 320 宽的弹窗里这一行很挤:标题与徽章之间只留最小间距,右侧刷新按钮自带留白
|
||||
return HStack(spacing: DS.Space.s1) {
|
||||
return HStack(spacing: DS.Space.s2) {
|
||||
Text(PopoverSection.networkPurity.title)
|
||||
.dsFont(.xs, weight: .semibold)
|
||||
.foregroundStyle(DS.Palette.textSecondary)
|
||||
.lineLimit(1)
|
||||
.fixedSize()
|
||||
HStack(spacing: DS.Space.s1) {
|
||||
if let family = network.shownFamily {
|
||||
TagBadge(text: family.title, tone: .primary, compact: true)
|
||||
}
|
||||
if let confidence = addresses?.purity?.confidence {
|
||||
TagBadge(text: tr("置信度 \(confidence)%"), tone: Self.confidenceTone(confidence), compact: true)
|
||||
}
|
||||
if let family = network.shownFamily {
|
||||
TagBadge(text: family.title, tone: .primary, compact: true)
|
||||
}
|
||||
if let url = addresses?.reportURL {
|
||||
ReportLink(url: url, style: report).padding(.leading, DS.Space.s1)
|
||||
if let confidence = addresses?.purity?.confidence {
|
||||
HStack(spacing: DS.Space.s1 / 2) {
|
||||
Text(tr("置信度")).foregroundStyle(DS.Palette.textTertiary)
|
||||
Text(verbatim: "\(confidence)%")
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(Self.confidenceColor(confidence))
|
||||
.monospacedDigit()
|
||||
}
|
||||
.dsFont(.xs)
|
||||
.lineLimit(1)
|
||||
.fixedSize()
|
||||
.help(tr("cleanip.io 对这次评分的把握:各数据源结论越一致越高"))
|
||||
}
|
||||
Spacer(minLength: 0)
|
||||
if isPopover {
|
||||
HeaderActionGroup {
|
||||
if let url = addresses?.reportURL {
|
||||
MiniIconButton(systemName: "arrow.up.forward", help: tr("在 cleanip.io 查看这个 IP 的完整报告")) {
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
RefreshButton(loading: network.isLookingUpPublic, help: tr("强制刷新:忽略缓存,立即重新查询公网 IP 与归属地")) {
|
||||
network.lookUpPublicAddresses(force: true)
|
||||
}
|
||||
.collapseButton(.networkPurity, settings: model.settings)
|
||||
} else {
|
||||
RefreshButton(loading: network.isLookingUpPublic, help: tr("强制刷新:忽略缓存,立即重新查询公网 IP 与归属地")) {
|
||||
network.lookUpPublicAddresses(force: true)
|
||||
if isPopover {
|
||||
MiniIconButton(systemName: "chevron.up", help: tr("收起")) {
|
||||
withAnimation(DS.Motion.quick) { model.settings.setExpanded(.networkPurity, false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 置信度高的绿、中等的灰、低的黄
|
||||
static func confidenceTone(_ confidence: Int) -> TagBadge.Tone {
|
||||
confidence >= 80 ? .success : confidence >= 50 ? .neutral : .warning
|
||||
static func confidenceColor(_ confidence: Int) -> Color {
|
||||
confidence >= 80 ? DS.Palette.success : confidence >= 50 ? DS.Palette.textSecondary : DS.Palette.warning
|
||||
}
|
||||
|
||||
static func riskLabel(_ raw: String) -> String {
|
||||
@@ -652,33 +654,3 @@ private struct NetworkProcessesSection: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 纯净度标题行里的“查看完整报告”链接;`icon` 只剩一个外链图标
|
||||
private struct ReportLink: View {
|
||||
let url: URL
|
||||
let style: PuritySection.ReportStyle
|
||||
@State private var hovering = false
|
||||
|
||||
var body: some View {
|
||||
let help = tr("在 cleanip.io 查看这个 IP 的完整报告")
|
||||
if style == .icon {
|
||||
MiniIconButton(systemName: "arrow.up.forward.square", help: help) { NSWorkspace.shared.open(url) }
|
||||
} else {
|
||||
Button { NSWorkspace.shared.open(url) } label: {
|
||||
HStack(spacing: DS.Space.s1 / 2) {
|
||||
Text(style == .full ? tr("查看完整报告") : tr("完整报告"))
|
||||
.dsFont(.xs, weight: .medium)
|
||||
Image(systemName: "arrow.up.forward.square")
|
||||
.font(.system(size: DS.TextSize.xs.rawValue, weight: .semibold))
|
||||
}
|
||||
.foregroundStyle(hovering ? DS.Palette.primaryHover : DS.Palette.primary)
|
||||
.lineLimit(1)
|
||||
.fixedSize()
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.onHover { hovering = $0 }
|
||||
.help(help)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,12 +246,13 @@ struct MiniIconButton: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// macOS 26 上是一颗小玻璃圆钮,更早的系统只有悬停底色
|
||||
/// macOS 26 上是一颗小玻璃圆钮,更早的系统、或已经在一组玻璃按钮里时只有悬停底色
|
||||
private struct MiniIconSurface: ViewModifier {
|
||||
let hovering: Bool
|
||||
@Environment(\.isInsideGlass) private var isInsideGlass
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
if DS.Glass.isAvailable {
|
||||
if DS.Glass.isAvailable, !isInsideGlass {
|
||||
content.dsGlass(in: Circle(), interactive: true)
|
||||
} else {
|
||||
content.background(hovering ? DS.Palette.surfaceHover : .clear, in: RoundedRectangle(cornerRadius: DS.Radius.sm))
|
||||
@@ -259,6 +260,21 @@ private struct MiniIconSurface: ViewModifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// 区块标题栏右侧的一组小图标按钮:macOS 26 上合成一颗玻璃胶囊(与访达工具栏的按钮分组一致),
|
||||
/// 里面的按钮不再各自带玻璃;更早的系统是一条浅灰胶囊
|
||||
struct HeaderActionGroup<Content: View>: View {
|
||||
@ViewBuilder var content: Content
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
content
|
||||
}
|
||||
.padding(.horizontal, DS.Space.s1 / 2)
|
||||
.environment(\.isInsideGlass, true)
|
||||
.dsGlass(in: Capsule(), fallback: DS.Palette.track)
|
||||
}
|
||||
}
|
||||
|
||||
/// 区块标题栏里的刷新按钮:查询进行中换成系统的转圈,查完自动变回图标
|
||||
struct RefreshButton: View {
|
||||
var loading: Bool
|
||||
|
||||
Reference in new issue
Block a user