Browse Source

Moving over to a seperate datasource.

pull/92/head
Abhishek 5 years ago
parent
commit
45c9d1c6ac
  1. 3
      Clocker/Overall App/Logger.swift
  2. 2
      Clocker/Panel/Data Layer/TimezoneDataOperations.swift
  3. 2
      Clocker/Panel/FloatingWindowController.swift
  4. 208
      Clocker/Preferences/General/PreferencesDataSource.swift
  5. 261
      Clocker/Preferences/General/PreferencesViewController.swift
  6. 6
      Clocker/Preferences/Preferences.storyboard

3
Clocker/Overall App/Logger.swift

@ -14,7 +14,6 @@ class Logger: NSObject {
@available(OSX 10.14, *) @available(OSX 10.14, *)
class PerfLogger: NSObject { class PerfLogger: NSObject {
static var panelLog = OSLog(subsystem: "com.abhishek.Clocker", static var panelLog = OSLog(subsystem: "com.abhishek.Clocker",
category: "Open Panel") category: "Open Panel")
static let signpostID = OSSignpostID(log: panelLog) static let signpostID = OSSignpostID(log: panelLog)
@ -37,5 +36,3 @@ class PerfLogger: NSObject {
signpostID: signpostID) signpostID: signpostID)
} }
} }

2
Clocker/Panel/Data Layer/TimezoneDataOperations.swift

@ -318,7 +318,7 @@ extension TimezoneDataOperations {
return dateFormatter.string(from: Date()) return dateFormatter.string(from: Date())
} }
func saveObject(at index: Int = -1) { func saveObject(at index: Int = -1) {
var defaults = DataStore.shared().timezones() var defaults = DataStore.shared().timezones()
let encodedObject = NSKeyedArchiver.archivedData(withRootObject: dataObject as Any) let encodedObject = NSKeyedArchiver.archivedData(withRootObject: dataObject as Any)
index == -1 ? defaults.append(encodedObject) : defaults.insert(encodedObject, at: index) index == -1 ? defaults.append(encodedObject) : defaults.insert(encodedObject, at: index)

2
Clocker/Panel/FloatingWindowController.swift

@ -43,7 +43,7 @@ class FloatingWindowController: ParentPanelController {
mainTableView.setAccessibility("FloatingTableView") mainTableView.setAccessibility("FloatingTableView")
} }
override func updatePanelColor() { override func updatePanelColor() {
super.updatePanelColor() super.updatePanelColor()
updateTheme() updateTheme()
} }

208
Clocker/Preferences/General/PreferencesDataSource.swift

@ -2,6 +2,212 @@
import Cocoa import Cocoa
protocol PreferenceSelectionUpdates: AnyObject {
func didAddTimezone(_ timezone: TimezoneData)
func markAsFavorite(_ dataObject: TimezoneData)
func unfavourite(_ dataObject: TimezoneData)
func refreshTimezoneTable()
func refreshMainTableView()
func tableViewSelectionDidChange(_ status: Bool)
func table(didClick tableColumn: NSTableColumn)
}
class PreferencesDataSource: NSObject { class PreferencesDataSource: NSObject {
private var selectedTimezones: [Data]! private weak var updateDelegate: PreferenceSelectionUpdates?
var selectedTimezones: [Data] {
return DataStore.shared().timezones()
}
init(callbackDelegate delegate: PreferenceSelectionUpdates) {
updateDelegate = delegate
super.init()
}
}
extension PreferencesDataSource: NSTableViewDelegate {
func tableViewSelectionDidChange(_ notification: Notification) {
if let tableView = notification.object as? NSTableView {
updateDelegate?.tableViewSelectionDidChange(tableView.selectedRow == -1)
}
}
func tableView(_: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
let data = NSKeyedArchiver.archivedData(withRootObject: 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 = NSKeyedUnarchiver.unarchiveObject(with: data) as? IndexSet, let first = rowIndexes.first else {
assertionFailure("Row was unexpectedly nil")
return false
}
let currentObject = newOrder[first]
newOrder.remove(at: first)
newOrder.insert(currentObject, at: destination)
DataStore.shared().setTimezones(newOrder)
tableView.reloadData()
updateDelegate?.refreshMainTableView()
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?.table(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 == PreferencesConstants.timezoneNameIdentifier {
return handleTimezoneNameIdentifier(selectedDataSource)
}
if tableColumn?.identifier.rawValue == PreferencesConstants.customLabelIdentifier {
return selectedDataSource?.customLabel ?? "Error"
}
if tableColumn?.identifier.rawValue == "favouriteTimezone" {
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.timezoneID
}
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?.markAsFavorite(dataObject) :
updateDelegate?.unfavourite(dataObject)
updateStatusItem()
updateDelegate?.refreshTimezoneTable()
}
updateDelegate?.refreshMainTableView()
}
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) {
let encodedObject = NSKeyedArchiver.archivedData(withRootObject: timezone)
var newDefaults = selectedTimezones
newDefaults[index] = encodedObject
DataStore.shared().setTimezones(newDefaults)
}
private func updateMenubarTitles() {
let defaultTimezones = DataStore.shared().timezones()
UserDefaults.standard.set([], forKey: CLMenubarFavorites)
let menubarTimes = defaultTimezones.compactMap { (data) -> TimezoneData? in
if let model = TimezoneData.customObject(from: data), model.isFavourite == 1 {
return model
}
return nil
}
let archivedObjects = menubarTimes.map { (timezone) -> Data in
NSKeyedArchiver.archivedData(withRootObject: timezone)
}
UserDefaults.standard.set(archivedObjects, forKey: CLMenubarFavorites)
// Update appereance if in compact menubar mode
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.performTimerWork()
}
} }

261
Clocker/Preferences/General/PreferencesViewController.swift

@ -76,6 +76,8 @@ class PreferencesViewController: ParentViewController {
@IBOutlet var sortToggle: NSButton! @IBOutlet var sortToggle: NSButton!
private var themeDidChangeNotification: NSObjectProtocol? private var themeDidChangeNotification: NSObjectProtocol?
private var selectionsDataSource: PreferencesDataSource!
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
@ -100,6 +102,10 @@ class PreferencesViewController: ParentViewController {
searchField.placeholderString = "Enter city, state, country or timezone name" searchField.placeholderString = "Enter city, state, country or timezone name"
setupTimezoneDatasource() setupTimezoneDatasource()
selectionsDataSource = PreferencesDataSource(callbackDelegate: self)
timezoneTableView.dataSource = selectionsDataSource
timezoneTableView.delegate = selectionsDataSource
} }
deinit { deinit {
@ -316,59 +322,34 @@ class PreferencesViewController: ParentViewController {
} }
extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate { extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate {
func numberOfRows(in tableView: NSTableView) -> Int { func numberOfRows(in _: NSTableView) -> Int {
var numberOfRows = 0 return numberOfSearchResults()
if tableView == timezoneTableView {
numberOfRows = selectedTimeZones.count
} else {
numberOfRows = numberOfSearchResults()
}
return numberOfRows
} }
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row _: Int) -> NSView? {
if let message = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "resultCell"), owner: self) as? SearchResultTableViewCell { if let message = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "resultCell"), owner: self) as? SearchResultTableViewCell {
message.sourceName.stringValue = "Nicaragua" message.sourceName.stringValue = "Nicaragua"
return message return message
} }
return nil; return nil
} }
func tableView(_: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { func tableView(_: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
var dataSource: TimezoneData? var dataSource: TimezoneData?
var selectedDataSource: TimezoneData?
if filteredArray.count > row, let currentFilteredObject = filteredArray[row] as? TimezoneData { if filteredArray.count > row, let currentFilteredObject = filteredArray[row] as? TimezoneData {
dataSource = currentFilteredObject dataSource = currentFilteredObject
} }
if selectedTimeZones.count > row, let model = TimezoneData.customObject(from: selectedTimeZones[row]) {
selectedDataSource = model
}
if tableColumn?.identifier.rawValue == PreferencesConstants.timezoneNameIdentifier {
return handleTimezoneNameIdentifier(for: row, selectedDataSource)
}
if tableColumn?.identifier.rawValue == PreferencesConstants.availableTimezoneIdentifier { if tableColumn?.identifier.rawValue == PreferencesConstants.availableTimezoneIdentifier {
if filteredArray.isEmpty { if filteredArray.isEmpty {
return timezoneArray[row] return timezoneArray[row]
} }
return dataSource != nil ? return dataSource != nil ?
handleAvailableTimezoneColumn(for: row, dataSource) : handleAvailableTimezoneColumn(for: row, dataSource) :
filteredArray[row] as? String filteredArray[row] as? String
}
if tableColumn?.identifier.rawValue == PreferencesConstants.customLabelIdentifier {
return selectedDataSource?.customLabel ?? "Error"
}
if tableColumn?.identifier.rawValue == "favouriteTimezone" {
return selectedDataSource?.isFavourite ?? 0
} }
if tableColumn?.identifier.rawValue == "abbreviation" { if tableColumn?.identifier.rawValue == "abbreviation" {
@ -378,18 +359,6 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
return nil return nil
} }
private func handleTimezoneNameIdentifier(for _: Int, _ selectedDataSource: TimezoneData?) -> Any? {
guard let model = selectedDataSource else {
return nil
}
if let address = model.formattedAddress, address.isEmpty == false {
return model.formattedAddress
}
return model.timezoneID
}
private func handleAvailableTimezoneColumn(for row: Int, _ dataSource: TimezoneData?) -> Any? { private func handleAvailableTimezoneColumn(for row: Int, _ dataSource: TimezoneData?) -> Any? {
if row < filteredArray.count { if row < filteredArray.count {
return dataSource?.formattedAddress return dataSource?.formattedAddress
@ -413,27 +382,7 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
return nil return nil
} }
func tableView(_: NSTableView, setObjectValue object: Any?, for _: NSTableColumn?, row: Int) { private func _markAsFavorite(_ dataObject: TimezoneData) {
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 ?
markAsFavorite(dataObject) :
unfavourite(dataObject)
updateStatusItem()
refreshTimezoneTableView()
}
refreshMainTable()
}
private func markAsFavorite(_ dataObject: TimezoneData) {
guard let menubarTitles = DataStore.shared().retrieve(key: CLMenubarFavorites) as? [Data] else { guard let menubarTitles = DataStore.shared().retrieve(key: CLMenubarFavorites) as? [Data] else {
return return
} }
@ -457,7 +406,7 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
} }
} }
private func unfavourite(_ dataObject: TimezoneData) { private func _unfavourite(_ dataObject: TimezoneData) {
guard let menubarTimers = DataStore.shared().retrieve(key: CLMenubarFavorites) as? [Data] else { guard let menubarTimers = DataStore.shared().retrieve(key: CLMenubarFavorites) as? [Data] else {
assertionFailure("Menubar timers is unexpectedly nil") assertionFailure("Menubar timers is unexpectedly nil")
return return
@ -487,31 +436,6 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
} }
} }
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 showAlertIfMoreThanOneTimezoneHasBeenAddedToTheMenubar() { private func showAlertIfMoreThanOneTimezoneHasBeenAddedToTheMenubar() {
let isUITestRunning = ProcessInfo.processInfo.arguments.contains(CLUITestingLaunchArgument) let isUITestRunning = ProcessInfo.processInfo.arguments.contains(CLUITestingLaunchArgument)
@ -558,100 +482,6 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
} }
} }
} }
func tableView(_: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
let data = NSKeyedArchiver.archivedData(withRootObject: rowIndexes)
pboard.declareTypes([.dragSession], owner: self)
pboard.setData(data, forType: .dragSession)
return true
}
func 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 = NSKeyedUnarchiver.unarchiveObject(with: data) as? IndexSet, let first = rowIndexes.first else {
assertionFailure("Row was unexpectedly nil")
return false
}
let currentObject = newOrder[first]
newOrder.remove(at: first)
newOrder.insert(currentObject, at: destination)
DataStore.shared().setTimezones(newOrder)
timezoneTableView.reloadData()
refreshMainTable()
timezoneTableView.deselectRow(timezoneTableView.selectedRow)
return true
}
func tableView(_: NSTableView, validateDrop _: NSDraggingInfo, proposedRow _: Int, proposedDropOperation _: NSTableView.DropOperation) -> NSDragOperation {
return .every
}
func tableViewSelectionDidChange(_: Notification) {
deleteButton.isEnabled = !(timezoneTableView.selectedRow == -1)
}
func tableView(_ tableView: NSTableView, didClick tableColumn: NSTableColumn) {
if tableColumn.identifier.rawValue == "favouriteTimezone" {
return
}
if tableView == timezoneTableView {
let sortedTimezones = selectedTimeZones.sorted { (obj1, obj2) -> Bool in
guard let object1 = TimezoneData.customObject(from: obj1),
let object2 = TimezoneData.customObject(from: obj2) else {
assertionFailure("Data was unexpectedly nil")
return false
}
if tableColumn.identifier.rawValue == "formattedAddress" {
return arePlacesSortedInAscendingOrder ?
object1.formattedAddress! > object2.formattedAddress! :
object1.formattedAddress! < object2.formattedAddress!
} else {
return arePlacesSortedInAscendingOrder ?
object1.customLabel! > object2.customLabel! :
object1.customLabel! < object2.customLabel!
}
}
let indicatorImage = arePlacesSortedInAscendingOrder ?
NSImage(named: NSImage.Name("NSDescendingSortIndicator"))! :
NSImage(named: NSImage.Name("NSAscendingSortIndicator"))!
timezoneTableView.setIndicatorImage(indicatorImage, in: tableColumn)
arePlacesSortedInAscendingOrder.toggle()
DataStore.shared().setTimezones(sortedTimezones)
updateAfterSorting()
}
}
} }
extension PreferencesViewController { extension PreferencesViewController {
@ -763,7 +593,6 @@ extension PreferencesViewController {
self.filteredArray.append(TimezoneData(with: totalPackage)) self.filteredArray.append(TimezoneData(with: totalPackage))
} }
} }
private func prepareUIForPresentingResults() { private func prepareUIForPresentingResults() {
@ -1168,7 +997,7 @@ extension PreferencesViewController {
availableTimezoneTableView.reloadData() availableTimezoneTableView.reloadData()
} }
@IBAction func filterArray(_ sender: Any?) { @IBAction func filterArray(_: Any?) {
messageLabel.stringValue = CLEmptyString messageLabel.stringValue = CLEmptyString
filteredArray = [] filteredArray = []
@ -1336,3 +1165,63 @@ extension PreferencesViewController {
class SearchResultTableViewCell: NSTableCellView { class SearchResultTableViewCell: NSTableCellView {
@IBOutlet var sourceName: NSTextField! @IBOutlet var sourceName: NSTextField!
} }
extension PreferencesViewController: PreferenceSelectionUpdates {
func didAddTimezone(_: TimezoneData) {}
func markAsFavorite(_ dataObject: TimezoneData) {
_markAsFavorite(dataObject)
}
func unfavourite(_ dataObject: TimezoneData) {
_unfavourite(dataObject)
}
func refreshTimezoneTable() {
refreshTimezoneTableView()
}
func refreshMainTableView() {
refreshMainTable()
}
func tableViewSelectionDidChange(_ status: Bool) {
deleteButton.isEnabled = !status
}
func table(didClick tableColumn: NSTableColumn) {
if tableColumn.identifier.rawValue == "favouriteTimezone" {
return
}
let sortedTimezones = selectedTimeZones.sorted { (obj1, obj2) -> Bool in
guard let object1 = TimezoneData.customObject(from: obj1),
let object2 = TimezoneData.customObject(from: obj2) else {
assertionFailure("Data was unexpectedly nil")
return false
}
if tableColumn.identifier.rawValue == "formattedAddress" {
return arePlacesSortedInAscendingOrder ?
object1.formattedAddress! > object2.formattedAddress! :
object1.formattedAddress! < object2.formattedAddress!
} else {
return arePlacesSortedInAscendingOrder ?
object1.customLabel! > object2.customLabel! :
object1.customLabel! < object2.customLabel!
}
}
let indicatorImage = arePlacesSortedInAscendingOrder ?
NSImage(named: NSImage.Name("NSDescendingSortIndicator"))! :
NSImage(named: NSImage.Name("NSAscendingSortIndicator"))!
timezoneTableView.setIndicatorImage(indicatorImage, in: tableColumn)
arePlacesSortedInAscendingOrder.toggle()
DataStore.shared().setTimezones(sortedTimezones)
updateAfterSorting()
}
}

6
Clocker/Preferences/Preferences.storyboard

@ -1472,10 +1472,6 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
</tableColumn> </tableColumn>
</tableColumns> </tableColumns>
<connections>
<outlet property="dataSource" destination="ZT5-cA-xLj" id="xIY-n8-day"/>
<outlet property="delegate" destination="ZT5-cA-xLj" id="NtV-GS-sHC"/>
</connections>
</tableView> </tableView>
</subviews> </subviews>
<nil key="backgroundColor"/> <nil key="backgroundColor"/>
@ -1649,7 +1645,7 @@ CA
<windowStyleMask key="styleMask" closable="YES" miniaturizable="YES" nonactivatingPanel="YES"/> <windowStyleMask key="styleMask" closable="YES" miniaturizable="YES" nonactivatingPanel="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="120" y="64" width="345" height="320"/> <rect key="contentRect" x="120" y="64" width="345" height="320"/>
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="777"/> <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<value key="minSize" type="size" width="345" height="320"/> <value key="minSize" type="size" width="345" height="320"/>
<value key="maxSize" type="size" width="345" height="320"/> <value key="maxSize" type="size" width="345" height="320"/>
<view key="contentView" id="MAe-t5-3A2"> <view key="contentView" id="MAe-t5-3A2">

Loading…
Cancel
Save