Flag queues whose driver filters need Rosetta or are missing

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kfattic
2026-09-16 14:23:31 -05:00
parent cf0241beac
commit 366bd74225
12 changed files with 362 additions and 5 deletions

View File

@@ -210,7 +210,8 @@ struct SidebarView: View {
List(selection: $selection) {
Section("Printers") {
ForEach(filtered) { printer in
PrinterRow(printer: printer, isDefault: store.defaultPrinter == printer.name)
PrinterRow(printer: printer, isDefault: store.defaultPrinter == printer.name,
driverWarning: store.driverFilters[printer.name]?.headline)
.tag(printer.name)
.contextMenu { menu(for: printer) }
}
@@ -311,6 +312,8 @@ struct QuickActionItems: View {
struct PrinterRow: View {
let printer: PrinterSummary
var isDefault = false
/// "Driver needs Rosetta" / "Driver filter missing", added to the tooltip.
var driverWarning: String?
var body: some View {
HStack(spacing: 8) {
@@ -339,7 +342,7 @@ struct PrinterRow: View {
}
}
.badge(printer.jobCount)
.help(printer.stateSummary)
.help(driverWarning.map { "\(printer.stateSummary) · \($0)" } ?? printer.stateSummary)
.accessibilityElement(children: .combine)
.accessibilityValue(printer.stateSummary)
}

View File

@@ -37,6 +37,8 @@ enum JobFilter: String, CaseIterable, Identifiable {
final class PrinterDetailModel {
let queue: String
private(set) var printer: IPPGroup?
/// Intel-only or missing driver filters, from the queue's PPD.
private(set) var driverFilters: DriverFilterReport?
private(set) var jobs: [JobSummary] = []
private(set) var loadError: String?
private(set) var isWorking = false
@@ -73,6 +75,11 @@ final class PrinterDetailModel {
do {
printer = try await store.client.getPrinterAttributes(queue: queue, requested: Self.headerAttributes)
loadError = nil
if let text = try await store.client.getPPD(queue: queue) {
driverFilters = await Task.detached { DriverFilterCheck.check(PPD(text: text)) }.value
} else {
driverFilters = nil
}
} catch {
loadError = String(describing: error)
store.report("ERROR: \(queue): \(error)")

View File

@@ -12,7 +12,7 @@ struct PrinterDetailView: View {
var body: some View {
VStack(spacing: 0) {
if let printer = model.printer {
PrinterHeaderView(printer: printer, ppdPath: model.ppdPath)
PrinterHeaderView(printer: printer, ppdPath: model.ppdPath, driverFilters: model.driverFilters)
Divider()
} else if let error = model.loadError {
ContentUnavailableView("Can’t Load \(model.queue)", systemImage: "exclamationmark.triangle",
@@ -35,6 +35,7 @@ struct PrinterDetailView: View {
struct PrinterHeaderView: View {
let printer: IPPGroup
let ppdPath: String?
let driverFilters: DriverFilterReport?
private var state: Int? { printer.int("printer-state") }
private var accepting: Bool { printer.bool("printer-is-accepting-jobs") ?? true }
@@ -64,6 +65,13 @@ struct PrinterHeaderView: View {
}
LabeledContent("Accepting jobs", value: accepting ? "Yes" : "No")
LabeledContent("Shared", value: printer.bool("printer-is-shared") == true ? "Yes" : "No")
if let headline = driverFilters?.headline {
LabeledContent("Driver") {
Label(headline, systemImage: "exclamationmark.triangle.fill")
.symbolRenderingMode(.multicolor)
}
.help(driverFilters?.detail ?? headline)
}
}
}
Form {
@@ -93,7 +101,7 @@ struct PrinterHeaderView: View {
.formStyle(.grouped)
.scrollDisabled(true)
.textSelection(.enabled)
.frame(height: 262)
.frame(height: driverFilters?.isFlagged == true ? 300 : 262)
}
}

View File

@@ -103,6 +103,8 @@ final class PrinterStore {
private(set) var defaultPrinter: String?
/// Driver PPD + IPP attributes per queue, for enabling Quick Actions.
private(set) var drivers: [String: DriverContext] = [:]
/// Filter check per queue (Intel-only or missing filters), from the cached PPDs.
private(set) var driverFilters: [String: DriverFilterReport] = [:]
var failure: Failure?
let client = CupsClient()
@@ -201,6 +203,11 @@ final class PrinterStore {
for printer in printers where drivers[printer.name] == nil {
if let context = try? await DriverContext.load(client: client, queue: printer.name) {
drivers[printer.name] = context
if let ppd = context.ppd {
driverFilters[printer.name] = await Task.detached { DriverFilterCheck.check(ppd) }.value
} else {
driverFilters[printer.name] = nil
}
}
}
}