Browse Source

Merge branch 'master' of https://github.com/n0shake/Clocker

pull/113/head
Abhishek 3 years ago
parent
commit
98cc5607d6
  1. 14
      Clocker/AppDelegate.swift
  2. 4
      Clocker/Clocker/Clocker.entitlements
  3. 3
      Clocker/Clocker/ar.lproj/Localizable.strings
  4. 5
      Clocker/Clocker/ca.lproj/Localizable.strings
  5. 5
      Clocker/Clocker/de.lproj/Localizable.strings
  6. 5
      Clocker/Clocker/en.lproj/Localizable.strings
  7. 5
      Clocker/Clocker/es.lproj/Localizable.strings
  8. 5
      Clocker/Clocker/fr.lproj/Localizable.strings
  9. 5
      Clocker/Clocker/hi.lproj/Localizable.strings
  10. 5
      Clocker/Clocker/hr.lproj/Localizable.strings
  11. 5
      Clocker/Clocker/it.lproj/Localizable.strings
  12. 5
      Clocker/Clocker/ja.lproj/Localizable.strings
  13. 5
      Clocker/Clocker/ko.lproj/Localizable.strings
  14. 5
      Clocker/Clocker/nl.lproj/Localizable.strings
  15. 3
      Clocker/Clocker/pl.lproj/Localizable.strings
  16. 5
      Clocker/Clocker/pt-BR.lproj/Localizable.strings
  17. 5
      Clocker/Clocker/ru.lproj/Localizable.strings
  18. 3
      Clocker/Clocker/tr.lproj/Localizable.strings
  19. 5
      Clocker/Clocker/zh-Hans.lproj/Localizable.strings
  20. 5
      Clocker/Clocker/zh-Hant.lproj/Localizable.strings
  21. 13
      Clocker/ClockerUnitTests/AppDelegateTests.swift
  22. 7
      Clocker/ClockerUnitTests/ClockerUnitTests.swift
  23. 3
      Clocker/ClockerUnitTests/StandardMenubarHandlerTests.swift
  24. 4
      Clocker/Dependencies/Date Additions/Date+TimeAgo.swift
  25. 4
      Clocker/Events and Reminders/CalendarHandler.swift
  26. 8
      Clocker/Onboarding/OnboardingParentViewController.swift
  27. 13
      Clocker/Onboarding/OnboardingSearchController.swift
  28. 43
      Clocker/Overall App/DataStore.swift
  29. 1
      Clocker/Overall App/Strings.swift
  30. 11
      Clocker/Panel/PanelController.swift
  31. 19
      Clocker/Panel/ParentPanelController.swift
  32. 2
      Clocker/Panel/Upcoming Events/UpcomingEventViewItem.swift
  33. 12
      Clocker/Preferences/About/AboutViewController.swift
  34. 6
      Clocker/Preferences/App Feedback/AppFeedbackWindowController.swift
  35. 17
      Clocker/Preferences/Appearance/AppearanceViewController.swift
  36. 19
      Clocker/Preferences/Calendar/CalendarViewController.swift
  37. 2
      Clocker/Preferences/General/PreferencesViewController.swift
  38. 2
      Clocker/Preferences/General/SearchDataSource.swift
  39. 2
      Clocker/Preferences/Menu Bar/MenubarTitleProvider.swift
  40. 1
      Clocker/Preferences/Menu Bar/StatusContainerView.swift
  41. 8
      Clocker/Preferences/Menu Bar/StatusItemHandler.swift
  42. 90
      Clocker/Preferences/Preferences.storyboard

14
Clocker/AppDelegate.swift

@ -8,7 +8,7 @@ import FirebaseCrashlytics
open class AppDelegate: NSObject, NSApplicationDelegate {
private lazy var floatingWindow = FloatingWindowController.shared()
private lazy var panelController = PanelController.shared()
internal lazy var panelController = PanelController(windowNibName: .panel)
private var statusBarHandler: StatusItemHandler!
private var panelObserver: NSKeyValueObservation?
@ -84,7 +84,6 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
let floatingWindow = FloatingWindowController.shared()
floatingWindow.openPreferences(NSButton())
} else {
let panelController = PanelController.shared()
panelController.openPreferences(NSButton())
}
}
@ -107,6 +106,11 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
}
func continueUsually() {
// Cleanup onboarding controller after its done!
if controller != nil {
controller = nil
}
// Check if another instance of the app is already running. If so, then stop this one.
checkIfAppIsAlreadyOpen()
@ -161,12 +165,6 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
}
}
private func showAppAlreadyOpenMessage() {
showAlert(message: "An instance of Clocker is already open 😅",
informativeText: "This instance of Clocker will terminate now.",
buttonTitle: "Close")
}
private func showAlert(message: String, informativeText: String, buttonTitle: String) {
NSApplication.shared.activate(ignoringOtherApps: true)
let alert = NSAlert()

4
Clocker/Clocker/Clocker.entitlements

@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.icloud-container-identifiers</key>
<array/>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>

3
Clocker/Clocker/ar.lproj/Localizable.strings

@ -158,3 +158,6 @@
"New Zealand" = "New Zealand";
"Florida" = "Florida";
"San Francisco" = "San Francisco";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/ca.lproj/Localizable.strings

@ -161,6 +161,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/de.lproj/Localizable.strings

@ -161,6 +161,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/en.lproj/Localizable.strings

@ -165,6 +165,9 @@
"Copied to Clipboard" = "Copied to Clipboard";
// Upcoming Event View
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/es.lproj/Localizable.strings

@ -163,6 +163,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/fr.lproj/Localizable.strings

@ -162,6 +162,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/hi.lproj/Localizable.strings

@ -157,6 +157,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/hr.lproj/Localizable.strings

@ -163,6 +163,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Prijelaz na ljetno računanje vremena dogodit će se za < 24 sata";
"Copied to Clipboard" = "Kopirano u međuspremnik";
"No upcoming events for today!" = "Za danas nema predstojećih događaja!";
"No upcoming events for today!" = "Za danas nema predstojećih događaja 🎉";
"Great going." = "Super.";
"Happy Weekend." = "Uživaj vikend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/it.lproj/Localizable.strings

@ -162,6 +162,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/ja.lproj/Localizable.strings

@ -192,7 +192,7 @@
"No upcoming event." = "No upcoming event.";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
/* Onboarding */
"Open Clocker At Login" = "ログイン時に Clocker を開始";
@ -355,3 +355,6 @@
"start-at-login" = "ログイン時に開始";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/ko.lproj/Localizable.strings

@ -164,6 +164,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉!";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/nl.lproj/Localizable.strings

@ -161,6 +161,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

3
Clocker/Clocker/pl.lproj/Localizable.strings

@ -158,3 +158,6 @@
"New Zealand" = "Nowa Zelandia";
"Florida" = "Floryda";
"San Francisco" = "San Francisco";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/pt-BR.lproj/Localizable.strings

@ -162,6 +162,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/ru.lproj/Localizable.strings

@ -154,6 +154,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

3
Clocker/Clocker/tr.lproj/Localizable.strings

@ -159,3 +159,6 @@ Takvimleri Görüntüle";
"New Zealand" = "New Zealand";
"Florida" = "Florida";
"San Francisco" = "San Francisco";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/zh-Hans.lproj/Localizable.strings

@ -155,6 +155,9 @@
"Daylights Saving transition will occur in < 24 hours" = "Daylights Saving transition will occur in < 24 hours";
"Copied to Clipboard" = "Copied to Clipboard";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
"Great going." = "Great going.";
"Happy Weekend." = "Happy Weekend.";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

5
Clocker/Clocker/zh-Hant.lproj/Localizable.strings

@ -192,7 +192,7 @@
"No upcoming event." = "沒有即將到來的行程";
"No upcoming events for today!" = "No upcoming events for today!";
"No upcoming events for today!" = "No upcoming events for today 🎉";
/* Onboarding */
"Open Clocker At Login" = "在登入時打開 Clocker";
@ -355,3 +355,6 @@
"start-at-login" = "在登入時啟動";
// iCloud
"Enable iCloud Sync" = "Enable iCloud Sync";

13
Clocker/ClockerUnitTests/AppDelegateTests.swift

@ -136,17 +136,4 @@ class AppDelegateTests: XCTestCase {
UserDefaults.standard.set(0, forKey: CLMenubarCompactMode) // Set the menubar mode back to compact
}
func testTogglingPanel() {
UserDefaults.standard.set(1, forKey: CLShowAppInForeground)
let subject = NSApplication.shared.delegate as? AppDelegate
subject?.ping("MockArgument")
UserDefaults.standard.set(0, forKey: CLShowAppInForeground)
let hasActiveGetter = PanelController.shared().hasActivePanel
subject?.ping("MockArgument")
XCTAssertNotEqual(hasActiveGetter, PanelController.shared().hasActivePanel)
}
}

7
Clocker/ClockerUnitTests/ClockerUnitTests.swift

@ -173,7 +173,7 @@ class ClockerUnitTests: XCTestCase {
XCTAssertTrue(operations.timeDifference() == ", 9h 30m ahead", "Difference was unexpectedly: \(operations.timeDifference())")
XCTAssertTrue(californiaOperations.timeDifference() == ", 3h behind", "Difference was unexpectedly: \(californiaOperations.timeDifference())")
XCTAssertTrue(floridaOperations.timeDifference() == "", "Difference was unexpectedly: \(floridaOperations.timeDifference())")
XCTAssertTrue(aucklandOperations.timeDifference() == ", 17h ahead", "Difference was unexpectedly: \(aucklandOperations.timeDifference())")
XCTAssertTrue(aucklandOperations.timeDifference() == ", 16h ahead", "Difference was unexpectedly: \(aucklandOperations.timeDifference())")
XCTAssertTrue(omahaOperations.timeDifference() == ", an hour behind", "Difference was unexpectedly: \(omahaOperations.timeDifference())")
}
@ -407,9 +407,8 @@ class ClockerUnitTests: XCTestCase {
let view = NSView(frame: CGRect.zero)
view.makeToast("Hello, this is a toast")
XCTAssertEqual(view.subviews.first?.accessibilityIdentifier(), "ToastView")
let expectation = expectation(description: "Toast View should hide after 1 second")
let result = XCTWaiter.wait(for: [expectation], timeout: 1.5) // Set 2 seconds here for a little leeway
let toastExpectation = expectation(description: "Toast View should hide after 1 second")
let result = XCTWaiter.wait(for: [toastExpectation], timeout: 1.5) // Set 1.5 seconds here for a little leeway
if result == XCTWaiter.Result.timedOut {
XCTAssertTrue(view.subviews.isEmpty)
}

3
Clocker/ClockerUnitTests/StandardMenubarHandlerTests.swift

@ -28,7 +28,8 @@ class StandardMenubarHandlerTests: XCTestCase {
private func saveObject(object: TimezoneData,
in store: DataStore,
at index: Int = -1) {
at index: Int = -1)
{
var defaults = store.timezones()
let encodedObject = NSKeyedArchiver.archivedData(withRootObject: object as Any)
index == -1 ? defaults.append(encodedObject) : defaults.insert(encodedObject, at: index)

4
Clocker/Dependencies/Date Additions/Date+TimeAgo.swift

@ -115,10 +115,10 @@ public extension Date {
return DateToolsLocalizedStrings("An hour ago")
} else if components.minute! >= 2 {
return logicalLocalizedStringFromFormat(format: "%%d %@minutes ago", value: components.minute!)
return logicalLocalizedStringFromFormat(format: "%%d%@m ago", value: components.minute!)
} else if components.minute! >= 1 {
if numericTimes {
return DateToolsLocalizedStrings("1 minute ago")
return DateToolsLocalizedStrings("1m ago")
}
return DateToolsLocalizedStrings("A minute ago")

4
Clocker/Events and Reminders/CalendarHandler.swift

@ -493,12 +493,12 @@ struct EventInfo {
if timeIntervalSinceNowForMeeting < 0, timeIntervalSinceNowForMeeting > -300 {
return "started \(event.startDate.shortTimeAgoSinceNow) ago."
} else if event.startDate.isToday {
let timeSince = Date().timeAgo(since: event.startDate)
let timeSince = Date().timeAgo(since: event.startDate).lowercased()
let withoutAn = timeSince.replacingOccurrences(of: "an", with: CLEmptyString)
let withoutAgo = withoutAn.replacingOccurrences(of: "ago", with: CLEmptyString)
// If the user has not turned on seconds granularity for one of the timezones,
// we return "in 12 seconds" which looks weird.
return withoutAgo.contains("seconds") ? "starts soon" : "in \(withoutAgo.lowercased())"
return withoutAgo.contains("seconds") ? "started" : "in \(withoutAgo.lowercased())"
} else if event.startDate.isTomorrow {
let hoursUntil = event.startDate.hoursUntil
return "in \(hoursUntil)h"

8
Clocker/Onboarding/OnboardingParentViewController.swift

@ -218,15 +218,15 @@ class OnboardingParentViewController: NSViewController {
func performFinalStepsBeforeFinishing() {
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)
}
// Install the menubar option!
let appDelegate = NSApplication.shared.delegate as? AppDelegate
appDelegate?.continueUsually()
}
private func addChildIfNeccessary(_ viewController: NSViewController) {

13
Clocker/Onboarding/OnboardingSearchController.swift

@ -40,7 +40,6 @@ class OnboardingSearchController: NSViewController {
super.viewDidLoad()
view.wantsLayer = true
searchResultsDataSource = SearchDataSource(with: searchBar, location: .onboarding)
resultsTableView.isHidden = true
resultsTableView.delegate = self
@ -71,6 +70,16 @@ class OnboardingSearchController: NSViewController {
setupUndoButton()
}
override func viewWillAppear() {
super.viewWillAppear()
searchResultsDataSource = SearchDataSource(with: searchBar, location: .onboarding)
}
override func viewWillDisappear() {
super.viewWillDisappear()
searchResultsDataSource = nil
}
deinit {
if let themeDidChangeNotif = themeDidChangeNotification {
NotificationCenter.default.removeObserver(themeDidChangeNotif)
@ -440,7 +449,7 @@ class OnboardingSearchController: NSViewController {
extension OnboardingSearchController: NSTableViewDataSource {
func numberOfRows(in _: NSTableView) -> Int {
return searchResultsDataSource.resultsCount()
return searchResultsDataSource != nil ? searchResultsDataSource.resultsCount() : 0
}
func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? {

43
Clocker/Overall App/DataStore.swift

@ -18,12 +18,13 @@ enum ViewType {
case dayInMenubar
case menubarCompactMode
case dstTransitionInfo
case sync
}
class DataStore: NSObject {
private static var sharedStore = DataStore(with: UserDefaults.standard)
private var userDefaults: UserDefaults!
private var ubiquitousStore: NSUbiquitousKeyValueStore!
private var ubiquitousStore: NSUbiquitousKeyValueStore?
// Since these pref can accessed every second, let's cache this
private var shouldDisplayDayInMenubar: Bool = false
@ -41,9 +42,39 @@ class DataStore: NSObject {
init(with defaults: UserDefaults) {
super.init()
userDefaults = defaults
ubiquitousStore = NSUbiquitousKeyValueStore.default
shouldDisplayDayInMenubar = shouldDisplay(.dayInMenubar)
shouldDisplayDateInMenubar = shouldDisplay(.dateInMenubar)
setupSyncNotification()
}
func setupSyncNotification() {
if shouldDisplay(.sync) {
ubiquitousStore = NSUbiquitousKeyValueStore.default
NotificationCenter.default.addObserver(self,
selector: #selector(ubiquitousKeyValueStoreChanged),
name: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
object: NSUbiquitousKeyValueStore.default)
ubiquitousStore?.synchronize()
} else {
NotificationCenter.default.removeObserver(self,
name: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
object: nil)
}
}
@objc func ubiquitousKeyValueStoreChanged(_ notification: Notification) {
let userInfo = notification.userInfo ?? [:]
let ubiquitousStore = notification.object as? NSUbiquitousKeyValueStore
print("--- User Info is \(userInfo)")
let currentTimezones = userDefaults.object(forKey: CLDefaultPreferenceKey) as? [Data]
let cloudTimezones = ubiquitousStore?.object(forKey: CLDefaultPreferenceKey) as? [Data]
if cloudTimezones != currentTimezones {
Logger.info("Syncing local timezones with data from the ☁")
userDefaults.set(cloudTimezones, forKey: CLDefaultPreferenceKey)
NotificationCenter.default.post(name: DataStore.didSyncFromExternalSourceNotification,
object: self)
}
}
func timezones() -> [Data] {
@ -57,7 +88,7 @@ class DataStore: NSObject {
func setTimezones(_ timezones: [Data]?) {
userDefaults.set(timezones, forKey: CLDefaultPreferenceKey)
// iCloud sync
ubiquitousStore.set(timezones, forKey: CLDefaultPreferenceKey)
ubiquitousStore?.set(timezones, forKey: CLDefaultPreferenceKey)
}
func menubarTimezones() -> [Data]? {
@ -158,6 +189,8 @@ class DataStore: NSObject {
}
return value == 0
case .sync:
return shouldDisplayHelper(CLEnableSyncKey)
}
}
@ -170,3 +203,7 @@ class DataStore: NSObject {
return value.isEqual(to: NSNumber(value: 0))
}
}
extension DataStore {
public static let didSyncFromExternalSourceNotification: NSNotification.Name = .init("didSyncFromExternalSourceNotification")
}

1
Clocker/Overall App/Strings.swift

@ -37,3 +37,4 @@ let CLInstallHomeIndicatorObject = "installHomeIndicatorObject"
let CLSwitchToCompactModeAlert = "com.abhishek.switchToCompactMode"
let CLDisplayDSTTransitionInfo = "com.abhishek.showDSTTransitionInfo"
let CLAppleInterfaceStyleKey = "AppleInterfaceStyle"
let CLEnableSyncKey = "com.abhishek.enableSync"

11
Clocker/Panel/PanelController.swift

@ -6,18 +6,12 @@ import CoreLoggerKit
class PanelController: ParentPanelController {
@objc dynamic var hasActivePanel: Bool = false
static var sharedWindow = PanelController(windowNibName: .panel)
@IBOutlet var backgroundView: BackgroundPanelView!
override func windowDidLoad() {
super.windowDidLoad()
}
class func shared() -> PanelController {
return sharedWindow
}
override func awakeFromNib() {
super.awakeFromNib()
@ -81,6 +75,8 @@ class PanelController: ParentPanelController {
updateDefaultPreferences()
setupUpcomingEventViewCollectionViewIfNeccesary()
if DataStore.shared().timezones().isEmpty || DataStore.shared().shouldDisplay(.futureSlider) == false {
futureSliderView.isHidden = true
modernContainerView.isHidden = true
@ -309,6 +305,9 @@ class PanelController: ParentPanelController {
window?.orderOut(nil)
datasource = nil
upcomingEventsDataSource = nil
parentTimer?.pause()
parentTimer = nil
}
func setActivePanel(newValue: Bool) {

19
Clocker/Panel/ParentPanelController.swift

@ -37,7 +37,7 @@ class ParentPanelController: NSWindowController {
var datasource: TimezoneDataSource?
private lazy var feedbackWindow = AppFeedbackWindowController.shared()
private var feedbackWindow: AppFeedbackWindowController?
private var notePopover: NotesPopover?
@ -195,7 +195,8 @@ class ParentPanelController: NSWindowController {
selector: #selector(systemTimezoneDidChange),
name: NSNotification.Name.NSSystemTimeZoneDidChange,
object: nil)
NotificationCenter.default.addObserver(forName: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
NotificationCenter.default.addObserver(forName: DataStore.didSyncFromExternalSourceNotification,
object: self,
queue: OperationQueue.main)
{ [weak self] _ in
@ -889,9 +890,9 @@ class ParentPanelController: NSWindowController {
} else if sender.title == PanelConstants.yesWithQuestionMark {
ReviewController.prompted()
updateReviewView()
feedbackWindow = AppFeedbackWindowController.shared()
feedbackWindow.showWindow(nil)
feedbackWindow?.appFeedbackWindowDelegate = self
feedbackWindow?.showWindow(nil)
NSApp.activate(ignoringOtherApps: true)
} else {
updateReviewView()
@ -985,7 +986,9 @@ class ParentPanelController: NSWindowController {
}
@objc func reportIssue() {
feedbackWindow.showWindow(nil)
feedbackWindow = AppFeedbackWindowController.shared()
feedbackWindow?.appFeedbackWindowDelegate = self
feedbackWindow?.showWindow(nil)
NSApp.activate(ignoringOtherApps: true)
window?.orderOut(nil)
@ -1146,3 +1149,9 @@ extension ParentPanelController: NSSharingServicePickerDelegate {
return clipboardCopy
}
}
extension ParentPanelController: AppFeedbackWindowControllerDelegate {
func appFeedbackWindowWillClose() {
feedbackWindow = nil
}
}

2
Clocker/Panel/Upcoming Events/UpcomingEventViewItem.swift

@ -90,7 +90,7 @@ class UpcomingEventViewItem: NSCollectionViewItem {
func setupEmptyState() {
let subtitle = NSCalendar.autoupdatingCurrent.isDateInWeekend(Date()) ? NSLocalizedString("Happy Weekend.", comment: "Button Title for no upcoming event") : NSLocalizedString("Great going.", comment: "Button Title for no upcoming event")
setAlternateState(NSLocalizedString("No upcoming events for today 🎉!", comment: "Next Event Label with no upcoming event"),
setAlternateState(NSLocalizedString("No upcoming events for today!", comment: "Next Event Label with no upcoming event"),
subtitle,
NSColor.systemGreen,
nil)

12
Clocker/Preferences/About/AboutViewController.swift

@ -22,7 +22,7 @@ class AboutViewController: ParentViewController {
@IBOutlet var versionField: NSTextField!
private var themeDidChangeNotification: NSObjectProtocol?
private lazy var feedbackWindow = AppFeedbackWindowController.shared()
private var feedbackWindow: AppFeedbackWindowController?
override func viewDidLoad() {
super.viewDidLoad()
@ -120,7 +120,9 @@ class AboutViewController: ParentViewController {
}
@IBAction func reportIssue(_: Any) {
feedbackWindow.showWindow(nil)
feedbackWindow = AppFeedbackWindowController.sharedWindow
feedbackWindow?.appFeedbackWindowDelegate = self
feedbackWindow?.showWindow(nil)
NSApp.activate(ignoringOtherApps: true)
view.window?.orderOut(nil)
@ -150,3 +152,9 @@ class AboutViewController: ParentViewController {
underlineTextForActionButton()
}
}
extension AboutViewController: AppFeedbackWindowControllerDelegate {
func appFeedbackWindowWillClose() {
feedbackWindow = nil
}
}

6
Clocker/Preferences/App Feedback/AppFeedbackWindowController.swift

@ -5,6 +5,10 @@ import CoreLoggerKit
import CoreModelKit
import FirebaseDatabase
protocol AppFeedbackWindowControllerDelegate: AnyObject {
func appFeedbackWindowWillClose()
}
extension NSNib.Name {
static let appFeedbackWindowIdentifier = NSNib.Name("AppFeedbackWindow")
static let onboardingWindowIdentifier = NSNib.Name("OnboardingWindow")
@ -36,6 +40,7 @@ class AppFeedbackWindowController: NSWindowController {
@IBOutlet var progressIndicator: NSProgressIndicator!
@IBOutlet var quickCommentsLabel: PointingHandCursorButton!
public weak var appFeedbackWindowDelegate: AppFeedbackWindowControllerDelegate?
private var themeDidChangeNotification: NSObjectProtocol?
private var serialNumber: String? {
let platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
@ -307,6 +312,7 @@ extension AppFeedbackWindowController: NSWindowDelegate {
emailField.stringValue = CLEmptyString
feedbackTextView.string = CLEmptyString
isActivityInProgress = false
appFeedbackWindowDelegate?.appFeedbackWindowWillClose()
}
func bringPreferencesWindowToFront() {

17
Clocker/Preferences/Appearance/AppearanceViewController.swift

@ -16,6 +16,8 @@ class AppearanceViewController: ParentViewController {
@IBOutlet var includePlaceNameControl: NSSegmentedControl!
@IBOutlet var appearanceTab: NSTabView!
@IBOutlet var appDisplayControl: NSSegmentedControl!
@IBOutlet var syncLabel: NSTextField!
@IBOutlet var syncSegementedControl: NSSegmentedControl!
private var themeDidChangeNotification: NSObjectProtocol?
@ -134,6 +136,10 @@ class AppearanceViewController: ParentViewController {
// True is Menubar Only and False is Menubar + Dock
let appDisplayOptions = DataStore.shared().shouldDisplay(.appDisplayOptions)
appDisplayControl.setSelected(true, forSegment: appDisplayOptions ? 0 : 1)
// Set the Sync value from NSUbiqutousKeyValueStore
let syncEnabled = NSUbiquitousKeyValueStore.default.bool(forKey: CLEnableSyncKey)
syncSegementedControl.setSelected(true, forSegment: syncEnabled ? 0 : 1)
}
@IBOutlet var timeFormatLabel: NSTextField!
@ -150,7 +156,6 @@ class AppearanceViewController: ParentViewController {
@IBOutlet var menubarModeLabel: NSTextField!
@IBOutlet var previewLabel: NSTextField!
@IBOutlet var miscelleaneousLabel: NSTextField!
@IBOutlet var dstTransitionField: NSTextField!
// Panel Preview
@IBOutlet var previewPanelTableView: NSTableView!
@ -162,6 +167,7 @@ class AppearanceViewController: ParentViewController {
showSliderLabel.stringValue = "Time Scroller".localized()
showSunriseLabel.stringValue = "Show Sunrise/Sunset".localized()
largerTextLabel.stringValue = "Larger Text".localized()
syncLabel.stringValue = "Enable iCloud Sync".localized()
futureSliderRangeLabel.stringValue = "Future Slider Range".localized()
includeDateLabel.stringValue = "Include Date".localized()
includeDayLabel.stringValue = "Include Day".localized()
@ -172,9 +178,9 @@ class AppearanceViewController: ParentViewController {
[timeFormatLabel, panelTheme,
dayDisplayOptionsLabel, showSliderLabel,
showSunriseLabel, largerTextLabel, futureSliderRangeLabel,
showSunriseLabel, largerTextLabel, syncLabel, futureSliderRangeLabel,
includeDayLabel, includeDateLabel, includePlaceLabel, appDisplayLabel, menubarModeLabel,
previewLabel, miscelleaneousLabel, dstTransitionField].forEach {
previewLabel, miscelleaneousLabel].forEach {
$0?.textColor = Themer.shared().mainTextColor()
}
@ -353,8 +359,9 @@ class AppearanceViewController: ParentViewController {
previewPanelTableView.reloadData()
}
@IBAction func toggleDSTTransitionOption(_: Any) {
previewPanelTableView.reloadData()
@IBAction func toggleSync(_ sender: NSSegmentedControl) {
NSUbiquitousKeyValueStore.default.set(sender.selectedSegment == 0, forKey: CLEnableSyncKey)
DataStore.shared().setupSyncNotification()
}
}

19
Clocker/Preferences/Calendar/CalendarViewController.swift

@ -5,29 +5,26 @@ import CoreLoggerKit
import EventKit
class ClockerTextBackgroundView: NSView {
private var themeDidChangeNotification: NSObjectProtocol?
override func awakeFromNib() {
wantsLayer = true
layer?.cornerRadius = 8.0
layer?.masksToBounds = false
layer?.backgroundColor = Themer.shared().textBackgroundColor().cgColor
themeDidChangeNotification = NotificationCenter.default.addObserver(forName: .themeDidChangeNotification, object: nil, queue: OperationQueue.main) { _ in
self.layer?.backgroundColor = Themer.shared().textBackgroundColor().cgColor
}
}
deinit {
if let themeDidChangeNotif = themeDidChangeNotification {
NotificationCenter.default.removeObserver(themeDidChangeNotif)
}
NotificationCenter.default.addObserver(self,
selector: #selector(updateBackgroundColor),
name: .themeDidChangeNotification,
object: nil)
}
override func updateLayer() {
super.updateLayer()
layer?.backgroundColor = Themer.shared().textBackgroundColor().cgColor
}
@objc func updateBackgroundColor() {
layer?.backgroundColor = Themer.shared().textBackgroundColor().cgColor
}
}
class CalendarViewController: ParentViewController {

2
Clocker/Preferences/General/PreferencesViewController.swift

@ -93,7 +93,7 @@ class PreferencesViewController: ParentViewController {
name: NSNotification.Name.customLabelChanged,
object: nil)
NotificationCenter.default.addObserver(forName: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
NotificationCenter.default.addObserver(forName: DataStore.didSyncFromExternalSourceNotification,
object: self,
queue: OperationQueue.main)
{ [weak self] _ in

2
Clocker/Preferences/General/SearchDataSource.swift

@ -21,7 +21,7 @@ struct TimezoneMetadata {
}
class SearchDataSource: NSObject {
private var searchField: NSSearchField!
private weak var searchField: NSSearchField!
private var finalArray: [RowType] = []
private var location: SearchLocation = .preferences
private var dataTask: URLSessionDataTask? = .none

2
Clocker/Preferences/Menu Bar/MenubarTitleProvider.swift

@ -9,7 +9,7 @@ class MenubarTitleProvider: NSObject {
private let store: DataStore
init(with dataStore: DataStore) {
self.store = dataStore
store = dataStore
super.init()
}

1
Clocker/Preferences/Menu Bar/StatusContainerView.swift

@ -239,6 +239,7 @@ class StatusContainerView: NSView {
// NSView move animation
NSAnimationContext.runAnimationGroup({ context in
context.duration = 0.2
context.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
let newFrame = CGRect(x: frame.origin.x, y: frame.origin.y, width: newWidth, height: frame.size.height)
// The view will animate to the new origin
self.animator().frame = newFrame

8
Clocker/Preferences/Menu Bar/StatusItemHandler.swift

@ -240,17 +240,15 @@ class StatusItemHandler: NSObject {
}
func updateCompactMenubar() {
if let upcomingEvent = menubarTitleHandler.checkForUpcomingEvents() {
print("Need to construct upcoming event view \(upcomingEvent)")
if menubarTitleHandler.checkForUpcomingEvents() != nil {
// Iterate and see if we're showing the calendar item view
let upcomingEventView = retrieveUpcomingEventStatusView()
// If not, reconstruct Status Container View with another view
if upcomingEventView == nil {
constructCompactView(with: true)
}
} else {
let upcomingEventView = retrieveUpcomingEventStatusView()
upcomingEventView?.removeFromSuperview()
} else if let upcomingEventView = retrieveUpcomingEventStatusView() {
upcomingEventView.removeFromSuperview()
constructCompactView() // So that Status Container View reclaims the space
}
// This will internally call `statusItemViewSetNeedsDisplay` on all subviews ensuring all text in the menubar is up-to-date.

90
Clocker/Preferences/Preferences.storyboard

@ -791,8 +791,8 @@
<gridRow id="YtR-o1-nGp"/>
<gridRow id="vjb-Ch-BZs"/>
<gridRow id="ad4-FM-AWq"/>
<gridRow id="yUG-1W-BQ2"/>
<gridRow id="fbk-ef-Req"/>
<gridRow id="B74-Mt-1h8"/>
</rows>
<columns>
<gridColumn xPlacement="trailing" id="ARE-A4-4k4"/>
@ -924,67 +924,66 @@
</connections>
</segmentedControl>
</gridCell>
<gridCell row="yUG-1W-BQ2" column="ARE-A4-4k4" id="M8P-5s-oL4">
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" preferredMaxLayoutWidth="120" translatesAutoresizingMaskIntoConstraints="NO" id="ZWy-WW-6H9">
<rect key="frame" x="50" y="42" width="163" height="18"/>
<gridCell row="fbk-ef-Req" column="ARE-A4-4k4" id="Vth-MP-nfS">
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" preferredMaxLayoutWidth="120" translatesAutoresizingMaskIntoConstraints="NO" id="xwt-pY-1w9">
<rect key="frame" x="9" y="43" width="204" height="18"/>
<constraints>
<constraint firstAttribute="width" constant="159" id="NX0-Bo-SU8"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="7fj-Em-Lyh"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Show DST transition info" id="i0m-6h-scA">
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Larger Text" id="LOM-yg-tI0">
<font key="font" size="13" name="Avenir-Light"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="yUG-1W-BQ2" column="YBI-pK-gPQ" id="N12-lC-Pe1">
<segmentedControl key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="DCB-IB-UxK">
<rect key="frame" x="229" y="39" width="81" height="24"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="PZZ-H7-LgV">
<font key="font" size="12" name="Avenir-Light"/>
<segments>
<segment label="Yes" width="36"/>
<segment label="No" width="36" selected="YES" tag="1"/>
</segments>
</segmentedCell>
<gridCell row="fbk-ef-Req" column="YBI-pK-gPQ" id="dCk-cz-no0">
<slider key="contentView" verticalHuggingPriority="750" alphaValue="0.59999999999999998" translatesAutoresizingMaskIntoConstraints="NO" id="3cU-IS-3Qu">
<rect key="frame" x="229" y="36" width="104" height="28"/>
<sliderCell key="cell" state="on" alignment="left" minValue="4" maxValue="7" doubleValue="4" tickMarkPosition="above" numberOfTickMarks="4" allowsTickMarkValuesOnly="YES" sliderType="linear" id="eAh-k3-cof"/>
<connections>
<action selector="toggleDSTTransitionOption:" target="1aL-zR-8L4" id="9bi-NL-gMv"/>
<binding destination="Gpv-Gr-MxZ" name="selectedIndex" keyPath="values.com.abhishek.showDSTTransitionInfo" id="eG0-sL-5hE"/>
<action selector="fontSliderChanged:" target="1aL-zR-8L4" id="YAW-aA-5aR"/>
<binding destination="Gpv-Gr-MxZ" name="value" keyPath="values.userFontSize" id="Dzw-Zc-qN5"/>
</connections>
</segmentedControl>
</slider>
</gridCell>
<gridCell row="fbk-ef-Req" column="ARE-A4-4k4" id="Vth-MP-nfS">
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" preferredMaxLayoutWidth="120" translatesAutoresizingMaskIntoConstraints="NO" id="xwt-pY-1w9">
<rect key="frame" x="9" y="1" width="204" height="18"/>
<gridCell row="B74-Mt-1h8" column="ARE-A4-4k4" id="PbY-PK-2xB">
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" preferredMaxLayoutWidth="120" translatesAutoresizingMaskIntoConstraints="NO" id="kkn-L8-yOj">
<rect key="frame" x="9" y="2" width="204" height="18"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="7fj-Em-Lyh"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="eD6-Fv-2tz"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Larger Text" id="LOM-yg-tI0">
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Enable iCloud Sync" id="MDa-w4-4Xw">
<font key="font" size="13" name="Avenir-Light"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="fbk-ef-Req" column="YBI-pK-gPQ" id="dCk-cz-no0">
<slider key="contentView" verticalHuggingPriority="750" alphaValue="0.59999999999999998" translatesAutoresizingMaskIntoConstraints="NO" id="3cU-IS-3Qu">
<rect key="frame" x="229" y="-6" width="104" height="28"/>
<sliderCell key="cell" state="on" alignment="left" minValue="4" maxValue="7" doubleValue="4" tickMarkPosition="above" numberOfTickMarks="4" allowsTickMarkValuesOnly="YES" sliderType="linear" id="eAh-k3-cof"/>
<gridCell row="B74-Mt-1h8" column="YBI-pK-gPQ" id="kVc-I2-8Kp">
<segmentedControl key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ncK-Q6-ag9">
<rect key="frame" x="229" y="-1" width="81" height="24"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="bio-ov-phY">
<font key="font" size="12" name="Avenir-Light"/>
<segments>
<segment label="Yes" width="36"/>
<segment label="No" width="36" selected="YES" tag="1"/>
</segments>
</segmentedCell>
<connections>
<action selector="fontSliderChanged:" target="1aL-zR-8L4" id="YAW-aA-5aR"/>
<binding destination="Gpv-Gr-MxZ" name="value" keyPath="values.userFontSize" id="Dzw-Zc-qN5"/>
<action selector="toggleSync:" target="1aL-zR-8L4" id="4Mg-ie-F7U"/>
</connections>
</slider>
</segmentedControl>
</gridCell>
</gridCells>
</gridView>
<scrollView borderType="line" autohidesScrollers="YES" horizontalLineScroll="113" horizontalPageScroll="10" verticalLineScroll="113" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ytg-0u-Mtu">
<rect key="frame" x="70" y="39" width="400" height="100"/>
<clipView key="contentView" ambiguous="YES" id="gnX-f5-31D">
<clipView key="contentView" id="gnX-f5-31D">
<rect key="frame" x="1" y="1" width="398" height="98"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="111" rowSizeStyle="automatic" viewBased="YES" id="KbJ-p4-i6E">
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="111" rowSizeStyle="automatic" viewBased="YES" id="KbJ-p4-i6E">
<rect key="frame" x="0.0" y="0.0" width="412" height="113"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
@ -1468,7 +1467,6 @@
<outlet property="appDisplayLabel" destination="HNj-dh-8gr" id="A6U-gp-sje"/>
<outlet property="appearanceTab" destination="SGu-yd-JQh" id="CJn-3E-Ujd"/>
<outlet property="dayDisplayOptionsLabel" destination="gFE-hZ-J92" id="tVv-pC-MSW"/>
<outlet property="dstTransitionField" destination="ZWy-WW-6H9" id="psJ-Wm-6Re"/>
<outlet property="futureSliderRangeLabel" destination="GaR-Qm-7u4" id="0aB-BK-7fN"/>
<outlet property="includeDateInMenubarControl" destination="Axn-Tb-Cdx" id="M5x-Qt-zvs"/>
<outlet property="includeDateLabel" destination="fTA-lS-4wJ" id="J1i-yl-JmT"/>
@ -1487,6 +1485,8 @@
<outlet property="showSliderLabel" destination="8Jv-Cf-blJ" id="UHb-hK-VVl"/>
<outlet property="showSunriseLabel" destination="4lt-X6-3uU" id="tez-s5-RzL"/>
<outlet property="sliderDayRangePopup" destination="8Nx-Xq-XDU" id="PBM-yB-Yo1"/>
<outlet property="syncLabel" destination="kkn-L8-yOj" id="egW-Df-fnH"/>
<outlet property="syncSegementedControl" destination="ncK-Q6-ag9" id="8oT-zA-Ms5"/>
<outlet property="theme" destination="89w-KN-GJ6" id="SAL-Sh-eqp"/>
<outlet property="timeFormat" destination="iiG-Xu-4id" id="oM3-1Y-fAF"/>
<outlet property="timeFormatLabel" destination="wtO-uL-QBf" id="udS-d6-Tep"/>
@ -1513,7 +1513,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<searchField toolTip="Search a timezone" wantsLayer="YES" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Dha-h9-Nd0">
<rect key="frame" x="8" y="205" width="320" height="23"/>
<rect key="frame" x="8" y="121" width="320" height="23"/>
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" focusRingType="none" placeholderString="Enter a city, state, country name" usesSingleLineMode="YES" maximumRecents="5" id="ikU-Tm-0WZ">
<font key="font" size="13" name="Avenir-Light"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -1570,13 +1570,13 @@ DQ
</connections>
</button>
<scrollView focusRingType="none" borderType="none" autohidesScrollers="YES" horizontalLineScroll="32" horizontalPageScroll="10" verticalLineScroll="32" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0wY-ff-FLW">
<rect key="frame" x="8" y="30" width="320" height="165"/>
<rect key="frame" x="8" y="30" width="320" height="81"/>
<clipView key="contentView" drawsBackground="NO" id="rGc-3M-cCq">
<rect key="frame" x="0.0" y="0.0" width="320" height="165"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="81"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" rowHeight="30" rowSizeStyle="automatic" viewBased="YES" id="xkl-2X-ZCb">
<rect key="frame" x="0.0" y="0.0" width="320" height="165"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="81"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -1666,14 +1666,14 @@ DQ
</scroller>
</scrollView>
<progressIndicator wantsLayer="YES" focusRingType="none" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="0A5-gp-lay">
<rect key="frame" x="160" y="132" width="16" height="16"/>
<rect key="frame" x="160" y="90" width="16" height="16"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="fgE-77-Vda"/>
<constraint firstAttribute="width" constant="16" id="pwe-em-e0a"/>
</constraints>
</progressIndicator>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xgb-wU-8RU">
<rect key="frame" x="18" y="102" width="300" height="22"/>
<rect key="frame" x="18" y="60" width="300" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" id="zqt-d8-yas"/>
</constraints>
@ -1721,7 +1721,7 @@ DQ
<rect key="frame" x="0.0" y="484" width="613" height="30"/>
<subviews>
<button toolTip="Sorts by time difference from your current timezone" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="P6d-qq-ycq">
<rect key="frame" x="285" y="3" width="8" height="25"/>
<rect key="frame" x="283" y="3" width="9" height="25"/>
<constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="180" id="cAs-on-f7X"/>
<constraint firstAttribute="height" constant="25" id="juv-QL-vMx"/>
@ -1736,7 +1736,7 @@ DQ
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0HL-uj-s4v">
<rect key="frame" x="331" y="3" width="8" height="25"/>
<rect key="frame" x="331" y="3" width="9" height="25"/>
<constraints>
<constraint firstAttribute="height" constant="25" id="eZL-Gr-38S"/>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="120" id="sJk-T7-7Lm"/>
@ -1751,7 +1751,7 @@ DQ
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6fs-Mx-NcG">
<rect key="frame" x="308" y="3" width="8" height="25"/>
<rect key="frame" x="307" y="3" width="9" height="25"/>
<constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="190" id="241-Rn-G6N"/>
<constraint firstAttribute="height" constant="25" id="weP-ll-vZ8"/>
@ -2010,7 +2010,7 @@ CA
<image name="ClockerIcon-512" width="1024" height="1024"/>
<image name="CurrentLocation" width="350" height="350"/>
<image name="Extra" width="700" height="700"/>
<image name="NSDescendingSortIndicator" width="8" height="8"/>
<image name="NSDescendingSortIndicator" width="9" height="9"/>
<image name="NSInfo" width="32" height="32"/>
<image name="NSPreferencesGeneral" width="32" height="32"/>
<image name="Privacy" width="350" height="350"/>

Loading…
Cancel
Save