Skip to content

Commit 04338c8

Browse files
committed
refactor(datagrid): centralize chevron-kind check and extract testable picker components (#1405)
1 parent fa10c73 commit 04338c8

5 files changed

Lines changed: 69 additions & 35 deletions

File tree

TablePro/Core/Services/Formatting/DateEditingService.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ struct ParsedTemporalValue: Equatable {
2323
let layout: TemporalLayout
2424
}
2525

26+
enum TemporalComponents: Equatable {
27+
case dateOnly
28+
case timeOnly
29+
case dateAndTime
30+
}
31+
2632
enum DateEditingService {
2733
private static let pattern =
2834
#"^(?:(\d{4})-(\d{2})-(\d{2}))?(?:([ T])?(\d{2}):(\d{2}):(\d{2})(\.\d+)?)?(Z|[+-]\d{2}(?::?\d{2})?)?$"#
@@ -120,6 +126,12 @@ enum DateEditingService {
120126
return dateString(from: components) + " " + timeString(from: components)
121127
}
122128

129+
static func components(for columnType: ColumnType) -> TemporalComponents {
130+
if case .date = columnType { return .dateOnly }
131+
if columnType.isTimeOnly { return .timeOnly }
132+
return .dateAndTime
133+
}
134+
123135
private static func dateString(from components: DateComponents) -> String {
124136
String(format: "%04d-%02d-%02d", components.year ?? 0, components.month ?? 0, components.day ?? 0)
125137
}

TablePro/Views/Results/Cells/DataGridCellKind.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,13 @@ enum DataGridCellKind: Equatable {
1313
case json
1414
case blob
1515
case date
16+
17+
var showsChevron: Bool {
18+
switch self {
19+
case .dropdown, .boolean, .json, .blob, .date:
20+
return true
21+
case .text, .foreignKey:
22+
return false
23+
}
24+
}
1625
}

TablePro/Views/Results/Cells/DataGridCellView.swift

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -283,42 +283,37 @@ final class DataGridCellView: NSView {
283283
}
284284

285285
private func computeAccessoryRect() -> NSRect {
286-
switch kind {
287-
case .text:
288-
return .zero
289-
case .foreignKey:
286+
if kind == .foreignKey {
290287
guard let raw = rawValue, !raw.isEmpty else { return .zero }
291288
let size = NSSize(width: 16, height: 16)
292289
let x = bounds.maxX - DataGridMetrics.cellHorizontalInset - size.width
293290
let y = (bounds.height - size.height) / 2
294291
return NSRect(x: x, y: y, width: size.width, height: size.height)
295-
case .dropdown, .boolean, .json, .blob, .date:
296-
guard isEditableCell else { return .zero }
297-
let size = NSSize(width: 12, height: 14)
298-
let minRequired = size.width + 2 * DataGridMetrics.cellHorizontalInset
299-
guard bounds.width >= minRequired else { return .zero }
300-
let x = bounds.maxX - DataGridMetrics.cellHorizontalInset - size.width
301-
let y = (bounds.height - size.height) / 2
302-
return NSRect(x: x, y: y, width: size.width, height: size.height)
303292
}
293+
guard kind.showsChevron, isEditableCell else { return .zero }
294+
let size = NSSize(width: 12, height: 14)
295+
let minRequired = size.width + 2 * DataGridMetrics.cellHorizontalInset
296+
guard bounds.width >= minRequired else { return .zero }
297+
let x = bounds.maxX - DataGridMetrics.cellHorizontalInset - size.width
298+
let y = (bounds.height - size.height) / 2
299+
return NSRect(x: x, y: y, width: size.width, height: size.height)
304300
}
305301

306302
private func drawAccessory(in rect: NSRect) {
307303
guard !rect.isEmpty else { return }
308304
let image: CGImage?
309-
switch kind {
310-
case .text:
311-
return
312-
case .foreignKey:
305+
if kind == .foreignKey {
313306
image = onEmphasizedSelection ? Self.fkArrowEmphasized : Self.fkArrowNormal
314-
case .dropdown, .boolean, .json, .blob, .date:
307+
} else if kind.showsChevron {
315308
if visualState.isDeleted {
316309
image = Self.chevronDisabled
317310
} else if onEmphasizedSelection {
318311
image = Self.chevronEmphasized
319312
} else {
320313
image = Self.chevronNormal
321314
}
315+
} else {
316+
return
322317
}
323318
guard let cgImage = image, let context = NSGraphicsContext.current?.cgContext else { return }
324319
context.saveGState()
@@ -337,21 +332,17 @@ final class DataGridCellView: NSView {
337332

338333
override func mouseDown(with event: NSEvent) {
339334
let point = convert(event.locationInWindow, from: nil)
340-
if !accessoryHitRect.isEmpty && accessoryHitRect.contains(point) {
341-
switch kind {
342-
case .foreignKey:
343-
accessoryDelegate?.dataGridCellDidClickFKArrow(row: cellRow, columnIndex: cellColumnIndex)
344-
return
345-
case .dropdown, .boolean, .json, .blob, .date:
346-
guard !visualState.isDeleted else {
347-
super.mouseDown(with: event)
348-
return
349-
}
350-
accessoryDelegate?.dataGridCellDidClickChevron(row: cellRow, columnIndex: cellColumnIndex)
351-
return
352-
case .text:
353-
break
354-
}
335+
guard !accessoryHitRect.isEmpty, accessoryHitRect.contains(point) else {
336+
super.mouseDown(with: event)
337+
return
338+
}
339+
if kind == .foreignKey {
340+
accessoryDelegate?.dataGridCellDidClickFKArrow(row: cellRow, columnIndex: cellColumnIndex)
341+
return
342+
}
343+
if kind.showsChevron, !visualState.isDeleted {
344+
accessoryDelegate?.dataGridCellDidClickChevron(row: cellRow, columnIndex: cellColumnIndex)
345+
return
355346
}
356347
super.mouseDown(with: event)
357348
}

TablePro/Views/Results/Extensions/DataGridView+Popovers.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,11 @@ extension TableViewCoordinator {
207207
}
208208

209209
private func datePickerElements(for columnType: ColumnType) -> NSDatePicker.ElementFlags {
210-
if case .date = columnType { return .yearMonthDay }
211-
if columnType.isTimeOnly { return .hourMinuteSecond }
212-
return [.yearMonthDay, .hourMinuteSecond]
210+
switch DateEditingService.components(for: columnType) {
211+
case .dateOnly: return .yearMonthDay
212+
case .timeOnly: return .hourMinuteSecond
213+
case .dateAndTime: return [.yearMonthDay, .hourMinuteSecond]
214+
}
213215
}
214216

215217
func showEnumPopover(tableView: NSTableView, row: Int, column: Int, columnIndex: Int) {

TableProTests/Core/Services/DateEditingServiceTests.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,24 @@ struct DateEditingServiceTests {
117117
let value = DateEditingService.defaultString(from: parsed.date, columnType: .timestamp(rawType: "TIME"))
118118
#expect(value == "09:30:45")
119119
}
120+
121+
@Test("date column edits date components only")
122+
func componentsForDate() {
123+
#expect(DateEditingService.components(for: .date(rawType: "DATE")) == .dateOnly)
124+
}
125+
126+
@Test("time column edits time components only")
127+
func componentsForTime() {
128+
#expect(DateEditingService.components(for: .timestamp(rawType: "TIME")) == .timeOnly)
129+
}
130+
131+
@Test("time column with precision edits time components only")
132+
func componentsForTimeWithPrecision() {
133+
#expect(DateEditingService.components(for: .timestamp(rawType: "TIME(6)")) == .timeOnly)
134+
}
135+
136+
@Test("timestamp column edits date and time components")
137+
func componentsForTimestamp() {
138+
#expect(DateEditingService.components(for: .timestamp(rawType: "TIMESTAMP")) == .dateAndTime)
139+
}
120140
}

0 commit comments

Comments
 (0)