release(ios): 0.2.2 构建 8 中性化批量标签禁用态并去蓝化图标底色

- FleetTagBatchSheet:无勾选时标签胶囊不再走 Button 禁用态(系统会压成灰块,像加载
  失败),改为中性标签原样渲染;覆盖度文案留空,图标改 tag;新建标签输入与按钮置灰
  并补一句「勾选节点后即可新建标签并批量贴上」。
- 应用图标:底色与插槽从偏青绿的石墨(R>G=B,亮壁纸上读作蓝)改为严格等值中性灰
  20/19/10,金色跨度拉大(#FADD98 -> #C78D2F)去掉芥末黄塑料感;AppIcon.svg 同步。
- 版本号:marketing 0.2.2 不带括号,构建号 7 -> 8;文档里 0.2.x (N) 一律改写为
  「0.2.x 构建 N」,README 与现行说明同步。
This commit is contained in:
chick
2026-09-15 05:07:03 +08:00
parent 36ce791215
commit 9ad0c46088
11 changed files with 120 additions and 63 deletions
@@ -2,5 +2,5 @@ public enum AppMetadata {
public static let name = "MultiSimAdmin"
public static let bundleIdentifier = "fun.chick.multi-simadmin"
public static let marketingVersion = "0.2.2"
public static let buildVersion = "7"
public static let buildVersion = "8"
}
@@ -102,10 +102,16 @@ struct FleetTagBatchSheet: View {
.accessibilityLabel("新标签名称")
.submitLabel(.done)
.onSubmit { submitDraft() }
.disabled(isBusy)
.disabled(isBusy || targets.isEmpty)
Button(isBusy ? "处理中" : "添加") { submitDraft() }
.buttonStyle(AIButtonStyle(kind: .primary, size: .regular, fixedWidth: 84))
.disabled(draft.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || isBusy)
.disabled(draft.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || isBusy || targets.isEmpty)
}
// 没有勾选节点时这个表单按下去只会清空输入,先说清楚为什么不能动。
if targets.isEmpty {
Text("勾选节点后即可新建标签并批量贴上。")
.font(.caption2)
.foregroundStyle(AITheme.faint)
}
}
}
@@ -135,44 +141,87 @@ struct FleetTagBatchSheet: View {
private var isComplete: Bool { total > 0 && covered == total }
private var isPartial: Bool { covered > 0 && covered < total }
// 没有勾选任何节点时这一整片都是不可操作状态,此时不该用「未贴」这种带暗示的
// 灰字,直接按中性标签渲染,避免看起来像加载失败的禁用控件。
private var isInert: Bool { total == 0 }
private var stateText: String {
if isInert { return "" }
if isComplete { return "全部" }
if isPartial { return "\(covered)/\(total)" }
return "未贴"
}
var body: some View {
Button(action: action) {
HStack(spacing: 6) {
Image(systemName: isComplete ? "checkmark.circle.fill" : (isPartial ? "circle.lefthalf.filled" : "circle"))
.font(.system(size: 12, weight: .semibold))
.accessibilityHidden(true)
Text(title)
.font(.footnote.weight(isComplete || isPartial ? .semibold : .medium))
.lineLimit(1)
.truncationMode(.middle)
if isInert {
// 不可操作时不渲染 Button:系统禁用态会把整枚胶囊压成灰色,
// 看起来像加载失败,而标签本身是需要读清楚的内容。
label
.accessibilityLabel("标签 \(title),勾选节点后可贴上")
} else {
Button(action: action) { label }
.buttonStyle(.plain)
.disabled(isBusy)
.accessibilityLabel(isComplete ? "从已选节点移除标签 \(title)" : "给已选节点贴上标签 \(title)")
.accessibilityAddTraits(isComplete ? [.isButton, .isSelected] : .isButton)
}
}
private var label: some View {
HStack(spacing: 6) {
Image(systemName: iconName)
.font(.system(size: 12, weight: .semibold))
.accessibilityHidden(true)
Text(title)
.font(.footnote.weight(isComplete || isPartial ? .semibold : .medium))
.lineLimit(1)
.truncationMode(.middle)
if stateText.isEmpty == false {
Text(stateText)
.font(.caption2.weight(.semibold))
.monospacedDigit()
.opacity(0.72)
Spacer(minLength: 0)
}
.padding(.horizontal, 10)
.frame(height: 38)
.foregroundStyle(isComplete ? AITheme.onPrimary : (isPartial ? AITheme.ink : AITheme.muted))
.background(isComplete ? AITheme.primary : (isPartial ? AITheme.tile : AITheme.surface))
.clipShape(Capsule(style: .continuous))
.overlay {
Capsule(style: .continuous)
.strokeBorder(isComplete ? AITheme.primary : (isPartial ? AITheme.primary.opacity(0.42) : AITheme.line))
}
.contentShape(Capsule(style: .continuous))
Spacer(minLength: 0)
}
.buttonStyle(.plain)
.disabled(isBusy || total == 0)
.accessibilityLabel(isComplete ? "从已选节点移除标签 \(title)" : "给已选节点贴上标签 \(title)")
.accessibilityAddTraits(isComplete ? [.isButton, .isSelected] : .isButton)
.padding(.horizontal, 10)
.frame(height: 38)
.foregroundStyle(foreground)
.background(background)
.clipShape(Capsule(style: .continuous))
.overlay {
Capsule(style: .continuous)
.strokeBorder(border)
}
.contentShape(Capsule(style: .continuous))
}
private var iconName: String {
if isInert { return "tag" }
if isComplete { return "checkmark.circle.fill" }
if isPartial { return "circle.lefthalf.filled" }
return "circle"
}
private var foreground: Color {
if isInert { return AITheme.ink }
if isComplete { return AITheme.onPrimary }
if isPartial { return AITheme.ink }
return AITheme.muted
}
private var background: Color {
if isInert { return AITheme.tile }
if isComplete { return AITheme.primary }
if isPartial { return AITheme.tile }
return AITheme.surface
}
private var border: Color {
if isInert { return AITheme.tileLine }
if isComplete { return AITheme.primary }
if isPartial { return AITheme.primary.opacity(0.42) }
return AITheme.line
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 936 KiB

After

Width:  |  Height:  |  Size: 812 KiB

@@ -10,7 +10,7 @@
<key>CFBundleName</key><string>MultiSimAdmin</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleShortVersionString</key><string>0.2.2</string>
<key>CFBundleVersion</key><string>7</string>
<key>CFBundleVersion</key><string>8</string>
<key>LSRequiresIPhoneOS</key><true/>
<key>MinimumOSVersion</key><string>16.0</string>
<key>NSAppTransportSecurity</key>