Browse Source

Few changes.

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

13
.swiftlint.yml

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

11
Clocker/AppDelegate.swift

@ -98,7 +98,8 @@ open class AppDelegate : NSObject, NSApplicationDelegate {
}()
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()
}
@ -238,10 +239,16 @@ 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
// This breaks start at login! Time to show an alert and terminate
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")
// Terminate

29
Clocker/Events and Reminders/CalendarHandler.swift

@ -228,23 +228,11 @@ extension EventCenter {
}
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 {
eventsForDateMapper[date] = []
}
eventsForDateMapper[date]?.append(eventInfo)
eventsForDateMapper[date]?.append(generateEventInfo(for: event, date, nextDate))
date = nextDate
}
@ -265,6 +253,21 @@ extension EventCenter {
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 {

96
Clocker/Onboarding/OnboardingParentViewController.swift

@ -26,15 +26,15 @@ class OnboardingParentViewController: NSViewController {
@IBOutlet private var backButton: 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() {
super.viewDidLoad()
@ -96,6 +96,19 @@ class OnboardingParentViewController: NSViewController {
@IBAction func continueOnboarding(_: NSButton) {
if positiveButton.tag == OnboardingType.welcome.rawValue {
navigateToPermissions()
} else if positiveButton.tag == OnboardingType.permissions.rawValue {
navigateToStartAtLogin()
} else if positiveButton.tag == OnboardingType.launchAtLogin.rawValue {
navigateToSearch()
} else if positiveButton.tag == OnboardingType.search.rawValue {
navigateToFinalStage()
} else {
performFinalStepsBeforeFinishing()
}
}
private func navigateToPermissions() {
guard let fromViewController = welcomeVC, let toViewController = permissionsVC else {
assertionFailure()
return
@ -110,8 +123,9 @@ class OnboardingParentViewController: NSViewController {
self.positiveButton.title = "Continue"
self.backButton.isHidden = false
}
}
} else if positiveButton.tag == OnboardingType.permissions.rawValue {
private func navigateToStartAtLogin() {
guard let fromViewController = permissionsVC, let toViewController = startAtLoginVC else {
assertionFailure()
return
@ -127,7 +141,9 @@ class OnboardingParentViewController: NSViewController {
self.positiveButton.title = "Open Clocker At Login"
self.negativeButton.isHidden = false
}
} else if positiveButton.tag == OnboardingType.launchAtLogin.rawValue {
}
private func navigateToSearch() {
guard let fromViewController = startAtLoginVC, let toViewController = onboardingSearchVC else {
assertionFailure()
return
@ -145,7 +161,9 @@ class OnboardingParentViewController: NSViewController {
self.positiveButton.title = "Continue"
self.negativeButton.isHidden = true
}
} else if positiveButton.tag == OnboardingType.search.rawValue {
}
private func navigateToFinalStage() {
guard let fromViewController = onboardingSearchVC, let toViewController = finalOnboardingVC else {
assertionFailure()
return
@ -161,8 +179,9 @@ class OnboardingParentViewController: NSViewController {
self.positiveButton.title = "Launch Clocker"
}
} else {
}
private func performFinalStepsBeforeFinishing() {
self.positiveButton.tag = OnboardingType.complete.rawValue
// Install the menubar option!
@ -175,7 +194,6 @@ class OnboardingParentViewController: NSViewController {
UserDefaults.standard.set(true, forKey: CLShowOnboardingFlow)
}
}
}
private func addChildIfNeccessary(_ viewController: NSViewController) {
if children.contains(viewController) == false {
@ -185,22 +203,18 @@ class OnboardingParentViewController: NSViewController {
@IBAction func back(_: Any) {
if backButton.tag == OnboardingType.welcome.rawValue {
guard let fromViewController = permissionsVC, let toViewController = welcomeVC else {
assertionFailure()
return
goBackToWelcomeScreen()
} else if backButton.tag == OnboardingType.permissions.rawValue {
goBackToPermissions()
} else if backButton.tag == OnboardingType.launchAtLogin.rawValue {
goBackToStartAtLogin()
} else if backButton.tag == OnboardingType.search.rawValue {
goBackToSearch()
}
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 {
// We're on StartAtLogin VC and we have to go back to Permissions
guard let fromViewController = startAtLoginVC, let toViewController = permissionsVC else {
private func goBackToSearch() {
guard let fromViewController = finalOnboardingVC, let toViewController = onboardingSearchVC else {
assertionFailure()
return
}
@ -208,12 +222,14 @@ class OnboardingParentViewController: NSViewController {
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.tag = OnboardingType.search.rawValue
self.backButton.tag = OnboardingType.launchAtLogin.rawValue
self.positiveButton.title = "Continue"
self.negativeButton.isHidden = true
}
} else if backButton.tag == OnboardingType.launchAtLogin.rawValue {
}
private func goBackToStartAtLogin() {
guard let fromViewController = onboardingSearchVC, let toViewController = startAtLoginVC else {
assertionFailure()
return
@ -227,9 +243,12 @@ class OnboardingParentViewController: NSViewController {
self.positiveButton.title = "Open Clocker At Login"
self.negativeButton.isHidden = false
}
} else if backButton.tag == OnboardingType.search.rawValue {
}
guard let fromViewController = finalOnboardingVC, let toViewController = onboardingSearchVC else {
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
}
@ -237,12 +256,25 @@ class OnboardingParentViewController: NSViewController {
transition(from: fromViewController,
to: toViewController,
options: .slideRight) {
self.positiveButton.tag = OnboardingType.search.rawValue
self.backButton.tag = OnboardingType.launchAtLogin.rawValue
self.positiveButton.title = "Continue"
self.positiveButton.tag = OnboardingType.permissions.rawValue
self.backButton.tag = OnboardingType.welcome.rawValue
self.negativeButton.isHidden = true
self.positiveButton.title = "Continue"
}
}
private func goBackToWelcomeScreen() {
guard let fromViewController = permissionsVC, let toViewController = welcomeVC else {
assertionFailure()
return
}
transition(from: fromViewController,
to: toViewController,
options: .slideRight) {
self.positiveButton.tag = OnboardingType.welcome.rawValue
self.backButton.isHidden = true
self.positiveButton.title = "Get Started"
}
}

47
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() {
appName.stringValue = "Quick Add Locations"
@ -278,12 +284,7 @@ class OnboardingSearchController: NSViewController {
self.results = []
if let errorPresent = error {
if errorPresent.localizedDescription == PreferencesConstants.offlineErrorMessage {
self.setInfoLabel(PreferencesConstants.noInternetConnectivityError)
} else {
self.setInfoLabel(PreferencesConstants.tryAgainMessage)
}
self.presentErrorMessage(errorPresent.localizedDescription)
setupForError()
return
}
@ -302,11 +303,29 @@ class OnboardingSearchController: NSViewController {
return
}
for result in searchResults!.results {
let location = result.geometry.location
self.appendResultsToFilteredArray(searchResults!.results)
self.setInfoLabel(CLEmptyString)
self.resultsTableView.reloadData()
}
})
}
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 = result.formattedAddress
let formattedAddress = $0.formattedAddress
let totalPackage = [
"latitude": latitude,
@ -314,17 +333,11 @@ class OnboardingSearchController: NSViewController {
CLTimezoneName: formattedAddress,
CLCustomLabel: formattedAddress,
CLTimezoneID: CLEmptyString,
CLPlaceIdentifier: result.placeId
CLPlaceIdentifier: $0.placeId
] as [String: Any]
self.results.append(TimezoneData(with: totalPackage))
}
self.setInfoLabel(CLEmptyString)
self.resultsTableView.reloadData()
}
})
}
// Extracting this out for tests

12
Clocker/Overall App/NetworkManager.swift

@ -10,15 +10,23 @@ class NetworkManager: NSObject {
}()
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",
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)
return error
}()
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",
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)
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)
}
}

33
Clocker/Panel/Notes Popover/NotesPopover.swift

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

5
Clocker/Panel/UI/BackgroundPanelView.swift

@ -40,7 +40,10 @@ class BackgroundPanelView: NSView {
let xOrdinate = arrowMidX - BackgroundPanelConstants.kArrowHeight - curveOffset
let yOrdinate = frame.height - BackgroundPanelConstants.kArrowHeight - BackgroundPanelConstants.kBorderWidth
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()

6
Clocker/Preferences/Appearance/AppearanceViewController.swift

@ -112,7 +112,11 @@ class AppearanceViewController: ParentViewController {
menubarDisplayOptionsLabel.stringValue = "Menubar Display Options"
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()
}
}

10
Clocker/Preferences/Calendar/CalendarViewController.swift

@ -224,7 +224,9 @@ class CalendarViewController: ParentViewController {
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...\""
[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? {
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
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.calendarSelected.state = currentSource.selected ? NSControl.StateValue.on : NSControl.StateValue.off
calendarCell.calendarSelected.target = self

133
Clocker/Preferences/General/PreferencesViewController.swift

@ -479,7 +479,10 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
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)
}
@ -532,10 +535,15 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
// Time to display the alert.
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()
alert.showsSuppressionButton = true
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: "Cancel")
@ -626,13 +634,21 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
}
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 {
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()
@ -645,7 +661,7 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
extension PreferencesViewController {
@objc private func search() {
var searchString = searchField.stringValue
let searchString = searchField.stringValue
if searchString.isEmpty {
dataTask?.cancel()
@ -657,8 +673,6 @@ extension PreferencesViewController {
dataTask?.cancel()
}
let userPreferredLanguage = Locale.preferredLanguages.first ?? "en-US"
OperationQueue.main.addOperation {
if self.availableTimezoneTableView.isHidden {
self.availableTimezoneTableView.isHidden = false
@ -675,26 +689,14 @@ extension PreferencesViewController {
self.placeholderLabel.placeholderString = "Searching for \(searchString)"
let words = searchString.components(separatedBy: CharacterSet.whitespacesAndNewlines)
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,
self.dataTask = NetworkManager.task(with: self.generateSearchURL(),
completionHandler: { [weak self] response, error in
guard let `self` = self else { return }
OperationQueue.main.addOperation {
if let errorPresent = error {
if errorPresent.localizedDescription == PreferencesConstants.offlineErrorMessage {
self.placeholderLabel.placeholderString = PreferencesConstants.noInternetConnectivityError
} else {
self.placeholderLabel.placeholderString = PreferencesConstants.tryAgainMessage
}
self.isActivityInProgress = false
self.presentError(errorPresent.localizedDescription)
return
}
@ -711,11 +713,41 @@ extension PreferencesViewController {
return
}
for result in searchResults!.results {
let location = result.geometry.location
self.appendResultsToFilteredArray(searchResults!.results)
self.prepareUIForPresentingResults()
}
})
}
}
private func generateSearchURL() -> String {
let userPreferredLanguage = Locale.preferredLanguages.first ?? "en-US"
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 = result.formattedAddress
let formattedAddress = $0.formattedAddress
let totalPackage = [
"latitude": latitude,
@ -723,23 +755,19 @@ extension PreferencesViewController {
CLTimezoneName: formattedAddress,
CLCustomLabel: formattedAddress,
CLTimezoneID: CLEmptyString,
CLPlaceIdentifier: result.placeId
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
private func decode(from data: Data) -> SearchResult? {
let jsonDecoder = JSONDecoder()
@ -802,6 +830,25 @@ extension PreferencesViewController {
if error == nil, let json = response, let timezone = self.decodeTimezone(from: json) {
if self.availableTimezoneTableView.selectedRow >= 0 && self.availableTimezoneTableView.selectedRow < self.filteredArray.count {
self.installTimezone(timezone)
}
self.updateViewState()
} else {
OperationQueue.main.addOperation {
if error?.localizedDescription == "The Internet connection appears to be offline." {
self.placeholderLabel.placeholderString = PreferencesConstants.noInternetConnectivityError
} else {
self.placeholderLabel.placeholderString = PreferencesConstants.tryAgainMessage
}
self.isActivityInProgress = false
}
}
}
}
}
private func installTimezone(_ timezone: Timezone) {
guard let dataObject = self.filteredArray[self.availableTimezoneTableView.selectedRow] as? TimezoneData else {
assertionFailure("Data was unexpectedly nil")
return
@ -830,22 +877,6 @@ extension PreferencesViewController {
Logger.log(object: ["PlaceName": filteredAddress, "Timezone": timezone.timeZoneId], for: "Filtered Address")
}
self.updateViewState()
} else {
OperationQueue.main.addOperation {
if error?.localizedDescription == "The Internet connection appears to be offline." {
self.placeholderLabel.placeholderString = PreferencesConstants.noInternetConnectivityError
} else {
self.placeholderLabel.placeholderString = PreferencesConstants.tryAgainMessage
}
self.isActivityInProgress = false
}
}
}
}
}
private func resetStateAndShowDisconnectedMessage() {
OperationQueue.main.addOperation {
self.showMessage()
@ -969,6 +1000,11 @@ extension PreferencesViewController {
}
} else {
cleanupAfterInstallingTimezone()
}
}
private func cleanupAfterInstallingTimezone() {
let data = TimezoneData()
data.setLabel(CLEmptyString)
@ -1018,7 +1054,6 @@ extension PreferencesViewController {
isActivityInProgress = false
}
}
private func metadata(for selection: String) -> (String, String) {
if selection == "Anywhere on Earth" {

4
Clocker/Preferences/OneWindowController.swift

@ -60,7 +60,7 @@ class OneWindowController: NSWindowController {
}
class func shared() -> OneWindowController {
if (sharedWindow == nil) {
if sharedWindow == nil {
let prefStoryboard = NSStoryboard.init(name: "Preferences", bundle: nil)
sharedWindow = prefStoryboard.instantiateInitialController() as? OneWindowController
}
@ -95,7 +95,7 @@ class OneWindowController: NSWindowController {
tabViewController.tabViewItems.forEach { (tabViewItem) in
let identity = (tabViewItem.identifier as? String) ?? ""
if (identifierTOImageMapping[identity] != nil) {
if identifierTOImageMapping[identity] != nil {
tabViewItem.image = identifierTOImageMapping[identity]
}
}

Loading…
Cancel
Save