You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
7.5 KiB
192 lines
7.5 KiB
// Copyright © 2015 Abhishek Banthia |
|
|
|
import Cocoa |
|
|
|
class TimezoneDataSource: NSObject { |
|
var timezones: [TimezoneData] = [] |
|
var sliderValue: Int = 0 |
|
|
|
init(items: [TimezoneData]) { |
|
sliderValue = 0 |
|
timezones = Array(items) |
|
} |
|
} |
|
|
|
extension TimezoneDataSource { |
|
func setSlider(value: Int) { |
|
sliderValue = value |
|
} |
|
|
|
func setItems(items: [TimezoneData]) { |
|
timezones = items |
|
} |
|
} |
|
|
|
extension TimezoneDataSource: NSTableViewDataSource, NSTableViewDelegate { |
|
func numberOfRows(in _: NSTableView) -> Int { |
|
var totalTimezones = timezones.count |
|
|
|
// If totalTimezone is 0, then we can show an option to add timezones |
|
if totalTimezones == 0 { |
|
totalTimezones += 1 |
|
} |
|
|
|
return totalTimezones |
|
} |
|
|
|
func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? { |
|
guard !timezones.isEmpty else { |
|
if let addCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "addCell"), owner: self) as? AddTableViewCell { |
|
return addCellView |
|
} |
|
|
|
assertionFailure("Unable to create AddTableViewCell") |
|
return nil |
|
} |
|
|
|
guard let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "timeZoneCell"), owner: self) as? TimezoneCellView else { |
|
assertionFailure("Unable to create tableviewcell") |
|
return NSView() |
|
} |
|
|
|
let currentModel = timezones[row] |
|
let operation = TimezoneDataOperations(with: currentModel) |
|
|
|
cellView.sunriseSetTime.stringValue = operation.formattedSunriseTime(with: sliderValue) |
|
cellView.sunriseImage.image = currentModel.isSunriseOrSunset ? Themer.shared().sunriseImage() : Themer.shared().sunsetImage() |
|
cellView.relativeDate.stringValue = operation.date(with: sliderValue, displayType: .panelDisplay) |
|
cellView.rowNumber = row |
|
cellView.customName.stringValue = currentModel.formattedTimezoneLabel() |
|
cellView.time.stringValue = operation.time(with: sliderValue) |
|
cellView.noteLabel.stringValue = currentModel.note ?? CLEmptyString |
|
cellView.noteLabel.toolTip = currentModel.note ?? CLEmptyString |
|
cellView.currentLocationIndicator.isHidden = !currentModel.isSystemTimezone |
|
cellView.time.setAccessibilityIdentifier("ActualTime") |
|
cellView.layout(with: currentModel) |
|
|
|
cellView.setAccessibilityIdentifier(currentModel.formattedTimezoneLabel()) |
|
cellView.setAccessibilityLabel(currentModel.formattedTimezoneLabel()) |
|
|
|
return cellView |
|
} |
|
|
|
func tableView(_: NSTableView, heightOfRow row: Int) -> CGFloat { |
|
guard !timezones.isEmpty else { |
|
return 100 |
|
} |
|
|
|
if let userFontSize = DataStore.shared().retrieve(key: CLUserFontSizePreference) as? NSNumber, timezones.count > row, let relativeDisplay = DataStore.shared().retrieve(key: CLRelativeDateKey) as? NSNumber { |
|
let model = timezones[row] |
|
|
|
var rowHeight: Int = userFontSize == 4 ? 60 : 65 |
|
|
|
if relativeDisplay.intValue == 3 { |
|
rowHeight -= 5 |
|
} |
|
|
|
if let note = model.note, !note.isEmpty { |
|
return CGFloat(rowHeight + userFontSize.intValue + 25) |
|
} |
|
|
|
return CGFloat(rowHeight + (userFontSize.intValue * 2)) |
|
} |
|
|
|
return 0 |
|
} |
|
|
|
func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge: NSTableView.RowActionEdge) -> [NSTableViewRowAction] { |
|
guard !timezones.isEmpty else { |
|
return [] |
|
} |
|
|
|
let windowController = FloatingWindowController.shared() |
|
|
|
if edge == .trailing { |
|
let swipeToDelete = NSTableViewRowAction(style: .destructive, |
|
title: "Delete", |
|
handler: { _, row in |
|
|
|
if self.timezones[row].isSystemTimezone { |
|
self.showAlertForDeletingAHomeRow(row, tableView) |
|
return |
|
} |
|
|
|
let indexSet = IndexSet(integer: row) |
|
|
|
tableView.removeRows(at: indexSet, withAnimation: NSTableView.AnimationOptions.slideUp) |
|
|
|
if DataStore.shared().shouldDisplay(ViewType.showAppInForeground) { |
|
windowController.deleteTimezone(at: row) |
|
} else { |
|
guard let panelController = PanelController.panel() else { return } |
|
panelController.deleteTimezone(at: row) |
|
} |
|
|
|
}) |
|
|
|
swipeToDelete.image = NSImage(named: NSImage.Name("Trash")) |
|
|
|
return [swipeToDelete] |
|
} |
|
|
|
return [] |
|
} |
|
|
|
func showAlertForDeletingAHomeRow(_ row: Int, _ tableView: NSTableView) { |
|
NSApplication.shared.activate(ignoringOtherApps: true) |
|
|
|
let alert = NSAlert() |
|
alert.messageText = "Confirm deleting the home row? 😅" |
|
alert.informativeText = "This row is automatically updated when Clocker detects a system timezone change. Are you sure you want to delete this?" |
|
alert.addButton(withTitle: "Yes") |
|
alert.addButton(withTitle: "No") |
|
|
|
let response = alert.runModal() |
|
if response.rawValue == 1000 { |
|
OperationQueue.main.addOperation { |
|
let indexSet = IndexSet(integer: row) |
|
|
|
tableView.removeRows(at: indexSet, withAnimation: NSTableView.AnimationOptions.slideUp) |
|
|
|
if DataStore.shared().shouldDisplay(ViewType.showAppInForeground) { |
|
let windowController = FloatingWindowController.shared() |
|
windowController.deleteTimezone(at: row) |
|
} else { |
|
guard let panelController = PanelController.panel() else { return } |
|
panelController.deleteTimezone(at: row) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
extension TimezoneDataSource: PanelTableViewDelegate { |
|
func tableView(_ table: NSTableView, didHoverOver row: NSInteger) { |
|
for rowIndex in 0 ..< table.numberOfRows { |
|
if let rowCellView = table.view(atColumn: 0, row: rowIndex, makeIfNecessary: false) as? TimezoneCellView { |
|
if row == -1 { |
|
rowCellView.extraOptions.alphaValue = 0.5 |
|
continue |
|
} |
|
|
|
rowCellView.extraOptions.alphaValue = (rowIndex == row) ? 1 : 0.5 |
|
} |
|
} |
|
} |
|
} |
|
|
|
extension TimezoneCellView { |
|
func layout(with model: TimezoneData) { |
|
let shouldDisplay = DataStore.shared().shouldDisplay(.sunrise) && !sunriseSetTime.stringValue.isEmpty |
|
|
|
sunriseSetTime.isHidden = !shouldDisplay |
|
sunriseImage.isHidden = !shouldDisplay |
|
|
|
// If it's a timezone and not a place, we can't determine the sunrise/sunset time; hide the sunrise image |
|
if model.selectionType == .timezone, model.latitude == nil, model.longitude == nil { |
|
sunriseImage.isHidden = true |
|
} |
|
|
|
setupLayout() |
|
} |
|
}
|
|
|