Skip to content

Commit 82df5e7

Browse files
p-linnaneclaude
andauthored
refactor(ui): group identical kernel entries into single cards (#294)
After removing scanner-side kernel deduplication (#292), IPSWs with multiple kernelcaches sharing the same chip, arch, and versions (e.g. early macOS 11 DTK builds with `j273` and `t485`) show as duplicate cards. Group these in the view layer instead, displaying individual filenames as a secondary detail when multiple kernelcaches are collapsed. Signed-off-by: Patrick Linnane <patrick@linnane.io> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent baaa19b commit 82df5e7

1 file changed

Lines changed: 94 additions & 11 deletions

File tree

macOSdbApp/Views/ReleaseDetailView.swift

Lines changed: 94 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -148,21 +148,21 @@ struct ReleaseDetailView: View {
148148

149149
@ViewBuilder
150150
private func kernelSection(_ release: Release) -> some View {
151+
let grouped = groupKernels(release.kernels).sorted { lhs, rhs in
152+
let lhsOrder = lhs.chipFamily?.series.sortOrder ?? -1
153+
let rhsOrder = rhs.chipFamily?.series.sortOrder ?? -1
154+
if lhsOrder != rhsOrder { return lhsOrder > rhsOrder }
155+
let lhsTier = lhs.chipFamily?.tier ?? .base
156+
let rhsTier = rhs.chipFamily?.tier ?? .base
157+
return lhsTier < rhsTier
158+
}
159+
151160
VStack(alignment: .leading, spacing: 8) {
152161
Text("Kernel")
153162
.font(.title2)
154163
.fontWeight(.semibold)
155164

156-
ForEach(release.kernels.sorted { lhs, rhs in
157-
let lhsChip = lhs.chipFamily
158-
let rhsChip = rhs.chipFamily
159-
let lhsOrder = lhsChip?.series.sortOrder ?? -1
160-
let rhsOrder = rhsChip?.series.sortOrder ?? -1
161-
if lhsOrder != rhsOrder { return lhsOrder > rhsOrder }
162-
let lhsTier = lhsChip?.tier ?? .base
163-
let rhsTier = rhsChip?.tier ?? .base
164-
return lhsTier < rhsTier
165-
}) { kernel in
165+
ForEach(grouped) { kernel in
166166
KernelCard(kernel: kernel)
167167
}
168168
}
@@ -191,10 +191,88 @@ struct ReleaseDetailView: View {
191191
}
192192
}
193193

194+
// MARK: - Kernel Grouping
195+
196+
private struct GroupedKernel: Identifiable {
197+
var id: String { "\(chip)-\(arch)-\(darwinVersion)-\(xnuVersion ?? "")" }
198+
199+
let chip: String
200+
let darwinVersion: String
201+
let xnuVersion: String?
202+
let arch: String
203+
let files: [String]
204+
let devices: [String]
205+
let deviceChips: [DeviceChip]?
206+
let isDevelopment: Bool
207+
208+
var chipFamily: ChipFamily? { ChipFamily.from(chipName: chip) }
209+
210+
var sortedChipNames: [String] {
211+
guard let deviceChips, !deviceChips.isEmpty else { return [chip] }
212+
let families = deviceChips.compactMap { ChipFamily.from(chipName: $0.chip) }
213+
guard !families.isEmpty else { return [chip] }
214+
let unique = Dictionary(grouping: families, by: { $0.displayName }).values.compactMap(\.first)
215+
return unique
216+
.sorted { lhs, rhs in
217+
if lhs.series.sortOrder != rhs.series.sortOrder {
218+
return lhs.series.sortOrder > rhs.series.sortOrder
219+
}
220+
return lhs.tier < rhs.tier
221+
}
222+
.map { $0.displayName }
223+
}
224+
}
225+
226+
private func groupKernels(_ kernels: [KernelInfo]) -> [GroupedKernel] {
227+
var groups: [String: GroupedKernel] = [:]
228+
var order: [String] = []
229+
230+
for kernel in kernels {
231+
let key = "\(kernel.chip)-\(kernel.arch)-\(kernel.darwinVersion)-\(kernel.xnuVersion ?? "")"
232+
if var existing = groups[key] {
233+
var files = existing.files
234+
files.append(kernel.file)
235+
var devices = existing.devices
236+
for device in kernel.devices where !devices.contains(device) {
237+
devices.append(device)
238+
}
239+
var deviceChips = existing.deviceChips ?? []
240+
for dc in kernel.deviceChips ?? [] where !deviceChips.contains(dc) {
241+
deviceChips.append(dc)
242+
}
243+
existing = GroupedKernel(
244+
chip: existing.chip,
245+
darwinVersion: existing.darwinVersion,
246+
xnuVersion: existing.xnuVersion,
247+
arch: existing.arch,
248+
files: files,
249+
devices: devices,
250+
deviceChips: deviceChips.isEmpty ? nil : deviceChips,
251+
isDevelopment: existing.isDevelopment || kernel.isDevelopment
252+
)
253+
groups[key] = existing
254+
} else {
255+
order.append(key)
256+
groups[key] = GroupedKernel(
257+
chip: kernel.chip,
258+
darwinVersion: kernel.darwinVersion,
259+
xnuVersion: kernel.xnuVersion,
260+
arch: kernel.arch,
261+
files: [kernel.file],
262+
devices: kernel.devices,
263+
deviceChips: kernel.deviceChips,
264+
isDevelopment: kernel.isDevelopment
265+
)
266+
}
267+
}
268+
269+
return order.compactMap { groups[$0] }
270+
}
271+
194272
// MARK: - Kernel Card
195273

196274
private struct KernelCard: View {
197-
let kernel: KernelInfo
275+
let kernel: GroupedKernel
198276

199277
var body: some View {
200278
HStack(alignment: .top, spacing: 16) {
@@ -216,6 +294,11 @@ private struct KernelCard: View {
216294
.font(.callout)
217295
.foregroundStyle(.secondary)
218296
}
297+
if kernel.files.count > 1 {
298+
Text(kernel.files.joined(separator: ", "))
299+
.font(.caption2)
300+
.foregroundStyle(.tertiary)
301+
}
219302
}
220303

221304
Spacer()

0 commit comments

Comments
 (0)