From 0fd72ab06fdea0fdd5d8531e903044eb7b25d9dd Mon Sep 17 00:00:00 2001 From: Abhishek Banthia Date: Sun, 5 May 2019 14:55:28 -0700 Subject: [PATCH] More linting. --- Clocker/AppDelegate.swift | 2 +- Clocker/Clocker.xcodeproj/project.pbxproj | 4 + .../UserDefaults + KVOExtensions.swift | 18 ++ Clocker/Panel/PanelController.swift | 2 +- Clocker/Panel/ParentPanelController.swift | 154 ++++++++++-------- .../General/PreferencesViewController.swift | 92 ++++++----- 6 files changed, 161 insertions(+), 111 deletions(-) create mode 100644 Clocker/Overall App/UserDefaults + KVOExtensions.swift diff --git a/Clocker/AppDelegate.swift b/Clocker/AppDelegate.swift index 0aaf859..6ff477d 100644 --- a/Clocker/AppDelegate.swift +++ b/Clocker/AppDelegate.swift @@ -126,7 +126,7 @@ open class AppDelegate : NSObject, NSApplicationDelegate { assignShortcut() - panelObserver = panelController.observe(\.hasActivePanel, options: [.new]) { (obj, change) in + panelObserver = panelController.observe(\.hasActivePanel, options: [.new]) { (obj, _) in self.statusBarHandler.setHasActiveIcon(obj.hasActivePanelGetter()) } diff --git a/Clocker/Clocker.xcodeproj/project.pbxproj b/Clocker/Clocker.xcodeproj/project.pbxproj index 22112a5..e612db4 100755 --- a/Clocker/Clocker.xcodeproj/project.pbxproj +++ b/Clocker/Clocker.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 3595FAD0227F88BC0044A12A /* UserDefaults + KVOExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3595FACF227F88BC0044A12A /* UserDefaults + KVOExtensions.swift */; }; 35C36EE422595EFD002FA5C6 /* StatusContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36EE022595EFD002FA5C6 /* StatusContainerView.swift */; }; 35C36EE522595EFD002FA5C6 /* MenubarHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36EE122595EFD002FA5C6 /* MenubarHandler.swift */; }; 35C36EE622595EFD002FA5C6 /* StatusItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36EE222595EFD002FA5C6 /* StatusItemView.swift */; }; @@ -214,6 +215,7 @@ /* Begin PBXFileReference section */ 3545C52A22612BCC00121E25 /* RateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RateTests.swift; sourceTree = ""; }; + 3595FACF227F88BC0044A12A /* UserDefaults + KVOExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults + KVOExtensions.swift"; sourceTree = ""; }; 35C36EE022595EFD002FA5C6 /* StatusContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusContainerView.swift; sourceTree = ""; }; 35C36EE122595EFD002FA5C6 /* MenubarHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarHandler.swift; sourceTree = ""; }; 35C36EE222595EFD002FA5C6 /* StatusItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusItemView.swift; sourceTree = ""; }; @@ -504,6 +506,7 @@ 35C36F3D2259D892002FA5C6 /* Strings.swift */, 35C36F392259D892002FA5C6 /* Themer.swift */, 35C36F3A2259D892002FA5C6 /* Timer.swift */, + 3595FACF227F88BC0044A12A /* UserDefaults + KVOExtensions.swift */, ); path = "Overall App"; sourceTree = ""; @@ -1178,6 +1181,7 @@ C2CCCD8220619C4C00F2DFC2 /* LocationController.swift in Sources */, 35C36F4B2259D971002FA5C6 /* UnderlinedButton.swift in Sources */, 9AB6F1562259CF3900A44663 /* CalendarViewController.swift in Sources */, + 3595FAD0227F88BC0044A12A /* UserDefaults + KVOExtensions.swift in Sources */, 9AB6F1612259D1B000A44663 /* PreferencesViewController.swift in Sources */, 35C36F2022596253002FA5C6 /* OneWindowController.swift in Sources */, 35C36F442259D892002FA5C6 /* Logger.swift in Sources */, diff --git a/Clocker/Overall App/UserDefaults + KVOExtensions.swift b/Clocker/Overall App/UserDefaults + KVOExtensions.swift new file mode 100644 index 0000000..8074333 --- /dev/null +++ b/Clocker/Overall App/UserDefaults + KVOExtensions.swift @@ -0,0 +1,18 @@ +// Copyright © 2015 Abhishek Banthia + +import Cocoa + +extension UserDefaults { + + @objc dynamic var displayFutureSlider: Int { + return integer(forKey: CLDisplayFutureSliderKey) + } + + @objc dynamic var userFontSize: Int { + return integer(forKey: CLUserFontSizePreference) + } + + @objc dynamic var sliderDayRange: Int { + return integer(forKey: CLFutureSliderRange) + } +} diff --git a/Clocker/Panel/PanelController.swift b/Clocker/Panel/PanelController.swift index ea98823..88ca1b0 100644 --- a/Clocker/Panel/PanelController.swift +++ b/Clocker/Panel/PanelController.swift @@ -3,7 +3,7 @@ import Cocoa class PanelController: ParentPanelController { - + @objc dynamic var hasActivePanel: Bool = false static var sharedWindow = PanelController(windowNibName: .panel) diff --git a/Clocker/Panel/ParentPanelController.swift b/Clocker/Panel/ParentPanelController.swift index 81271c7..f4b7413 100644 --- a/Clocker/Panel/ParentPanelController.swift +++ b/Clocker/Panel/ParentPanelController.swift @@ -13,6 +13,10 @@ struct PanelConstants { class ParentPanelController: NSWindowController { + private var futureSliderObserver: NSKeyValueObservation? + private var userFontSizeSelectionObserver: NSKeyValueObservation? + private var futureSliderRangeObserver: NSKeyValueObservation? + private var eventStoreChangedNotification: NSObjectProtocol? var dateFormatter = DateFormatter() @@ -87,6 +91,32 @@ class ParentPanelController: NSWindowController { if let eventStoreNotif = eventStoreChangedNotification { NotificationCenter.default.removeObserver(eventStoreNotif) } + + [futureSliderObserver, userFontSizeSelectionObserver, futureSliderRangeObserver].forEach { + $0?.invalidate() + } + } + + private func setupObservers() { + futureSliderObserver = UserDefaults.standard.observe(\.displayFutureSlider, options: [.new]) { (_, change) in + if let changedValue = change.newValue { + self.futureSliderView.isHidden = changedValue == 1 + } + } + + userFontSizeSelectionObserver = UserDefaults.standard.observe(\.userFontSize, options: [.new]) { (_, change) in + if let newFontSize = change.newValue { + Logger.log(object: ["FontSize": newFontSize], for: "User Font Size Preference") + self.mainTableView.reloadData() + self.setScrollViewConstraint() + } + } + + futureSliderRangeObserver = UserDefaults.standard.observe(\.sliderDayRange, options: [.new]) { (_, change) in + if change.newValue != nil { + self.adjustFutureSliderBasedOnPreferences() + } + } } override func awakeFromNib() { @@ -107,13 +137,7 @@ class ParentPanelController: NSWindowController { mainTableView.selectionHighlightStyle = .none mainTableView.enclosingScrollView?.hasVerticalScroller = false - [CLDisplayFutureSliderKey, CLUserFontSizePreference, CLThemeKey, CLFutureSliderRange].forEach { key in - - UserDefaults.standard.addObserver(self, - forKeyPath: key, - options: .new, - context: nil) - } + setupObservers() updateReviewViewFontColor() @@ -281,6 +305,8 @@ class ParentPanelController: NSWindowController { sharingButton.image = sharedThemer.sharingImage() sliderDatePicker.textColor = sharedThemer.mainTextColor() + + updateReviewViewFontColor() } override func windowDidLoad() { @@ -302,25 +328,6 @@ class ParentPanelController: NSWindowController { } } - override func observeValue(forKeyPath keyPath: String?, of _: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { - if keyPath == CLDisplayFutureSliderKey, let changes = change, let new = changes[NSKeyValueChangeKey.newKey] as? NSNumber { - futureSliderView.isHidden = new.isEqual(to: NSNumber(value: 1)) - } else if keyPath == CLUserFontSizePreference, let userFontSize = DataStore.shared().retrieve(key: CLUserFontSizePreference) as? NSNumber { - Logger.log(object: ["FontSize": userFontSize], for: "User Font Size Preference") - mainTableView.reloadData() - setScrollViewConstraint() - } else if keyPath == CLThemeKey { - updateReviewViewFontColor() - } else if keyPath == CLFutureSliderRange { - adjustFutureSliderBasedOnPreferences() - } else { - super.observeValue(forKeyPath: keyPath, - of: keyPath, - change: change, - context: context) - } - } - func screenHeight() -> CGFloat { guard let main = NSScreen.main else { return 100 } @@ -343,38 +350,42 @@ class ParentPanelController: NSWindowController { parentTimer = nil } - func setScrollViewConstraint() { - var totalHeight: CGFloat = 0.0 - let preferences = defaultPreferences + private func getAdjustedRowHeight(for object: TimezoneData?, _ currentHeight: CGFloat) -> CGFloat { + var newHeight = currentHeight - for cellIndex in 0 ..< preferences.count { - let currentObject = TimezoneData.customObject(from: preferences[cellIndex]) - let rowRect = mainTableView.rect(ofRow: cellIndex) - var height: CGFloat = rowRect.size.height + if newHeight <= 68.0 { + newHeight = 69.0 + } - if height <= 68.0 { - height = 69.0 + if newHeight >= 68.0 { + newHeight = 75.0 + if let note = object?.note, note.isEmpty == false { + newHeight += 30 } + } - if height >= 68.0 { - height = 75.0 - if let note = currentObject?.note, note.isEmpty == false { - height += 30 - } + if newHeight >= 88.0 { + // Set it to 95 expicity in case the row height is calculated be higher. + newHeight = 95.0 + + if let note = object?.note, note.isEmpty { + newHeight -= 30.0 } + } - if height >= 88.0 { - // Set it to 95 expicity in case the row height is calculated be higher. - height = 95.0 + newHeight += mainTableView.intercellSpacing.height - if let note = currentObject?.note, note.isEmpty { - height -= 30.0 - } - } + return newHeight + } - height += mainTableView.intercellSpacing.height + func setScrollViewConstraint() { + var totalHeight: CGFloat = 0.0 + let preferences = defaultPreferences - totalHeight += height + for cellIndex in 0 ..< preferences.count { + let currentObject = TimezoneData.customObject(from: preferences[cellIndex]) + let rowRect = mainTableView.rect(ofRow: cellIndex) + totalHeight += getAdjustedRowHeight(for: currentObject, rowRect.size.height) } // This is for the Add Cell View case @@ -828,41 +839,44 @@ class ParentPanelController: NSWindowController { return } - NSAnimationContext.runAnimationGroup({ context in + NSAnimationContext.runAnimationGroup({ (context) in context.duration = 1 context.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) leftButton.animator().alphaValue = 0.0 rightButton.animator().alphaValue = 0.0 - }) { + }, completionHandler: { field.stringValue = title - NSAnimationContext.runAnimationGroup({ context in + NSAnimationContext.runAnimationGroup({ (context) in context.duration = 1 context.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) - self.leftButton.animator().alphaValue = 1.0 - self.rightButton.animator().alphaValue = 1.0 - - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.alignment = .center + self.runAnimationCompletionBlock(leftTitle, rightTitle) + }, completionHandler: {}) + }) + } - let styleAttributes = [ - NSAttributedString.Key.paragraphStyle: paragraphStyle, - NSAttributedString.Key.font: NSFont(name: "Avenir-Light", size: 13)! - ] + private func runAnimationCompletionBlock(_ leftButtonTitle: String, _ rightButtonTitle: String) { + self.leftButton.animator().alphaValue = 1.0 + self.rightButton.animator().alphaValue = 1.0 - if self.leftButton.attributedTitle.string == "Not Really" { - self.leftButton.animator().attributedTitle = NSAttributedString(string: PanelConstants.noThanksTitle, attributes: styleAttributes) - } + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.alignment = .center - if self.rightButton.attributedTitle.string == PanelConstants.yesWithExclamation { - self.rightButton.animator().attributedTitle = NSAttributedString(string: "Yes, sure", attributes: styleAttributes) - } + let styleAttributes = [ + NSAttributedString.Key.paragraphStyle: paragraphStyle, + NSAttributedString.Key.font: NSFont(name: "Avenir-Light", size: 13)! + ] - self.leftButton.animator().attributedTitle = NSAttributedString(string: leftTitle, attributes: styleAttributes) - self.rightButton.animator().attributedTitle = NSAttributedString(string: rightTitle, attributes: styleAttributes) + if self.leftButton.attributedTitle.string == "Not Really" { + self.leftButton.animator().attributedTitle = NSAttributedString(string: PanelConstants.noThanksTitle, attributes: styleAttributes) + } - }) {} + if self.rightButton.attributedTitle.string == PanelConstants.yesWithExclamation { + self.rightButton.animator().attributedTitle = NSAttributedString(string: "Yes, sure", attributes: styleAttributes) } + + self.leftButton.animator().attributedTitle = NSAttributedString(string: leftButtonTitle, attributes: styleAttributes) + self.rightButton.animator().attributedTitle = NSAttributedString(string: rightButtonTitle, attributes: styleAttributes) } // MARK: Date Picker + Slider diff --git a/Clocker/Preferences/General/PreferencesViewController.swift b/Clocker/Preferences/General/PreferencesViewController.swift index 39c5acb..090b2e7 100644 --- a/Clocker/Preferences/General/PreferencesViewController.swift +++ b/Clocker/Preferences/General/PreferencesViewController.swift @@ -340,30 +340,11 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate } if tableColumn?.identifier.rawValue == PreferencesConstants.timezoneNameIdentifier { - guard let model = selectedDataSource else { - return nil - } - - if let address = model.formattedAddress, address.isEmpty == false { - return model.formattedAddress - } - - return model.timezoneID + return handleTimezoneNameIdentifier(for: row, selectedDataSource) } if tableColumn?.identifier.rawValue == PreferencesConstants.availableTimezoneIdentifier { - let criteria = searchCriteria.selectedSegment - - if criteria == 0 { - if row < filteredArray.count { - return dataSource?.formattedAddress - } - } else { - if searchField.stringValue.isEmpty == false && row < timezoneFilteredArray.count { - return timezoneFilteredArray[row] - } - return timezoneArray[row] - } + return handleAvailableTimezoneColumn(for: row, dataSource) } if tableColumn?.identifier.rawValue == PreferencesConstants.customLabelIdentifier { @@ -375,31 +356,64 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate } if tableColumn?.identifier.rawValue == "abbreviation" { - if searchField.stringValue.isEmpty == false && (row < timezoneFilteredArray.count) { - let currentSelection = timezoneFilteredArray[row] - if currentSelection == "UTC" { - return "UTC" - } else if currentSelection == "Anywhere on Earth" { - return "GMT+12" - } + return handleAbbreviationColumn(for: row) + } - return NSTimeZone(name: timezoneFilteredArray[row])?.abbreviation ?? "Error" - } + return nil + } - if timezoneArray.count > row { - // Special return for manually inserted 'UTC' - if timezoneArray[row] == "UTC" { - return "UTC" - } + private func handleTimezoneNameIdentifier(for row: Int, _ selectedDataSource: TimezoneData?) -> Any? { + guard let model = selectedDataSource else { + return nil + } - if timezoneArray[row] == "Anywhere on Earth" { - return "AoE" - } + if let address = model.formattedAddress, address.isEmpty == false { + return model.formattedAddress + } + + return model.timezoneID + } - return NSTimeZone(name: timezoneArray[row])?.abbreviation ?? "Error" + private func handleAvailableTimezoneColumn(for row: Int, _ dataSource: TimezoneData?) -> Any? { + let criteria = searchCriteria.selectedSegment + + if criteria == 0 { + if row < filteredArray.count { + return dataSource?.formattedAddress } + } else { + if searchField.stringValue.isEmpty == false && row < timezoneFilteredArray.count { + return timezoneFilteredArray[row] + } + return timezoneArray[row] } + return nil + } + private func handleAbbreviationColumn(for row: Int) -> Any? { + if searchField.stringValue.isEmpty == false && (row < timezoneFilteredArray.count) { + let currentSelection = timezoneFilteredArray[row] + if currentSelection == "UTC" { + return "UTC" + } else if currentSelection == "Anywhere on Earth" { + return "GMT+12" + } + + return NSTimeZone(name: timezoneFilteredArray[row])?.abbreviation ?? "Error" + } + + if timezoneArray.count > row { + // Special return for manually inserted 'UTC' + if timezoneArray[row] == "UTC" { + return "UTC" + } + + if timezoneArray[row] == "Anywhere on Earth" { + return "AoE" + } + + return NSTimeZone(name: timezoneArray[row])?.abbreviation ?? "Error" + } return nil }