Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Squirrel.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@
CODE_SIGN_ENTITLEMENTS = resources/Squirrel.entitlements;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1.1.1;
CURRENT_PROJECT_VERSION = 1.1.2;
DEAD_CODE_STRIPPING = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -722,7 +722,7 @@
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = resources/Squirrel.entitlements;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1.1.1;
CURRENT_PROJECT_VERSION = 1.1.2;
DEAD_CODE_STRIPPING = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
Expand Down
31 changes: 31 additions & 0 deletions appcast.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
TriFecta 的 Sparkle 更新源(appcast)。
注意:
- 本项目已关闭 Sparkle 自动检查(SUEnableAutomaticChecks=false),
因此正常运行时不会自动拉取本文件;更新走「设置 → 关于 → 检查 TriFecta 更新」。
- 若要启用 Sparkle 自动更新,需为每个 Release 生成 EdDSA 签名(sparkle:edSignature),
并将本文件放在可公网访问的位置(如 GitHub Pages 或本仓库 raw 地址)。
- 本文件当前作为 TriFecta 更新源的占位/参考,指向 thesadbee/TriFecta 的 Release。
-->
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>TriFecta 更新</title>
<link>https://github.com/thesadbee/TriFecta/releases</link>
<description>TriFecta(基于 Rime/Squirrel 的 macOS 中文输入法)更新源</description>
<item>
<title>TriFecta v1.1.1</title>
<sparkle:version>1.1.1</sparkle:version>
<sparkle:shortVersionString>1.1.1</sparkle:shortVersionString>
<sparkle:releaseNotesLink>https://github.com/thesadbee/TriFecta/releases/tag/v1.1.1</sparkle:releaseNotesLink>
<pubDate>Fri, 28 Aug 2026 03:13:18 +0000</pubDate>
<!-- sparkle:edSignature 需由发布流水线用 TriFecta 的 Sparkle EdDSA 私钥生成 -->
<enclosure url="https://github.com/thesadbee/TriFecta/releases/download/v1.1.1/TriFecta.pkg"
sparkle:version="1.1.1"
sparkle:shortVersionString="1.1.1"
length="17837706"
type="application/octet-stream" />
</item>
</channel>
</rss>
4 changes: 2 additions & 2 deletions resources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>SUEnableAutomaticChecks</key>
<true/>
<false/>
<key>SUFeedURL</key>
<string>https://rime.github.io/release/squirrel/appcast.xml</string>
<string>https://raw.githubusercontent.com/thesadbee/TriFecta/main/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>ukvWq2dKOWn3B9AsdsQIwOptiDdDKdUjAVNgFxSvB2o=</string>
<key>TICapsLockLanguageSwitchCapable</key>
Expand Down
137 changes: 127 additions & 10 deletions settings/Sources/TriFectaSettings/Pages/AboutPage.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
//
// 关于:版本信息、GitHub 链接、检查更新。
// 关于:版本信息、GitHub 链接、更新检查。
// 更新分为两块,避免混淆:
// - Squirrel 更新:来自上游 rime/Squirrel 仓库(引擎本体),与 TriFecta 版本无关;
// - TriFecta 更新:来自 thesadbee/TriFecta 仓库(项目自身的发布版本)。
//
import SwiftUI
import AppKit

struct AboutPage: View {
@EnvironmentObject private var state: AppState
@Environment(\.appTheme) private var theme
@StateObject private var updater = AboutUpdateModel()

private enum Links {
static let repo = "https://github.com/thesadbee/TriFecta"
static let releases = "https://github.com/thesadbee/TriFecta/releases"
static let squirrelReleases = "https://github.com/rime/squirrel/releases"
static let squirrelFeed = "https://rime.github.io/release/squirrel/appcast.xml"
}

private var imeVersion: String {
let plist = NSDictionary(contentsOf: state.repo.paths.imeInfoPlist) as? [String: Any]
let short = plist?["CFBundleShortVersionString"] as? String ?? "—"
let short = plist?["CFBundleShortVersionString"] as? String
let build = plist?["CFBundleVersion"] as? String ?? "—"
return "\(short) (\(build))"
if let s = short, !s.isEmpty { return "\(s) (\(build))" }
return build
}

/// TriFecta 当前版本(对应发布 tag 的 v 前缀形式)
private var trifectaCurrent: String { "v" + imeVersion }

private var settingsVersion: String {
let short = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "dev"
return short
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "dev"
}

private func open(_ url: String) {
Expand All @@ -31,6 +40,21 @@ struct AboutPage: View {
}
}

// 上游 Squirrel 版本行:当前 → 最新
private var squirrelLine: String {
let latest = updater.squirrelLatest ?? "获取中…"
return "当前 \(imeVersion) → 上游最新 \(latest)"
}

// TriFecta 版本行:当前 → 最新(含“有新版本”提示)
private var trifectaLine: String {
if let lt = updater.trifectaLatest {
let hasNew = AboutUpdateModel.isNewer(current: trifectaCurrent, latest: lt)
return "当前 \(trifectaCurrent) → 最新 \(lt)\(hasNew ? "(有新版本)" : "")"
}
return "当前 \(trifectaCurrent) → 最新 获取中…"
}

var body: some View {
PageScroll(title: "关于", footer: "TriFecta:基于 Rime/Squirrel 的 macOS 中文输入法(GPL-3.0)") {
SettingCard {
Expand All @@ -47,17 +71,110 @@ struct AboutPage: View {
}
.frame(maxWidth: .infinity)
.padding(.vertical, 24)
Divider()
}

SettingCard {
// —— 上游 Squirrel 引擎更新(与 TriFecta 版本无关)——
SettingRow("Squirrel 更新(上游)",
subtitle: "上游 rime / 鼠鬚管 引擎版本,非 TriFecta 版本更新",
icon: "arrow.triangle.2.circlepath",
divider: false) {
VStack(alignment: .trailing, spacing: 4) {
Text(squirrelLine)
.font(.system(size: 11))
.foregroundColor(.secondary)
Button("打开上游 Releases") { open(Links.squirrelReleases) }
}
}
}

SettingCard {
// —— TriFecta 项目自身更新 ——
SettingRow("TriFecta 更新",
subtitle: "来自 thesadbee/TriFecta 仓库的项目版本",
icon: "arrow.triangle.2.circlepath",
divider: false) {
VStack(alignment: .trailing, spacing: 4) {
Text(trifectaLine)
.font(.system(size: 11))
.foregroundColor(.secondary)
Button(updater.loading ? "检查中…" : "检查 TriFecta 更新") { updater.refresh() }
}
}
}

SettingCard {
SettingRow("GitHub 仓库", icon: "arrow.up.right.square") {
Button("打开") { open(Links.repo) }
}
SettingRow("Rime Wiki(上游文档)", icon: "book") {
SettingRow("Rime Wiki(上游文档)", icon: "book", divider: false) {
Button("打开") { open("https://github.com/rime/home/wiki") }
}
SettingRow("检查更新", icon: "arrow.triangle.2.circlepath", divider: false) {
Button("查看 Releases") { open(Links.releases) }
}
}
}
.task { updater.refresh() }
}
}

/// 拉取两个仓库的最新 release 版本号(tag_name)。
@MainActor
final class AboutUpdateModel: ObservableObject {
@Published var squirrelLatest: String?
@Published var trifectaLatest: String?
@Published var loading = false
@Published var error: String?

func refresh() {
loading = true
let group = DispatchGroup()

var s: String?, t: String?, e: String?

group.enter()
fetchLatest("https://api.github.com/repos/rime/squirrel/releases/latest") { tag, err in
s = tag; if err != nil { e = e ?? err }; group.leave()
}

group.enter()
fetchLatest("https://api.github.com/repos/thesadbee/TriFecta/releases/latest") { tag, err in
t = tag; if err != nil { e = e ?? err }; group.leave()
}

group.notify(queue: .main) {
self.squirrelLatest = s
self.trifectaLatest = t
self.error = e
self.loading = false
}
}

private func fetchLatest(_ urlString: String, _ completion: @escaping (String?, String?) -> Void) {
guard let url = URL(string: urlString) else { completion(nil, "invalid url"); return }
var req = URLRequest(url: url)
req.setValue("application/vnd.github+json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: req) { data, resp, err in
if let err = err { completion(nil, err.localizedDescription); return }
guard let data = data,
let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let tag = obj["tag_name"] as? String else {
completion(nil, "no tag_name"); return
}
completion(tag, nil)
}.resume()
}

/// 轻量版本比较("v1.1.1" 式):latest 是否比 current 更新
static func isNewer(current: String, latest: String) -> Bool {
let c = current.lowercased().replacingOccurrences(of: "v", with: "")
let l = latest.lowercased().replacingOccurrences(of: "v", with: "")
let cp = c.split(separator: ".").compactMap { Int($0) }
let lp = l.split(separator: ".").compactMap { Int($0) }
let n = max(cp.count, lp.count)
for i in 0..<n {
let a = i < cp.count ? cp[i] : 0
let b = i < lp.count ? lp[i] : 0
if b != a { return b > a }
}
return false
}
}
19 changes: 19 additions & 0 deletions settings/Sources/TriFectaSettings/Pages/AppearancePage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,25 @@ struct AppearancePage: View {
}
}

SettingCard {
SettingRow("候选框液态玻璃",
subtitle: "左=完全液态玻璃,右=完全不透明(微微发白保证对比)",
icon: "circle.lefthalf.filled",
divider: false) {
HStack(spacing: 8) {
Image(systemName: "circle.lefthalf.filled")
.font(.system(size: 12))
.foregroundColor(.secondary)
Slider(value: $state.style.glassOpacity, in: 0...1)
.frame(width: 150)
Image(systemName: "circle.fill")
.font(.system(size: 12))
.foregroundColor(.secondary)
}
.frame(width: 200)
}
}

SettingCard {
SettingRow("三色分组配色",
subtitle: "候选多时按 ~ 键分组选字(红/黄/绿)") {
Expand Down
11 changes: 9 additions & 2 deletions settings/Sources/TriFectaSettingsCore/EffectiveModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,20 @@ public struct StyleValues: Equatable {
public var fontFace: String
public var fontPoint: Double
public var candidateFormat: String
/// 候选框液态玻璃程度:0=完全液态玻璃(透明底、露玻璃模糊),1=完全不透明(微微发白)。
/// 连续无极取值,写入 style/glass_opacity。
public var glassOpacity: Double

public init(colorScheme: String, candidateListLayout: String, textOrientation: String,
fontFace: String, fontPoint: Double, candidateFormat: String) {
fontFace: String, fontPoint: Double, candidateFormat: String,
glassOpacity: Double = 0) {
self.colorScheme = colorScheme
self.candidateListLayout = candidateListLayout
self.textOrientation = textOrientation
self.fontFace = fontFace
self.fontPoint = fontPoint
self.candidateFormat = candidateFormat
self.glassOpacity = glassOpacity
}

/// 与 SharedSupport 基线一致的缺省 UI 值(readStyle 回退与 AppState 初始快照共用)
Expand Down Expand Up @@ -174,9 +179,11 @@ public enum RimeModel {
let fontFace = style?["font_face"]?.string ?? d.fontFace
let fontPoint = style?["font_point"]?.float.map { $0 } ?? style?["font_point"]?.int.map { Double($0) } ?? d.fontPoint
let format = style?["candidate_format"]?.string ?? d.candidateFormat
let glass = style?["glass_opacity"]?.float.map { Double($0) } ?? d.glassOpacity
return StyleValues(colorScheme: schemeID, candidateListLayout: layout,
textOrientation: orientation, fontFace: fontFace,
fontPoint: fontPoint, candidateFormat: format)
fontPoint: fontPoint, candidateFormat: format,
glassOpacity: max(0, min(1, glass)))
}

public static func readColorSchemes(_ node: Node) -> [(id: String, name: String)] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ public final class SettingsRepository {
if cur.candidateFormat != style.candidateFormat {
try editor.setScalar(section: "style", keyText: "candidate_format", value: .string(style.candidateFormat))
}
if cur.glassOpacity != style.glassOpacity {
try editor.setScalar(section: "style", keyText: "glass_opacity", value: .number(formatNumber(style.glassOpacity)))
}
}
if let gc = changes.groupColors {
let cur = RimeModel.readGroupColors(effective)
Expand Down Expand Up @@ -152,6 +155,7 @@ public final class SettingsRepository {
try assertWritten("style/font_face", before: before.fontFace, expected: style.fontFace, after: after.fontFace)
try assertWritten("style/font_point", before: before.fontPoint, expected: style.fontPoint, after: after.fontPoint)
try assertWritten("style/candidate_format", before: before.candidateFormat, expected: style.candidateFormat, after: after.candidateFormat)
try assertWritten("style/glass_opacity", before: before.glassOpacity, expected: style.glassOpacity, after: after.glassOpacity)
}
if let gc = changes.groupColors {
let before = RimeModel.readGroupColors(effective)
Expand Down
22 changes: 22 additions & 0 deletions sources/SquirrelTheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
private(set) var alpha: CGFloat = 1

private(set) var translucency = false
/// 候选框液态玻璃程度(0=完全液态玻璃(透明底、露出玻璃模糊),1=完全不透明)。
/// 由 style/glass_opacity 覆盖;未设置时按 translucency 推导(true→0,false→1)。
private(set) var glassOpacity: CGFloat = 0
private(set) var mutualExclusive = false
private(set) var linear = false
private(set) var vertical = false
Expand Down Expand Up @@ -206,6 +209,18 @@
}
}

/// 候选框面板的底色(不透明端使用):把方案背景朝白色拉近一点,
/// 让「玻璃感变弱」时背景微微发白、保持对比度,而不是纯黑/纯透明。
var panelBackgroundColor: NSColor {
let base = backgroundColor
guard let c = base.usingColorSpace(.sRGB) else { return base }

Check failure on line 216 in sources/SquirrelTheme.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'c' should be between 3 and 40 characters long (identifier_name)

Check failure on line 216 in sources/SquirrelTheme.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'c' should be between 3 and 40 characters long (identifier_name)
let t: CGFloat = 0.15 // 朝白色拉近 15%

Check failure on line 217 in sources/SquirrelTheme.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 't' should be between 3 and 40 characters long (identifier_name)

Check failure on line 217 in sources/SquirrelTheme.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 't' should be between 3 and 40 characters long (identifier_name)
return NSColor(srgbRed: c.redComponent * (1 - t) + t,
green: c.greenComponent * (1 - t) + t,
blue: c.blueComponent * (1 - t) + t,
alpha: c.alphaComponent)
}

func load(config: SquirrelConfig, dark: Bool) {
linear ?= config.getString("style/candidate_list_layout").map { $0 == "linear" }
vertical ?= config.getString("style/text_orientation").map { $0 == "vertical" }
Expand Down Expand Up @@ -304,6 +319,13 @@
self.commentFontSize = commentFontSize
preeditFonts = decodeFonts(from: preeditFontName ?? fontName)
self.preeditFontSize = preeditFontSize

// 液态玻璃程度:默认按 translucency 推导(true→0 全玻璃,false→1 不透明),
// style/glass_opacity 提供连续无极覆盖。
glassOpacity = translucency ? 0 : 1
if let v = config.getDouble("style/glass_opacity") {

Check failure on line 326 in sources/SquirrelTheme.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'v' should be between 3 and 40 characters long (identifier_name)

Check failure on line 326 in sources/SquirrelTheme.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'v' should be between 3 and 40 characters long (identifier_name)
glassOpacity = max(0, min(1, CGFloat(v)))
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions sources/SquirrelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
static let noBreak = NSAttributedString.Key("noBreak")
}

final class SquirrelView: NSView {

Check warning on line 25 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Class body should span 300 lines or less excluding comments and whitespace: currently spans 355 lines (type_body_length)

Check warning on line 25 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Class body should span 300 lines or less excluding comments and whitespace: currently spans 355 lines (type_body_length)
let textView: NSTextView

private let squirrelLayoutDelegate: SquirrelLayoutDelegate
Expand All @@ -43,7 +43,7 @@
var groupColors: [NSColor] = [
NSColor(calibratedRed: 0.94, green: 0.20, blue: 0.16, alpha: 0.68), // 红
NSColor(calibratedRed: 0.95, green: 0.72, blue: 0.00, alpha: 0.68), // 黄
NSColor(calibratedRed: 0.14, green: 0.74, blue: 0.27, alpha: 0.68), // 绿

Check warning on line 46 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Collection literals should not have trailing commas (trailing_comma)

Check warning on line 46 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Collection literals should not have trailing commas (trailing_comma)
]
// 三色分组配色从配置读取:squirrel.yaml 顶层 group_colors(0xAABBGGRR,缺省回退上方硬编码值)
// 注意:设置窗口(TriFectaSettings)采用「只写改动的 key」的增量写入,
Expand All @@ -59,7 +59,7 @@
let defaults = [
NSColor(calibratedRed: 0.94, green: 0.20, blue: 0.16, alpha: 0.68), // 红
NSColor(calibratedRed: 0.95, green: 0.72, blue: 0.00, alpha: 0.68), // 黄
NSColor(calibratedRed: 0.14, green: 0.74, blue: 0.27, alpha: 0.68), // 绿

Check warning on line 62 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Collection literals should not have trailing commas (trailing_comma)

Check warning on line 62 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Collection literals should not have trailing commas (trailing_comma)
]
let red = config.getColor("group_colors/red", inSpace: .sRGB) ?? defaults[0]
let yellow = config.getColor("group_colors/yellow", inSpace: .sRGB) ?? defaults[1]
Expand Down Expand Up @@ -203,14 +203,14 @@
candidateItemPaths = [nil, nil, nil]
let count = candidateRanges.count
let numGroups = min(3, (count + groupSize - 1) / groupSize)
for g in 0..<numGroups {

Check failure on line 206 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'g' should be between 3 and 40 characters long (identifier_name)

Check failure on line 206 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'g' should be between 3 and 40 characters long (identifier_name)
let startIdx = g * groupSize
let endIdx = min(groupSize * (g + 1), count)
guard startIdx < endIdx else { break }
if let selG = selectedGroup, selG == g {
// 选中组:每个候选画成独立胶囊,按组内位置着色
for i in startIdx..<endIdx {
if let cp = drawPath(highlightedRange: candidateRanges[i], backgroundRect: backgroundRect, preeditRect: preeditRect,

Check warning on line 213 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'cp' should be between 3 and 40 characters long (identifier_name)

Check warning on line 213 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'cp' should be between 3 and 40 characters long (identifier_name)
containingRect: containingRect, extraExpansion: theme.surroundingExtraExpansion),
i - startIdx < candidateItemPaths.count {
if candidateItemPaths[i - startIdx] == nil { candidateItemPaths[i - startIdx] = CGMutablePath() }
Expand All @@ -219,11 +219,11 @@
}
} else {
// 未选中组:整组一条胶囊
let r0 = candidateRanges[startIdx]

Check warning on line 222 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'r0' should be between 3 and 40 characters long (identifier_name)

Check warning on line 222 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'r0' should be between 3 and 40 characters long (identifier_name)
let r1 = candidateRanges[endIdx - 1]

Check warning on line 223 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'r1' should be between 3 and 40 characters long (identifier_name)

Check warning on line 223 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'r1' should be between 3 and 40 characters long (identifier_name)
let groupRange = NSRange(location: r0.location, length: (r1.location + r1.length) - r0.location)
if groupRange.length > 0,
let cp = drawPath(highlightedRange: groupRange, backgroundRect: backgroundRect, preeditRect: preeditRect,

Check warning on line 226 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'cp' should be between 3 and 40 characters long (identifier_name)

Check warning on line 226 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'cp' should be between 3 and 40 characters long (identifier_name)
containingRect: containingRect, extraExpansion: theme.surroundingExtraExpansion) {
if candidateGroupPaths[g] == nil { candidateGroupPaths[g] = CGMutablePath() }
candidateGroupPaths[g]?.addPath(cp)
Expand Down Expand Up @@ -291,8 +291,8 @@
}
}
let panelLayer = shapeFromPath(path: backPath)
// 开启 translucency 时背景涂透明,露出底层 NSGlassEffectView 的液态玻璃效果
panelLayer.fillColor = theme.translucency ? NSColor.clear.cgColor : theme.backgroundColor.cgColor
// 连续无极控制:glassOpacity=0 → 全透明(露出液态玻璃),=1 → 不透明(微微发白的底色)
panelLayer.fillColor = theme.panelBackgroundColor.withAlphaComponent(theme.glassOpacity).cgColor
let panelLayerMask = shapeFromPath(path: backgroundPath)
panelLayer.mask = panelLayerMask
self.layer?.addSublayer(panelLayer)
Expand Down Expand Up @@ -325,14 +325,14 @@
if selectedGroup != nil {
// 选中组:其它组完全褪去(不绘制),只保留选中组内候选按位置红/黄/绿,
// 避免变淡后的残留色造成视觉杂乱、对比度不足。
for (idx, ip) in candidateItemPaths.enumerated() {

Check warning on line 328 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'ip' should be between 3 and 40 characters long (identifier_name)

Check warning on line 328 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'ip' should be between 3 and 40 characters long (identifier_name)
guard let ip, idx < groupColors.count else { continue }

Check warning on line 329 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'ip' should be between 3 and 40 characters long (identifier_name)

Check warning on line 329 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'ip' should be between 3 and 40 characters long (identifier_name)
let layer = shapeFromPath(path: ip)
layer.fillColor = groupColors[idx].cgColor
panelLayer.addSublayer(layer)
}
} else {
for (g, path) in candidateGroupPaths.enumerated() {

Check failure on line 335 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'g' should be between 3 and 40 characters long (identifier_name)

Check failure on line 335 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

Variable name 'g' should be between 3 and 40 characters long (identifier_name)
guard let path, g < groupColors.count else { continue }
let layer = shapeFromPath(path: path)
layer.fillColor = groupColors[g].cgColor
Expand Down Expand Up @@ -838,4 +838,4 @@
}
return (layer, downPath, upPath)
}
}

Check warning on line 841 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

File should contain 800 lines or less: currently contains 841 (file_length)

Check warning on line 841 in sources/SquirrelView.swift

View workflow job for this annotation

GitHub Actions / build

File should contain 800 lines or less: currently contains 841 (file_length)
Loading