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.
211 lines
7.1 KiB
211 lines
7.1 KiB
// Copyright © 2015 Abhishek Banthia |
|
|
|
import Cocoa |
|
import CoreLoggerKit |
|
import CoreModelKit |
|
|
|
struct PreferencesDataSourceConstants { |
|
static let timezoneNameIdentifier = "formattedAddress" |
|
static let customLabelIdentifier = "label" |
|
static let availableTimezoneIdentifier = "availableTimezones" |
|
static let favoriteTimezoneIdentifier = "favouriteTimezone" |
|
} |
|
|
|
protocol PreferenceSelectionUpdates: AnyObject { |
|
func preferenceSelectionDataSourceMarkAsFavorite(_ dataObject: TimezoneData) |
|
func preferenceSelectionDataSourceUnfavourite(_ dataObject: TimezoneData) |
|
func preferenceSelectionDataSourceRefreshTimezoneTable() |
|
func preferenceSelectionDataSourceRefreshMainTableView() |
|
func preferenceSelectionDataSourceTableViewSelectionDidChange(_ status: Bool) |
|
func preferenceSelectionDataSourceTable(didClick tableColumn: NSTableColumn) |
|
} |
|
|
|
class PreferencesDataSource: NSObject { |
|
private weak var updateDelegate: PreferenceSelectionUpdates? |
|
private let store: DataStore |
|
var selectedTimezones: [Data] { |
|
return store.timezones() |
|
} |
|
|
|
init(with store: DataStore, callbackDelegate delegate: PreferenceSelectionUpdates) { |
|
self.store = store |
|
updateDelegate = delegate |
|
super.init() |
|
} |
|
} |
|
|
|
extension PreferencesDataSource: NSTableViewDelegate { |
|
func tableViewSelectionDidChange(_ notification: Notification) { |
|
if let tableView = notification.object as? NSTableView { |
|
updateDelegate?.preferenceSelectionDataSourceTableViewSelectionDidChange(tableView.selectedRow == -1) |
|
} |
|
} |
|
|
|
func tableView(_: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool { |
|
let data = NSKeyedArchiver.clocker_archive(with: rowIndexes) |
|
|
|
pboard.declareTypes([.dragSession], owner: self) |
|
pboard.setData(data, forType: .dragSession) |
|
|
|
return true |
|
} |
|
|
|
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation _: NSTableView.DropOperation) -> Bool { |
|
var newOrder = selectedTimezones |
|
|
|
var destination = row |
|
|
|
if row == newOrder.count { |
|
destination -= 1 |
|
} |
|
|
|
let pBoard = info.draggingPasteboard |
|
|
|
guard let data = pBoard.data(forType: .dragSession) else { |
|
assertionFailure("Data was unexpectedly nil") |
|
return false |
|
} |
|
|
|
guard let rowIndexes = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NSIndexSet.self, from: data) else { |
|
assertionFailure("Row was unexpectedly nil") |
|
return false |
|
} |
|
|
|
let first = rowIndexes.firstIndex |
|
|
|
let currentObject = newOrder[first] |
|
|
|
newOrder.remove(at: first) |
|
|
|
newOrder.insert(currentObject, at: destination) |
|
|
|
store.setTimezones(newOrder) |
|
|
|
tableView.reloadData() |
|
|
|
updateDelegate?.preferenceSelectionDataSourceRefreshMainTableView() |
|
|
|
tableView.deselectRow(tableView.selectedRow) |
|
|
|
return true |
|
} |
|
|
|
func tableView(_: NSTableView, validateDrop _: NSDraggingInfo, proposedRow _: Int, proposedDropOperation _: NSTableView.DropOperation) -> NSDragOperation { |
|
return .every |
|
} |
|
|
|
func tableView(_: NSTableView, didClick tableColumn: NSTableColumn) { |
|
updateDelegate?.preferenceSelectionDataSourceTable(didClick: tableColumn) |
|
} |
|
} |
|
|
|
extension PreferencesDataSource: NSTableViewDataSource { |
|
func numberOfRows(in _: NSTableView) -> Int { |
|
return selectedTimezones.count |
|
} |
|
|
|
func tableView(_: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { |
|
var selectedDataSource: TimezoneData? |
|
|
|
if selectedTimezones.count > row, |
|
let model = TimezoneData.customObject(from: selectedTimezones[row]) |
|
{ |
|
selectedDataSource = model |
|
} |
|
|
|
if tableColumn?.identifier.rawValue == PreferencesDataSourceConstants.timezoneNameIdentifier { |
|
return handleTimezoneNameIdentifier(selectedDataSource) |
|
} |
|
|
|
if tableColumn?.identifier.rawValue == PreferencesDataSourceConstants.customLabelIdentifier { |
|
return selectedDataSource?.customLabel ?? "Error" |
|
} |
|
|
|
if tableColumn?.identifier.rawValue == PreferencesDataSourceConstants.favoriteTimezoneIdentifier { |
|
return selectedDataSource?.isFavourite ?? 0 |
|
} |
|
|
|
return nil |
|
} |
|
|
|
private func handleTimezoneNameIdentifier(_ selectedDataSource: TimezoneData?) -> Any? { |
|
guard let model = selectedDataSource else { |
|
return nil |
|
} |
|
|
|
if let address = model.formattedAddress, address.isEmpty == false { |
|
return model.formattedAddress |
|
} |
|
|
|
return model.timezone() |
|
} |
|
|
|
func tableView(_: NSTableView, setObjectValue object: Any?, for _: NSTableColumn?, row: Int) { |
|
guard !selectedTimezones.isEmpty, let dataObject = TimezoneData.customObject(from: selectedTimezones[row]) else { |
|
return |
|
} |
|
|
|
if let edit = object as? String { |
|
setNewLabel(edit, for: dataObject, at: row) |
|
} else if let isFavouriteValue = object as? NSNumber { |
|
dataObject.isFavourite = isFavouriteValue.intValue |
|
insert(timezone: dataObject, at: row) |
|
dataObject.isFavourite == 1 ? |
|
updateDelegate?.preferenceSelectionDataSourceMarkAsFavorite(dataObject) : |
|
updateDelegate?.preferenceSelectionDataSourceUnfavourite(dataObject) |
|
updateStatusItem() |
|
updateDelegate?.preferenceSelectionDataSourceRefreshTimezoneTable() |
|
} |
|
|
|
updateDelegate?.preferenceSelectionDataSourceRefreshMainTableView() |
|
} |
|
|
|
private func setNewLabel(_ label: String, for dataObject: TimezoneData, at row: Int) { |
|
let formattedValue = label.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines) |
|
|
|
if selectedTimezones.count > row { |
|
Logger.log(object: [ |
|
"Old Label": dataObject.customLabel ?? "Error", |
|
"New Label": formattedValue, |
|
], |
|
for: "Custom Label Changed") |
|
|
|
dataObject.setLabel(formattedValue) |
|
|
|
insert(timezone: dataObject, at: row) |
|
|
|
updateMenubarTitles() |
|
} else { |
|
Logger.log(object: [ |
|
"MethodName": "SetObjectValue", |
|
"Selected Timezone Count": selectedTimezones.count, |
|
"Current Row": row, |
|
], |
|
for: "Error in selected row count") |
|
} |
|
} |
|
|
|
private func insert(timezone: TimezoneData, at index: Int) { |
|
guard let encodedObject = NSKeyedArchiver.clocker_archive(with: timezone) else { |
|
return |
|
} |
|
var newDefaults = selectedTimezones |
|
newDefaults[index] = encodedObject |
|
store.setTimezones(newDefaults) |
|
} |
|
|
|
private func updateMenubarTitles() { |
|
if let appDelegate = NSApplication.shared.delegate as? AppDelegate { |
|
appDelegate.setupMenubarTimer() |
|
} |
|
} |
|
|
|
// TODO: This probably does not need to be used |
|
private func updateStatusItem() { |
|
guard let statusItem = (NSApplication.shared.delegate as? AppDelegate)?.statusItemForPanel() else { |
|
return |
|
} |
|
|
|
statusItem.refresh() |
|
} |
|
}
|
|
|