Browse Source

Few changes.

pull/92/head
Abhishek Banthia 6 years ago
parent
commit
66ae394ecb
  1. 13
      .swiftlint.yml
  2. 17
      Clocker/AppDelegate.swift
  3. 29
      Clocker/Events and Reminders/CalendarHandler.swift
  4. 282
      Clocker/Onboarding/OnboardingParentViewController.swift
  5. 61
      Clocker/Onboarding/OnboardingSearchController.swift
  6. 12
      Clocker/Overall App/NetworkManager.swift
  7. 4
      Clocker/Overall App/Themer.swift
  8. 2
      Clocker/Panel/Data Layer/TimezoneDataOperations.swift
  9. 33
      Clocker/Panel/Notes Popover/NotesPopover.swift
  10. 4
      Clocker/Panel/ParentPanelController.swift
  11. 5
      Clocker/Panel/UI/BackgroundPanelView.swift
  12. 6
      Clocker/Preferences/Appearance/AppearanceViewController.swift
  13. 10
      Clocker/Preferences/Calendar/CalendarViewController.swift
  14. 239
      Clocker/Preferences/General/PreferencesViewController.swift
  15. 8
      Clocker/Preferences/OneWindowController.swift

13
.swiftlint.yml

@ -1,18 +1,15 @@
disabled_rules: # rule identifiers to exclude from running disabled_rules: # rule identifiers to exclude from running
- colon
- comma
- control_statement
- line_length
- type_body_length - type_body_length
- file_length # - file_length
- nesting # - nesting
- function_body_length
opt_in_rules: # some rules are only opt-in opt_in_rules: # some rules are only opt-in
- empty_count - empty_count
# included: # paths to include during linting. `--path` is ignored if present. # included: # paths to include during linting. `--path` is ignored if present.
# - Clocker # - Clocker
excluded: # paths to ignore during linting. Takes precedence over `included`. excluded: # paths to ignore during linting. Takes precedence over `included`.
- Clocker/Dependencies - Clocker/Dependencies
- Clocker/ClockerUnitTests
- Clocker/ClockerUITests
# - Pods # - Pods
# - Source/ExcludedFolder # - Source/ExcludedFolder
# - Source/ExcludedFile.swift # - Source/ExcludedFile.swift
@ -51,4 +48,4 @@ identifier_name:
# - id # - id
# - URL # - URL
# - GlobalAPIKey # - GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown) reporter: "xcode"

17
Clocker/AppDelegate.swift

@ -2,7 +2,7 @@
import Cocoa import Cocoa
open class AppDelegate : NSObject, NSApplicationDelegate { open class AppDelegate: NSObject, NSApplicationDelegate {
lazy private var floatingWindow: FloatingWindowController = FloatingWindowController.shared() lazy private var floatingWindow: FloatingWindowController = FloatingWindowController.shared()
lazy private var panelController: PanelController = PanelController.shared() lazy private var panelController: PanelController = PanelController.shared()
@ -13,7 +13,7 @@ open class AppDelegate : NSObject, NSApplicationDelegate {
panelObserver?.invalidate() panelObserver?.invalidate()
} }
open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
if let path = keyPath, path == "values.globalPing" { if let path = keyPath, path == "values.globalPing" {
@ -98,7 +98,8 @@ open class AppDelegate : NSObject, NSApplicationDelegate {
}() }()
private func showOnboardingFlow() { private func showOnboardingFlow() {
let shouldLaunchOnboarding = (DataStore.shared().retrieve(key: CLShowOnboardingFlow) == nil && DataStore.shared().timezones().isEmpty) || (ProcessInfo.processInfo.arguments.contains(CLOnboaringTestsLaunchArgument)) let shouldLaunchOnboarding = (DataStore.shared().retrieve(key: CLShowOnboardingFlow) == nil && DataStore.shared().timezones().isEmpty)
|| (ProcessInfo.processInfo.arguments.contains(CLOnboaringTestsLaunchArgument))
shouldLaunchOnboarding ? controller?.launch() : continueUsually() shouldLaunchOnboarding ? controller?.launch() : continueUsually()
} }
@ -238,11 +239,17 @@ open class AppDelegate : NSObject, NSApplicationDelegate {
} }
} }
let informativeText = """
Clocker must be run from the Applications folder in order to work properly.
Please quit Clocker, move it to the Applications folder, and relaunch.
Current folder: \(applicationDirectory)"
"""
// Clocker is installed out of Applications directory // Clocker is installed out of Applications directory
// This breaks start at login! Time to show an alert and terminate // This breaks start at login! Time to show an alert and terminate
showAlert(message: "Move Clocker to the Applications folder", showAlert(message: "Move Clocker to the Applications folder",
informativeText: "Clocker must be run from the Applications folder in order to work properly.\n\nPlease quit Clocker, move it to the Applications folder, and relaunch. Current folder: \(applicationDirectory)", informativeText: informativeText,
buttonTitle: "Quit") buttonTitle: "Quit")
// Terminate // Terminate
NSApp.terminate(nil) NSApp.terminate(nil)

29
Clocker/Events and Reminders/CalendarHandler.swift

@ -228,23 +228,11 @@ extension EventCenter {
} }
nextDate = autoupdatingCalendar.startOfDay(for: nextDate) nextDate = autoupdatingCalendar.startOfDay(for: nextDate)
// Make a customized struct
let isStartDate = autoupdatingCalendar.isDate(date, inSameDayAs: event.startDate) && (event.endDate.compare(date) == .orderedDescending)
let isEndDate = autoupdatingCalendar.isDate(date, inSameDayAs: event.endDate) && (event.startDate.compare(date) == .orderedAscending)
let isAllDay = event.isAllDay || (event.startDate.compare(date) == .orderedAscending && event.endDate.compare(nextDate) == .orderedSame)
let isSingleDay = event.isAllDay && (event.startDate.compare(date) == .orderedSame && event.endDate.compare(nextDate) == .orderedSame)
let eventInfo = EventInfo(event: event,
isStartDate: isStartDate,
isEndDate: isEndDate,
isAllDay: isAllDay,
isSingleDay: isSingleDay)
if eventsForDateMapper[date] == nil { if eventsForDateMapper[date] == nil {
eventsForDateMapper[date] = [] eventsForDateMapper[date] = []
} }
eventsForDateMapper[date]?.append(eventInfo) eventsForDateMapper[date]?.append(generateEventInfo(for: event, date, nextDate))
date = nextDate date = nextDate
} }
@ -265,6 +253,21 @@ extension EventCenter {
filterEvents() filterEvents()
} }
private func generateEventInfo(for event: EKEvent, _ date: Date, _ nextDate: Date) -> EventInfo {
// Make a customized struct
let isStartDate = autoupdatingCalendar.isDate(date, inSameDayAs: event.startDate) && (event.endDate.compare(date) == .orderedDescending)
let isEndDate = autoupdatingCalendar.isDate(date, inSameDayAs: event.endDate) && (event.startDate.compare(date) == .orderedAscending)
let isAllDay = event.isAllDay || (event.startDate.compare(date) == .orderedAscending && event.endDate.compare(nextDate) == .orderedSame)
let isSingleDay = event.isAllDay && (event.startDate.compare(date) == .orderedSame && event.endDate.compare(nextDate) == .orderedSame)
let eventInfo = EventInfo(event: event,
isStartDate: isStartDate,
isEndDate: isEndDate,
isAllDay: isAllDay,
isSingleDay: isSingleDay)
return eventInfo
}
} }
struct CalendarInfo { struct CalendarInfo {

282
Clocker/Onboarding/OnboardingParentViewController.swift

@ -26,15 +26,15 @@ class OnboardingParentViewController: NSViewController {
@IBOutlet private var backButton: NSButton! @IBOutlet private var backButton: NSButton!
@IBOutlet private var positiveButton: NSButton! @IBOutlet private var positiveButton: NSButton!
private lazy var welcomeVC: WelcomeViewController? = (storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier.welcomeIdentifier) as? WelcomeViewController) private lazy var welcomeVC = (storyboard?.instantiateController(withIdentifier: .welcomeIdentifier) as? WelcomeViewController)
private lazy var permissionsVC: OnboardingPermissionsViewController? = (storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier.onboardingPermissionsIdentifier) as? OnboardingPermissionsViewController) private lazy var permissionsVC = (storyboard?.instantiateController(withIdentifier: .onboardingPermissionsIdentifier) as? OnboardingPermissionsViewController)
private lazy var startAtLoginVC: StartAtLoginViewController? = (storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier.startAtLoginIdentifier) as? StartAtLoginViewController) private lazy var startAtLoginVC = (storyboard?.instantiateController(withIdentifier: .startAtLoginIdentifier) as? StartAtLoginViewController)
private lazy var onboardingSearchVC: OnboardingSearchController? = (self.storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier.onboardingSearchIdentifier) as? OnboardingSearchController) private lazy var onboardingSearchVC = (storyboard?.instantiateController(withIdentifier: .onboardingSearchIdentifier) as? OnboardingSearchController)
private lazy var finalOnboardingVC: FinalOnboardingViewController? = (self.storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier.finalOnboardingIdentifier) as? FinalOnboardingViewController) private lazy var finalOnboardingVC = (storyboard?.instantiateController(withIdentifier: .finalOnboardingIdentifier) as? FinalOnboardingViewController)
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
@ -96,84 +96,102 @@ class OnboardingParentViewController: NSViewController {
@IBAction func continueOnboarding(_: NSButton) { @IBAction func continueOnboarding(_: NSButton) {
if positiveButton.tag == OnboardingType.welcome.rawValue { if positiveButton.tag == OnboardingType.welcome.rawValue {
guard let fromViewController = welcomeVC, let toViewController = permissionsVC else { navigateToPermissions()
assertionFailure()
return
}
addChildIfNeccessary(toViewController)
transition(from: fromViewController,
to: toViewController,
options: .slideLeft) {
self.positiveButton.tag = OnboardingType.permissions.rawValue
self.positiveButton.title = "Continue"
self.backButton.isHidden = false
}
} else if positiveButton.tag == OnboardingType.permissions.rawValue { } else if positiveButton.tag == OnboardingType.permissions.rawValue {
guard let fromViewController = permissionsVC, let toViewController = startAtLoginVC else { navigateToStartAtLogin()
assertionFailure()
return
}
addChildIfNeccessary(toViewController)
transition(from: fromViewController,
to: toViewController,
options: .slideLeft) {
self.backButton.tag = OnboardingType.permissions.rawValue
self.positiveButton.tag = OnboardingType.launchAtLogin.rawValue
self.positiveButton.title = "Open Clocker At Login"
self.negativeButton.isHidden = false
}
} else if positiveButton.tag == OnboardingType.launchAtLogin.rawValue { } else if positiveButton.tag == OnboardingType.launchAtLogin.rawValue {
guard let fromViewController = startAtLoginVC, let toViewController = onboardingSearchVC else { navigateToSearch()
assertionFailure()
return
}
addChildIfNeccessary(toViewController)
shouldStartAtLogin(true)
transition(from: fromViewController,
to: toViewController,
options: .slideLeft) {
self.backButton.tag = OnboardingType.launchAtLogin.rawValue
self.positiveButton.tag = OnboardingType.search.rawValue
self.positiveButton.title = "Continue"
self.negativeButton.isHidden = true
}
} else if positiveButton.tag == OnboardingType.search.rawValue { } else if positiveButton.tag == OnboardingType.search.rawValue {
guard let fromViewController = onboardingSearchVC, let toViewController = finalOnboardingVC else { navigateToFinalStage()
assertionFailure() } else {
return performFinalStepsBeforeFinishing()
} }
}
addChildIfNeccessary(toViewController) private func navigateToPermissions() {
guard let fromViewController = welcomeVC, let toViewController = permissionsVC else {
assertionFailure()
return
}
transition(from: fromViewController, addChildIfNeccessary(toViewController)
to: toViewController,
options: .slideLeft) {
self.backButton.tag = OnboardingType.search.rawValue
self.positiveButton.tag = OnboardingType.final.rawValue
self.positiveButton.title = "Launch Clocker"
}
} else { transition(from: fromViewController,
to: toViewController,
options: .slideLeft) {
self.positiveButton.tag = OnboardingType.permissions.rawValue
self.positiveButton.title = "Continue"
self.backButton.isHidden = false
}
}
self.positiveButton.tag = OnboardingType.complete.rawValue private func navigateToStartAtLogin() {
guard let fromViewController = permissionsVC, let toViewController = startAtLoginVC else {
assertionFailure()
return
}
// Install the menubar option! addChildIfNeccessary(toViewController)
let appDelegate = NSApplication.shared.delegate as? AppDelegate
appDelegate?.continueUsually()
view.window?.close() transition(from: fromViewController,
to: toViewController,
options: .slideLeft) {
self.backButton.tag = OnboardingType.permissions.rawValue
self.positiveButton.tag = OnboardingType.launchAtLogin.rawValue
self.positiveButton.title = "Open Clocker At Login"
self.negativeButton.isHidden = false
}
}
if ProcessInfo.processInfo.arguments.contains(CLOnboaringTestsLaunchArgument) == false { private func navigateToSearch() {
UserDefaults.standard.set(true, forKey: CLShowOnboardingFlow) guard let fromViewController = startAtLoginVC, let toViewController = onboardingSearchVC else {
} assertionFailure()
return
}
addChildIfNeccessary(toViewController)
shouldStartAtLogin(true)
transition(from: fromViewController,
to: toViewController,
options: .slideLeft) {
self.backButton.tag = OnboardingType.launchAtLogin.rawValue
self.positiveButton.tag = OnboardingType.search.rawValue
self.positiveButton.title = "Continue"
self.negativeButton.isHidden = true
}
}
private func navigateToFinalStage() {
guard let fromViewController = onboardingSearchVC, let toViewController = finalOnboardingVC else {
assertionFailure()
return
}
addChildIfNeccessary(toViewController)
transition(from: fromViewController,
to: toViewController,
options: .slideLeft) {
self.backButton.tag = OnboardingType.search.rawValue
self.positiveButton.tag = OnboardingType.final.rawValue
self.positiveButton.title = "Launch Clocker"
}
}
private func performFinalStepsBeforeFinishing() {
self.positiveButton.tag = OnboardingType.complete.rawValue
// Install the menubar option!
let appDelegate = NSApplication.shared.delegate as? AppDelegate
appDelegate?.continueUsually()
view.window?.close()
if ProcessInfo.processInfo.arguments.contains(CLOnboaringTestsLaunchArgument) == false {
UserDefaults.standard.set(true, forKey: CLShowOnboardingFlow)
} }
} }
@ -185,64 +203,78 @@ class OnboardingParentViewController: NSViewController {
@IBAction func back(_: Any) { @IBAction func back(_: Any) {
if backButton.tag == OnboardingType.welcome.rawValue { if backButton.tag == OnboardingType.welcome.rawValue {
guard let fromViewController = permissionsVC, let toViewController = welcomeVC else { goBackToWelcomeScreen()
assertionFailure()
return
}
transition(from: fromViewController,
to: toViewController,
options: .slideRight) {
self.positiveButton.tag = OnboardingType.welcome.rawValue
self.backButton.isHidden = true
self.positiveButton.title = "Get Started"
}
} else if backButton.tag == OnboardingType.permissions.rawValue { } else if backButton.tag == OnboardingType.permissions.rawValue {
// We're on StartAtLogin VC and we have to go back to Permissions goBackToPermissions()
guard let fromViewController = startAtLoginVC, let toViewController = permissionsVC else {
assertionFailure()
return
}
transition(from: fromViewController,
to: toViewController,
options: .slideRight) {
self.positiveButton.tag = OnboardingType.permissions.rawValue
self.backButton.tag = OnboardingType.welcome.rawValue
self.negativeButton.isHidden = true
self.positiveButton.title = "Continue"
}
} else if backButton.tag == OnboardingType.launchAtLogin.rawValue { } else if backButton.tag == OnboardingType.launchAtLogin.rawValue {
guard let fromViewController = onboardingSearchVC, let toViewController = startAtLoginVC else { goBackToStartAtLogin()
assertionFailure()
return
}
transition(from: fromViewController,
to: toViewController,
options: .slideRight) {
self.positiveButton.tag = OnboardingType.launchAtLogin.rawValue
self.backButton.tag = OnboardingType.permissions.rawValue
self.positiveButton.title = "Open Clocker At Login"
self.negativeButton.isHidden = false
}
} else if backButton.tag == OnboardingType.search.rawValue { } else if backButton.tag == OnboardingType.search.rawValue {
goBackToSearch()
}
}
private func goBackToSearch() {
guard let fromViewController = finalOnboardingVC, let toViewController = onboardingSearchVC else {
assertionFailure()
return
}
transition(from: fromViewController,
to: toViewController,
options: .slideRight) {
self.positiveButton.tag = OnboardingType.search.rawValue
self.backButton.tag = OnboardingType.launchAtLogin.rawValue
self.positiveButton.title = "Continue"
self.negativeButton.isHidden = true
}
}
private func goBackToStartAtLogin() {
guard let fromViewController = onboardingSearchVC, let toViewController = startAtLoginVC else {
assertionFailure()
return
}
transition(from: fromViewController,
to: toViewController,
options: .slideRight) {
self.positiveButton.tag = OnboardingType.launchAtLogin.rawValue
self.backButton.tag = OnboardingType.permissions.rawValue
self.positiveButton.title = "Open Clocker At Login"
self.negativeButton.isHidden = false
}
}
private func goBackToPermissions() {
// We're on StartAtLogin VC and we have to go back to Permissions
guard let fromViewController = startAtLoginVC, let toViewController = permissionsVC else {
assertionFailure()
return
}
guard let fromViewController = finalOnboardingVC, let toViewController = onboardingSearchVC else { transition(from: fromViewController,
assertionFailure() to: toViewController,
return options: .slideRight) {
} self.positiveButton.tag = OnboardingType.permissions.rawValue
self.backButton.tag = OnboardingType.welcome.rawValue
self.negativeButton.isHidden = true
self.positiveButton.title = "Continue"
}
}
transition(from: fromViewController, private func goBackToWelcomeScreen() {
to: toViewController, guard let fromViewController = permissionsVC, let toViewController = welcomeVC else {
options: .slideRight) { assertionFailure()
self.positiveButton.tag = OnboardingType.search.rawValue return
self.backButton.tag = OnboardingType.launchAtLogin.rawValue }
self.positiveButton.title = "Continue"
self.negativeButton.isHidden = true
}
transition(from: fromViewController,
to: toViewController,
options: .slideRight) {
self.positiveButton.tag = OnboardingType.welcome.rawValue
self.backButton.isHidden = true
self.positiveButton.title = "Get Started"
} }
} }

61
Clocker/Onboarding/OnboardingSearchController.swift

@ -200,7 +200,13 @@ class OnboardingSearchController: NSViewController {
} }
} }
private var placeholders: [String] = ["New York", "Los Angeles", "Chicago", "Moscow", "Tokyo", "Istanbul", "Beijing", "Shanghai", "Sao Paulo", "Cairo", "Mexico City", "London", "Seoul", "Copenhagen", "Tel Aviv", "Bern", "San Francisco", "Los Angeles", "Sydney NSW", "Berlin"] private var placeholders: [String] = ["New York", "Los Angeles", "Chicago",
"Moscow", "Tokyo", "Istanbul",
"Beijing", "Shanghai", "Sao Paulo",
"Cairo", "Mexico City", "London",
"Seoul", "Copenhagen", "Tel Aviv",
"Bern", "San Francisco", "Los Angeles",
"Sydney NSW", "Berlin"]
private func setup() { private func setup() {
appName.stringValue = "Quick Add Locations" appName.stringValue = "Quick Add Locations"
@ -278,12 +284,7 @@ class OnboardingSearchController: NSViewController {
self.results = [] self.results = []
if let errorPresent = error { if let errorPresent = error {
if errorPresent.localizedDescription == PreferencesConstants.offlineErrorMessage { self.presentErrorMessage(errorPresent.localizedDescription)
self.setInfoLabel(PreferencesConstants.noInternetConnectivityError)
} else {
self.setInfoLabel(PreferencesConstants.tryAgainMessage)
}
setupForError() setupForError()
return return
} }
@ -302,23 +303,7 @@ class OnboardingSearchController: NSViewController {
return return
} }
for result in searchResults!.results { self.appendResultsToFilteredArray(searchResults!.results)
let location = result.geometry.location
let latitude = location.lat
let longitude = location.lng
let formattedAddress = result.formattedAddress
let totalPackage = [
"latitude": latitude,
"longitude": longitude,
CLTimezoneName: formattedAddress,
CLCustomLabel: formattedAddress,
CLTimezoneID: CLEmptyString,
CLPlaceIdentifier: result.placeId
] as [String: Any]
self.results.append(TimezoneData(with: totalPackage))
}
self.setInfoLabel(CLEmptyString) self.setInfoLabel(CLEmptyString)
@ -327,6 +312,34 @@ class OnboardingSearchController: NSViewController {
}) })
} }
private func presentErrorMessage(_ errorMessage: String) {
if errorMessage == PreferencesConstants.offlineErrorMessage {
self.setInfoLabel(PreferencesConstants.noInternetConnectivityError)
} else {
self.setInfoLabel(PreferencesConstants.tryAgainMessage)
}
}
private func appendResultsToFilteredArray(_ results: [SearchResult.Result]) {
results.forEach {
let location = $0.geometry.location
let latitude = location.lat
let longitude = location.lng
let formattedAddress = $0.formattedAddress
let totalPackage = [
"latitude": latitude,
"longitude": longitude,
CLTimezoneName: formattedAddress,
CLCustomLabel: formattedAddress,
CLTimezoneID: CLEmptyString,
CLPlaceIdentifier: $0.placeId
] as [String: Any]
self.results.append(TimezoneData(with: totalPackage))
}
}
// Extracting this out for tests // Extracting this out for tests
private func decode(from data: Data) -> SearchResult? { private func decode(from data: Data) -> SearchResult? {
let jsonDecoder = JSONDecoder() let jsonDecoder = JSONDecoder()

12
Clocker/Overall App/NetworkManager.swift

@ -10,15 +10,23 @@ class NetworkManager: NSObject {
}() }()
static let internalServerError: NSError = { static let internalServerError: NSError = {
let localizedError = """
There was a problem retrieving your information. Please try again later.
If the problem continues please contact App Support.
"""
let userInfoDictionary: [String: Any] = [NSLocalizedDescriptionKey: "Internal Error", let userInfoDictionary: [String: Any] = [NSLocalizedDescriptionKey: "Internal Error",
NSLocalizedFailureReasonErrorKey: "There was a problem retrieving your information. Please try again later. If the problem continues please contact App Support."] NSLocalizedFailureReasonErrorKey: localizedError]
let error = NSError(domain: "APIError", code: 100, userInfo: userInfoDictionary) let error = NSError(domain: "APIError", code: 100, userInfo: userInfoDictionary)
return error return error
}() }()
static let unableToGenerateURL: NSError = { static let unableToGenerateURL: NSError = {
let localizedError = """
There was a problem searching the location. Please try again later.
If the problem continues please contact App Support.
"""
let userInfoDictionary: [String: Any] = [NSLocalizedDescriptionKey: "Unable to generate URL", let userInfoDictionary: [String: Any] = [NSLocalizedDescriptionKey: "Unable to generate URL",
NSLocalizedFailureReasonErrorKey: "There was a problem searching the location. Please try again later. If the problem continues please contact App Support."] NSLocalizedFailureReasonErrorKey: localizedError]
let error = NSError(domain: "APIError", code: 100, userInfo: userInfoDictionary) let error = NSError(domain: "APIError", code: 100, userInfo: userInfoDictionary)
return error return error
}() }()

4
Clocker/Overall App/Themer.swift

@ -432,6 +432,8 @@ extension Themer {
} }
} }
return themeIndex == .light ? NSColor(deviceRed: 241.0 / 255.0, green: 241.0 / 255.0, blue: 241.0 / 255.0, alpha: 1.0) : NSColor(deviceRed: 42.0 / 255.0, green: 55.0 / 255.0, blue: 62.0 / 255.0, alpha: 1.0) return themeIndex == .light ?
NSColor(deviceRed: 241.0 / 255.0, green: 241.0 / 255.0, blue: 241.0 / 255.0, alpha: 1.0) :
NSColor(deviceRed: 42.0 / 255.0, green: 55.0 / 255.0, blue: 62.0 / 255.0, alpha: 1.0)
} }
} }

2
Clocker/Panel/Data Layer/TimezoneDataOperations.swift

@ -168,7 +168,7 @@ extension TimezoneDataOperations {
return "\(todaysDate(with: sliderValue))\(timeDifference())" return "\(todaysDate(with: sliderValue))\(timeDifference())"
} }
let errorDictionary: [String: Any] = ["Timezone" : dataObject.timezone(), let errorDictionary: [String: Any] = ["Timezone": dataObject.timezone(),
"Current Locale": Locale.autoupdatingCurrent.identifier, "Current Locale": Locale.autoupdatingCurrent.identifier,
"Slider Value": sliderValue, "Slider Value": sliderValue,
"Today's Date": Date()] "Today's Date": Date()]

33
Clocker/Panel/Notes Popover/NotesPopover.swift

@ -278,34 +278,24 @@ class NotesPopover: NSViewController {
private func insertTimezoneInDefaultPreferences() { private func insertTimezoneInDefaultPreferences() {
guard let model = dataObject, var timezones = timezoneObjects else { return } guard let model = dataObject, var timezones = timezoneObjects else { return }
let encodedObject = NSKeyedArchiver.archivedData(withRootObject: model) let encodedObject = NSKeyedArchiver.archivedData(withRootObject: model)
timezones[currentRow] = encodedObject timezones[currentRow] = encodedObject
DataStore.shared().setTimezones(timezones) DataStore.shared().setTimezones(timezones)
} }
private func updateMenubarTitles() { private func updateMenubarTitles() {
guard let model = dataObject, model.isFavourite == 1, var timezones = DataStore.shared().retrieve(key: CLMenubarFavorites) as? [Data] else { return } guard let model = dataObject, model.isFavourite == 1, var timezones = DataStore.shared().retrieve(key: CLMenubarFavorites) as? [Data] else { return }
let menubarIndex = timezones.firstIndex { (menubarLocation) -> Bool in let menubarIndex = timezones.firstIndex { (menubarLocation) -> Bool in
if let convertedObject = TimezoneData.customObject(from: menubarLocation) { if let convertedObject = TimezoneData.customObject(from: menubarLocation) {
return convertedObject.isEqual(dataObject) return convertedObject.isEqual(dataObject)
} }
return false return false
} }
if let index = menubarIndex { if let index = menubarIndex {
let encodedObject = NSKeyedArchiver.archivedData(withRootObject: model) let encodedObject = NSKeyedArchiver.archivedData(withRootObject: model)
timezones[index] = encodedObject timezones[index] = encodedObject
UserDefaults.standard.set(timezones, forKey: CLMenubarFavorites) UserDefaults.standard.set(timezones, forKey: CLMenubarFavorites)
} }
} }
@ -370,7 +360,6 @@ class NotesPopover: NSViewController {
if eventCenter.reminderAccessNotDetermined() { if eventCenter.reminderAccessNotDetermined() {
eventCenter.requestAccess(to: .reminder, completionHandler: { granted in eventCenter.requestAccess(to: .reminder, completionHandler: { granted in
if granted { if granted {
OperationQueue.main.addOperation { OperationQueue.main.addOperation {
self.createReminder() self.createReminder()
@ -402,7 +391,6 @@ class NotesPopover: NSViewController {
private func createReminder() { private func createReminder() {
guard let model = dataObject else { return } guard let model = dataObject else { return }
if setReminderCheckbox.state == .on { if setReminderCheckbox.state == .on {
let eventCenter = EventCenter.sharedCenter() let eventCenter = EventCenter.sharedCenter()
let alertIndex = alertPopupButton.indexOfSelectedItem let alertIndex = alertPopupButton.indexOfSelectedItem
@ -507,29 +495,19 @@ class NotesPopover: NSViewController {
} }
setInitialReminderTime() setInitialReminderTime()
updateTimeFormat() updateTimeFormat()
updateSecondsFormat() updateSecondsFormat()
} }
private func updateTimeFormat() { private func updateTimeFormat() {
if dataObject?.overrideFormat.rawValue == 0 { if let overrideFormat = dataObject?.overrideFormat.rawValue {
timeFormatControl.setSelected(true, forSegment: 0) timeFormatControl.setSelected(true, forSegment: overrideFormat)
} else if dataObject?.overrideFormat.rawValue == 1 {
timeFormatControl.setSelected(true, forSegment: 1)
} else {
timeFormatControl.setSelected(true, forSegment: 2)
} }
} }
private func updateSecondsFormat() { private func updateSecondsFormat() {
if dataObject?.overrideSecondsFormat.rawValue == 0 { if let overrideFormat = dataObject?.overrideSecondsFormat.rawValue {
secondsFormatControl.setSelected(true, forSegment: 0) secondsFormatControl.setSelected(true, forSegment: overrideFormat)
} else if dataObject?.overrideSecondsFormat.rawValue == 1 {
secondsFormatControl.setSelected(true, forSegment: 1)
} else {
secondsFormatControl.setSelected(true, forSegment: 2)
} }
} }
@ -549,13 +527,10 @@ extension NotesPopover: NSTextFieldDelegate {
// We need to do a couple of things if the customLabel is updated // We need to do a couple of things if the customLabel is updated
// 1. Update the userDefaults // 1. Update the userDefaults
// 2. Check if the timezone is displayed in the menubar; if so, update the model // 2. Check if the timezone is displayed in the menubar; if so, update the model
guard let model = dataObject else { return } guard let model = dataObject else { return }
model.setLabel(customLabel.stringValue) model.setLabel(customLabel.stringValue)
insertTimezoneInDefaultPreferences() insertTimezoneInDefaultPreferences()
updateMenubarTitles() updateMenubarTitles()
NotificationCenter.default.post(name: NSNotification.Name.customLabelChanged, NotificationCenter.default.post(name: NSNotification.Name.customLabelChanged,

4
Clocker/Panel/ParentPanelController.swift

@ -536,7 +536,9 @@ class ParentPanelController: NSWindowController {
stride(from: 0, to: preferences.count, by: 1).forEach { stride(from: 0, to: preferences.count, by: 1).forEach {
let current = preferences[$0] let current = preferences[$0]
if $0 < mainTableView.numberOfRows, let cellView = mainTableView.view(atColumn: 0, row: $0, makeIfNecessary: false) as? TimezoneCellView, let model = TimezoneData.customObject(from: current) { if $0 < mainTableView.numberOfRows,
let cellView = mainTableView.view(atColumn: 0, row: $0, makeIfNecessary: false) as? TimezoneCellView,
let model = TimezoneData.customObject(from: current) {
if let futureSliderCell = futureSlider.cell as? CustomSliderCell, futureSliderCell.tracking == true { if let futureSliderCell = futureSlider.cell as? CustomSliderCell, futureSliderCell.tracking == true {
return return
} }

5
Clocker/Panel/UI/BackgroundPanelView.swift

@ -40,7 +40,10 @@ class BackgroundPanelView: NSView {
let xOrdinate = arrowMidX - BackgroundPanelConstants.kArrowHeight - curveOffset let xOrdinate = arrowMidX - BackgroundPanelConstants.kArrowHeight - curveOffset
let yOrdinate = frame.height - BackgroundPanelConstants.kArrowHeight - BackgroundPanelConstants.kBorderWidth let yOrdinate = frame.height - BackgroundPanelConstants.kArrowHeight - BackgroundPanelConstants.kBorderWidth
arrowPath.move(to: NSPoint(x: xOrdinate, y: yOrdinate)) arrowPath.move(to: NSPoint(x: xOrdinate, y: yOrdinate))
arrowPath.relativeCurve(to: NSPoint(x: BackgroundPanelConstants.kArrowHeight + curveOffset, y: BackgroundPanelConstants.kBorderWidth), controlPoint1: NSPoint(x: curveOffset, y: 0), controlPoint2: NSPoint(x: BackgroundPanelConstants.kArrowHeight, y: BackgroundPanelConstants.kArrowHeight)) arrowPath.relativeCurve(to: NSPoint(x: BackgroundPanelConstants.kArrowHeight + curveOffset,
y: BackgroundPanelConstants.kBorderWidth),
controlPoint1: NSPoint(x: curveOffset, y: 0),
controlPoint2: NSPoint(x: BackgroundPanelConstants.kArrowHeight, y: BackgroundPanelConstants.kArrowHeight))
} }
Themer.shared().mainBackgroundColor().setFill() Themer.shared().mainBackgroundColor().setFill()

6
Clocker/Preferences/Appearance/AppearanceViewController.swift

@ -112,7 +112,11 @@ class AppearanceViewController: ParentViewController {
menubarDisplayOptionsLabel.stringValue = "Menubar Display Options" menubarDisplayOptionsLabel.stringValue = "Menubar Display Options"
menubarModeLabel.stringValue = "Menubar Mode" menubarModeLabel.stringValue = "Menubar Mode"
[headerLabel, timeFormatLabel, panelTheme, dayDisplayOptionsLabel, showSliderLabel, showSecondsLabel, showSunriseLabel, largerTextLabel, futureSliderRangeLabel, includeDayLabel, includeDateLabel, includePlaceLabel, menubarDisplayOptionsLabel, appDisplayLabel, menubarModeLabel].forEach { [headerLabel, timeFormatLabel, panelTheme,
dayDisplayOptionsLabel, showSliderLabel, showSecondsLabel,
showSunriseLabel, largerTextLabel, futureSliderRangeLabel,
includeDayLabel, includeDateLabel, includePlaceLabel,
menubarDisplayOptionsLabel, appDisplayLabel, menubarModeLabel].forEach {
$0?.textColor = Themer.shared().mainTextColor() $0?.textColor = Themer.shared().mainTextColor()
} }
} }

10
Clocker/Preferences/Calendar/CalendarViewController.swift

@ -224,7 +224,9 @@ class CalendarViewController: ParentViewController {
showEventsFromLabel.stringValue = "Show events from" showEventsFromLabel.stringValue = "Show events from"
truncateAccessoryLabel.stringValue = "If meeting title is \"Meeting with Neel\" and truncate length is set to 5, text in menubar will appear as \"Meeti...\"" truncateAccessoryLabel.stringValue = "If meeting title is \"Meeting with Neel\" and truncate length is set to 5, text in menubar will appear as \"Meeti...\""
[headerLabel, upcomingEventView, allDayMeetingsLabel, showNextMeetingLabel, nextMeetingAccessoryLabel, truncateTextLabel, showEventsFromLabel, charactersField, truncateAccessoryLabel].forEach { $0?.textColor = Themer.shared().mainTextColor() } [headerLabel, upcomingEventView, allDayMeetingsLabel,
showNextMeetingLabel, nextMeetingAccessoryLabel, truncateTextLabel,
showEventsFromLabel, charactersField, truncateAccessoryLabel].forEach { $0?.textColor = Themer.shared().mainTextColor() }
} }
} }
@ -253,12 +255,14 @@ extension CalendarViewController: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if let currentSource = calendars[row] as? String, let message = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "sourceCellView"), owner: self) as? SourceTableViewCell { if let currentSource = calendars[row] as? String,
let message = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "sourceCellView"), owner: self) as? SourceTableViewCell {
message.sourceName.stringValue = currentSource message.sourceName.stringValue = currentSource
return message return message
} }
if let currentSource = calendars[row] as? CalendarInfo, let calendarCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "calendarCellView"), owner: self) as? CalendarTableViewCell { if let currentSource = calendars[row] as? CalendarInfo,
let calendarCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "calendarCellView"), owner: self) as? CalendarTableViewCell {
calendarCell.calendarName.stringValue = currentSource.calendar.title calendarCell.calendarName.stringValue = currentSource.calendar.title
calendarCell.calendarSelected.state = currentSource.selected ? NSControl.StateValue.on : NSControl.StateValue.off calendarCell.calendarSelected.state = currentSource.selected ? NSControl.StateValue.on : NSControl.StateValue.off
calendarCell.calendarSelected.target = self calendarCell.calendarSelected.target = self

239
Clocker/Preferences/General/PreferencesViewController.swift

@ -479,7 +479,10 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
UserDefaults.standard.set(filteredMenubars, forKey: CLMenubarFavorites) UserDefaults.standard.set(filteredMenubars, forKey: CLMenubarFavorites)
if let appDelegate = NSApplication.shared.delegate as? AppDelegate, let menubarFavourites = DataStore.shared().retrieve(key: CLMenubarFavorites) as? [Data], menubarFavourites.isEmpty, DataStore.shared().shouldDisplay(.showMeetingInMenubar) == false { if let appDelegate = NSApplication.shared.delegate as? AppDelegate,
let menubarFavourites = DataStore.shared().retrieve(key: CLMenubarFavorites) as? [Data],
menubarFavourites.isEmpty,
DataStore.shared().shouldDisplay(.showMeetingInMenubar) == false {
appDelegate.invalidateMenubarTimer(true) appDelegate.invalidateMenubarTimer(true)
} }
@ -532,10 +535,15 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
// Time to display the alert. // Time to display the alert.
NSApplication.shared.activate(ignoringOtherApps: true) NSApplication.shared.activate(ignoringOtherApps: true)
let infoText = """
Multiple timezones occupy space and if macOS determines Clocker is occupying too much space, it'll hide Clocker entirely!
Enable Menubar Compact Mode to fit in more timezones in less space.
"""
let alert = NSAlert() let alert = NSAlert()
alert.showsSuppressionButton = true alert.showsSuppressionButton = true
alert.messageText = "More than one location added to the menubar 😅" alert.messageText = "More than one location added to the menubar 😅"
alert.informativeText = "Multiple timezones occupy space and if macOS determines Clocker is occupying too much space, it'll hide Clocker entirely! Enable Menubar Compact Mode to fit in more timezones in less space." alert.informativeText = infoText
alert.addButton(withTitle: "Enable Compact Mode") alert.addButton(withTitle: "Enable Compact Mode")
alert.addButton(withTitle: "Cancel") alert.addButton(withTitle: "Cancel")
@ -626,13 +634,21 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
} }
if tableColumn.identifier.rawValue == "formattedAddress" { if tableColumn.identifier.rawValue == "formattedAddress" {
return arePlacesSortedInAscendingOrder ? object1.formattedAddress! > object2.formattedAddress! : object1.formattedAddress! < object2.formattedAddress! return arePlacesSortedInAscendingOrder ?
object1.formattedAddress! > object2.formattedAddress! :
object1.formattedAddress! < object2.formattedAddress!
} else { } else {
return arePlacesSortedInAscendingOrder ? object1.customLabel! > object2.customLabel! : object1.customLabel! < object2.customLabel! return arePlacesSortedInAscendingOrder ?
object1.customLabel! > object2.customLabel! :
object1.customLabel! < object2.customLabel!
} }
} }
arePlacesSortedInAscendingOrder ? timezoneTableView.setIndicatorImage(NSImage(named: NSImage.Name("NSDescendingSortIndicator"))!, in: tableColumn) : timezoneTableView.setIndicatorImage(NSImage(named: NSImage.Name("NSAscendingSortIndicator"))!, in: tableColumn) let indicatorImage = arePlacesSortedInAscendingOrder ?
NSImage(named: NSImage.Name("NSDescendingSortIndicator"))! :
NSImage(named: NSImage.Name("NSAscendingSortIndicator"))!
timezoneTableView.setIndicatorImage(indicatorImage, in: tableColumn)
arePlacesSortedInAscendingOrder.toggle() arePlacesSortedInAscendingOrder.toggle()
@ -645,7 +661,7 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
extension PreferencesViewController { extension PreferencesViewController {
@objc private func search() { @objc private func search() {
var searchString = searchField.stringValue let searchString = searchField.stringValue
if searchString.isEmpty { if searchString.isEmpty {
dataTask?.cancel() dataTask?.cancel()
@ -657,8 +673,6 @@ extension PreferencesViewController {
dataTask?.cancel() dataTask?.cancel()
} }
let userPreferredLanguage = Locale.preferredLanguages.first ?? "en-US"
OperationQueue.main.addOperation { OperationQueue.main.addOperation {
if self.availableTimezoneTableView.isHidden { if self.availableTimezoneTableView.isHidden {
self.availableTimezoneTableView.isHidden = false self.availableTimezoneTableView.isHidden = false
@ -675,26 +689,14 @@ extension PreferencesViewController {
self.placeholderLabel.placeholderString = "Searching for \(searchString)" self.placeholderLabel.placeholderString = "Searching for \(searchString)"
let words = searchString.components(separatedBy: CharacterSet.whitespacesAndNewlines) self.dataTask = NetworkManager.task(with: self.generateSearchURL(),
searchString = words.joined(separator: CLEmptyString)
let urlString = "https://maps.googleapis.com/maps/api/geocode/json?address=\(searchString)&key=\(CLGeocodingKey)&language=\(userPreferredLanguage)"
self.dataTask = NetworkManager.task(with: urlString,
completionHandler: { [weak self] response, error in completionHandler: { [weak self] response, error in
guard let `self` = self else { return } guard let `self` = self else { return }
OperationQueue.main.addOperation { OperationQueue.main.addOperation {
if let errorPresent = error { if let errorPresent = error {
if errorPresent.localizedDescription == PreferencesConstants.offlineErrorMessage { self.presentError(errorPresent.localizedDescription)
self.placeholderLabel.placeholderString = PreferencesConstants.noInternetConnectivityError
} else {
self.placeholderLabel.placeholderString = PreferencesConstants.tryAgainMessage
}
self.isActivityInProgress = false
return return
} }
@ -711,35 +713,61 @@ extension PreferencesViewController {
return return
} }
for result in searchResults!.results { self.appendResultsToFilteredArray(searchResults!.results)
let location = result.geometry.location self.prepareUIForPresentingResults()
let latitude = location.lat }
let longitude = location.lng
let formattedAddress = result.formattedAddress
let totalPackage = [
"latitude": latitude,
"longitude": longitude,
CLTimezoneName: formattedAddress,
CLCustomLabel: formattedAddress,
CLTimezoneID: CLEmptyString,
CLPlaceIdentifier: result.placeId
] as [String: Any]
self.filteredArray.append(TimezoneData(with: totalPackage))
}
self.placeholderLabel.placeholderString = CLEmptyString })
}
}
self.isActivityInProgress = false private func generateSearchURL() -> String {
let userPreferredLanguage = Locale.preferredLanguages.first ?? "en-US"
self.availableTimezoneTableView.reloadData() var searchString = searchField.stringValue
} let words = searchString.components(separatedBy: CharacterSet.whitespacesAndNewlines)
searchString = words.joined(separator: CLEmptyString)
}) let url = "https://maps.googleapis.com/maps/api/geocode/json?address=\(searchString)&key=\(CLGeocodingKey)&language=\(userPreferredLanguage)"
return url
}
private func presentError(_ errorMessage: String) {
if errorMessage == PreferencesConstants.offlineErrorMessage {
self.placeholderLabel.placeholderString = PreferencesConstants.noInternetConnectivityError
} else {
self.placeholderLabel.placeholderString = PreferencesConstants.tryAgainMessage
}
self.isActivityInProgress = false
}
private func appendResultsToFilteredArray(_ results: [SearchResult.Result]) {
results.forEach {
let location = $0.geometry.location
let latitude = location.lat
let longitude = location.lng
let formattedAddress = $0.formattedAddress
let totalPackage = [
"latitude": latitude,
"longitude": longitude,
CLTimezoneName: formattedAddress,
CLCustomLabel: formattedAddress,
CLTimezoneID: CLEmptyString,
CLPlaceIdentifier: $0.placeId
] as [String: Any]
self.filteredArray.append(TimezoneData(with: totalPackage))
} }
} }
private func prepareUIForPresentingResults() {
self.placeholderLabel.placeholderString = CLEmptyString
self.isActivityInProgress = false
self.availableTimezoneTableView.reloadData()
}
// Extracting this out for tests // Extracting this out for tests
private func decode(from data: Data) -> SearchResult? { private func decode(from data: Data) -> SearchResult? {
let jsonDecoder = JSONDecoder() let jsonDecoder = JSONDecoder()
@ -802,34 +830,8 @@ extension PreferencesViewController {
if error == nil, let json = response, let timezone = self.decodeTimezone(from: json) { if error == nil, let json = response, let timezone = self.decodeTimezone(from: json) {
if self.availableTimezoneTableView.selectedRow >= 0 && self.availableTimezoneTableView.selectedRow < self.filteredArray.count { if self.availableTimezoneTableView.selectedRow >= 0 && self.availableTimezoneTableView.selectedRow < self.filteredArray.count {
guard let dataObject = self.filteredArray[self.availableTimezoneTableView.selectedRow] as? TimezoneData else { self.installTimezone(timezone)
assertionFailure("Data was unexpectedly nil")
return
}
var filteredAddress = "Error"
if let address = dataObject.formattedAddress {
filteredAddress = address.filteredName()
}
let newTimeZone = [
CLTimezoneID: timezone.timeZoneId,
CLTimezoneName: filteredAddress,
CLPlaceIdentifier: dataObject.placeID!,
"latitude": dataObject.latitude!,
"longitude": dataObject.longitude!,
"nextUpdate": CLEmptyString,
CLCustomLabel: filteredAddress
] as [String: Any]
let timezoneObject = TimezoneData(with: newTimeZone)
let operationsObject = TimezoneDataOperations(with: timezoneObject)
operationsObject.saveObject()
Logger.log(object: ["PlaceName": filteredAddress, "Timezone": timezone.timeZoneId], for: "Filtered Address")
} }
self.updateViewState() self.updateViewState()
} else { } else {
OperationQueue.main.addOperation { OperationQueue.main.addOperation {
@ -846,6 +848,35 @@ extension PreferencesViewController {
} }
} }
private func installTimezone(_ timezone: Timezone) {
guard let dataObject = self.filteredArray[self.availableTimezoneTableView.selectedRow] as? TimezoneData else {
assertionFailure("Data was unexpectedly nil")
return
}
var filteredAddress = "Error"
if let address = dataObject.formattedAddress {
filteredAddress = address.filteredName()
}
let newTimeZone = [
CLTimezoneID: timezone.timeZoneId,
CLTimezoneName: filteredAddress,
CLPlaceIdentifier: dataObject.placeID!,
"latitude": dataObject.latitude!,
"longitude": dataObject.longitude!,
"nextUpdate": CLEmptyString,
CLCustomLabel: filteredAddress
] as [String: Any]
let timezoneObject = TimezoneData(with: newTimeZone)
let operationsObject = TimezoneDataOperations(with: timezoneObject)
operationsObject.saveObject()
Logger.log(object: ["PlaceName": filteredAddress, "Timezone": timezone.timeZoneId], for: "Filtered Address")
}
private func resetStateAndShowDisconnectedMessage() { private func resetStateAndShowDisconnectedMessage() {
OperationQueue.main.addOperation { OperationQueue.main.addOperation {
self.showMessage() self.showMessage()
@ -969,55 +1000,59 @@ extension PreferencesViewController {
} }
} else { } else {
let data = TimezoneData() cleanupAfterInstallingTimezone()
data.setLabel(CLEmptyString) }
}
if searchField.stringValue.isEmpty == false { private func cleanupAfterInstallingTimezone() {
if timezoneFilteredArray.count <= availableTimezoneTableView.selectedRow { let data = TimezoneData()
return data.setLabel(CLEmptyString)
}
let currentSelection = timezoneFilteredArray[availableTimezoneTableView.selectedRow] if searchField.stringValue.isEmpty == false {
if timezoneFilteredArray.count <= availableTimezoneTableView.selectedRow {
return
}
let metaInfo = metadata(for: currentSelection) let currentSelection = timezoneFilteredArray[availableTimezoneTableView.selectedRow]
data.timezoneID = metaInfo.0
data.formattedAddress = metaInfo.1
} else { let metaInfo = metadata(for: currentSelection)
let currentSelection = timezoneArray[availableTimezoneTableView.selectedRow] data.timezoneID = metaInfo.0
data.formattedAddress = metaInfo.1
let metaInfo = metadata(for: currentSelection) } else {
data.timezoneID = metaInfo.0 let currentSelection = timezoneArray[availableTimezoneTableView.selectedRow]
data.formattedAddress = metaInfo.1
}
data.selectionType = .timezone let metaInfo = metadata(for: currentSelection)
data.timezoneID = metaInfo.0
data.formattedAddress = metaInfo.1
}
let operationObject = TimezoneDataOperations(with: data) data.selectionType = .timezone
operationObject.saveObject()
timezoneFilteredArray = [] let operationObject = TimezoneDataOperations(with: data)
operationObject.saveObject()
timezoneArray = [] timezoneFilteredArray = []
availableTimezoneTableView.reloadData() timezoneArray = []
refreshTimezoneTableView() availableTimezoneTableView.reloadData()
refreshTimezoneTableView()
refreshMainTable() refreshMainTable()
timezonePanel.close() timezonePanel.close()
placeholderLabel.placeholderString = CLEmptyString placeholderLabel.placeholderString = CLEmptyString
searchField.stringValue = CLEmptyString searchField.stringValue = CLEmptyString
searchField.placeholderString = "Enter a city, state or country name" searchField.placeholderString = "Enter a city, state or country name"
availableTimezoneTableView.isHidden = false availableTimezoneTableView.isHidden = false
isActivityInProgress = false isActivityInProgress = false
}
} }
private func metadata(for selection: String) -> (String, String) { private func metadata(for selection: String) -> (String, String) {

8
Clocker/Preferences/OneWindowController.swift

@ -35,7 +35,7 @@ class OneWindowController: NSWindowController {
NSAnimationContext.runAnimationGroup({ (context) in NSAnimationContext.runAnimationGroup({ (context) in
context.duration = 1 context.duration = 1
context.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeOut) context.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
self.window?.animator().backgroundColor = Themer.shared().mainBackgroundColor() self.window?.animator().backgroundColor = Themer.shared().mainBackgroundColor()
}) })
@ -60,8 +60,8 @@ class OneWindowController: NSWindowController {
} }
class func shared() -> OneWindowController { class func shared() -> OneWindowController {
if (sharedWindow == nil) { if sharedWindow == nil {
let prefStoryboard = NSStoryboard.init(name: "Preferences", bundle: nil) let prefStoryboard = NSStoryboard.init(name: "Preferences", bundle: nil)
sharedWindow = prefStoryboard.instantiateInitialController() as? OneWindowController sharedWindow = prefStoryboard.instantiateInitialController() as? OneWindowController
} }
return sharedWindow return sharedWindow
@ -95,7 +95,7 @@ class OneWindowController: NSWindowController {
tabViewController.tabViewItems.forEach { (tabViewItem) in tabViewController.tabViewItems.forEach { (tabViewItem) in
let identity = (tabViewItem.identifier as? String) ?? "" let identity = (tabViewItem.identifier as? String) ?? ""
if (identifierTOImageMapping[identity] != nil) { if identifierTOImageMapping[identity] != nil {
tabViewItem.image = identifierTOImageMapping[identity] tabViewItem.image = identifierTOImageMapping[identity]
} }
} }

Loading…
Cancel
Save