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.
 
 
 
 
 

204 lines
7.8 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())
#if DEBUG
if row == 0 {
cellView.currentLocationIndicator.isHidden = false
}
#endif
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]
let shouldShowSunrise = DataStore.shared().shouldDisplay(.sunrise)
var rowHeight: Int = userFontSize == 4 ? 60 : 65
if relativeDisplay.intValue == 3 {
rowHeight -= 5
}
if shouldShowSunrise, model.selectionType == .city {
rowHeight += 8
}
if let note = model.note, !note.isEmpty {
rowHeight += userFontSize.intValue + 25
}
rowHeight += (userFontSize.intValue * 2)
return CGFloat(rowHeight)
}
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()
}
}