Browse Source

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

pull/101/head
Abhishek 4 years ago
parent
commit
30af3b1426
  1. 8
      Clocker/AppDelegate.swift
  2. 38
      Clocker/Clocker.xcodeproj/project.pbxproj
  3. 4
      Clocker/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  4. 2
      Clocker/ClockerUITests/AboutUsTests.swift
  5. 38
      Clocker/ClockerUITests/CopyToClipboardTests.swift
  6. 2
      Clocker/ClockerUITests/FloatingWindowTests.swift
  7. 8
      Clocker/ClockerUITests/PreferencesTest.swift
  8. 3
      Clocker/ClockerUnitTests/ClockerUnitTests.swift
  9. 16
      Clocker/CoreModelKit/Sources/CoreModelKit/TimezoneData.swift
  10. 6
      Clocker/Dependencies/Date Additions/TimePeriodChain.swift
  11. 6
      Clocker/Dependencies/Solar.swift
  12. 12
      Clocker/Events and Reminders/CalendarHandler.swift
  13. 1
      Clocker/Events and Reminders/EventCenter.swift
  14. 3
      Clocker/Events and Reminders/RemindersHandler.swift
  15. 2
      Clocker/Menu Bar/MenubarHandler.swift
  16. 9
      Clocker/Menu Bar/StatusContainerView.swift
  17. 2
      Clocker/Menu Bar/StatusItemHandler.swift
  18. 5
      Clocker/Menu Bar/StatusItemView.swift
  19. 6
      Clocker/Onboarding/FinalOnboardingViewController.swift
  20. 5
      Clocker/Onboarding/OnboardingSearchController.swift
  21. 6
      Clocker/Overall App/DateFormatterManager.swift
  22. 6
      Clocker/Overall App/Foundation + Additions.swift
  23. 3
      Clocker/Overall App/NetworkManager.swift
  24. 4
      Clocker/Overall App/Reach.swift
  25. 2
      Clocker/Overall App/VersionUpdateHandler.swift
  26. 20
      Clocker/Panel/Data Layer/TimezoneDataOperations.swift
  27. 2
      Clocker/Panel/FloatingWindowController.swift
  28. 12
      Clocker/Panel/Notes Popover/NotesPopover.swift
  29. 8
      Clocker/Panel/PanelController.swift
  30. 1
      Clocker/Panel/ParentPanelController+ModernSlider.swift
  31. 21
      Clocker/Panel/ParentPanelController.swift
  32. 5
      Clocker/Panel/UI/TimezoneCellView.swift
  33. 84
      Clocker/Panel/UI/Toasty.swift
  34. 8
      Clocker/Preferences/App Feedback/AppFeedbackWindowController.swift
  35. 5
      Clocker/Preferences/Appearance/AppearanceViewController.swift
  36. 6
      Clocker/Preferences/Calendar/CalendarViewController.swift
  37. 3
      Clocker/Preferences/General/PreferencesDataSource.swift
  38. 31
      Clocker/Preferences/General/PreferencesViewController.swift
  39. 2
      Clocker/Preferences/General/SearchDataSource.swift
  40. 2
      Clocker/Preferences/Menu Bar/MenubarHandler.swift
  41. 9
      Clocker/Preferences/Menu Bar/StatusContainerView.swift
  42. 2
      Clocker/Preferences/Menu Bar/StatusItemHandler.swift
  43. 5
      Clocker/Preferences/Menu Bar/StatusItemView.swift

8
Clocker/AppDelegate.swift

@ -7,8 +7,8 @@ import FirebaseCore
import FirebaseCrashlytics import FirebaseCrashlytics
open class AppDelegate: NSObject, NSApplicationDelegate { open class AppDelegate: NSObject, NSApplicationDelegate {
private lazy var floatingWindow: FloatingWindowController = FloatingWindowController.shared() private lazy var floatingWindow = FloatingWindowController.shared()
private lazy var panelController: PanelController = PanelController.shared() private lazy var panelController = PanelController.shared()
private var statusBarHandler: StatusItemHandler! private var statusBarHandler: StatusItemHandler!
private var panelObserver: NSKeyValueObservation? private var panelObserver: NSKeyValueObservation?
@ -16,7 +16,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?) { override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) {
if let path = keyPath, path == PreferencesConstants.hotKeyPathIdentifier { if let path = keyPath, path == PreferencesConstants.hotKeyPathIdentifier {
let hotKeyCenter = PTHotKeyCenter.shared() let hotKeyCenter = PTHotKeyCenter.shared()
@ -30,7 +30,7 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
} }
// Register new key // Register new key
let newHotKey: PTHotKey = PTHotKey(identifier: keyPath, let newHotKey = PTHotKey(identifier: keyPath,
keyCombo: newShortcut, keyCombo: newShortcut,
target: self, target: self,
action: #selector(ping(_:))) action: #selector(ping(_:)))

38
Clocker/Clocker.xcodeproj/project.pbxproj

@ -22,7 +22,6 @@
3531F7F126936DE900DF0111 /* upload-symbols in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7EC26936DE900DF0111 /* upload-symbols */; }; 3531F7F126936DE900DF0111 /* upload-symbols in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7EC26936DE900DF0111 /* upload-symbols */; };
3531F7F226936DE900DF0111 /* upload-symbols in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7EC26936DE900DF0111 /* upload-symbols */; }; 3531F7F226936DE900DF0111 /* upload-symbols in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7EC26936DE900DF0111 /* upload-symbols */; };
3531F7F52693882300DF0111 /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7F42693882300DF0111 /* Keys.plist */; }; 3531F7F52693882300DF0111 /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7F42693882300DF0111 /* Keys.plist */; };
3531F7F62693882300DF0111 /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7F42693882300DF0111 /* Keys.plist */; };
3531F7F72693882300DF0111 /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7F42693882300DF0111 /* Keys.plist */; }; 3531F7F72693882300DF0111 /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3531F7F42693882300DF0111 /* Keys.plist */; };
3531F80626938D7700DF0111 /* GoogleUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3531F7FC26938D7600DF0111 /* GoogleUtilities.framework */; }; 3531F80626938D7700DF0111 /* GoogleUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3531F7FC26938D7600DF0111 /* GoogleUtilities.framework */; };
3531F80726938D7700DF0111 /* GoogleUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3531F7FC26938D7600DF0111 /* GoogleUtilities.framework */; }; 3531F80726938D7700DF0111 /* GoogleUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3531F7FC26938D7600DF0111 /* GoogleUtilities.framework */; };
@ -216,13 +215,6 @@
remoteGlobalIDString = E273122E1349EC9000A84433; remoteGlobalIDString = E273122E1349EC9000A84433;
remoteInfo = PTHotKey.framework; remoteInfo = PTHotKey.framework;
}; };
9A86E2BF1CE04F1600547EE7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 9A86E2B51CE04F1600547EE7 /* ShortcutRecorder.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 0D6B2468180304DE00CE1142;
remoteInfo = Demo;
};
C20839CC21515C1F00C86589 /* PBXContainerItemProxy */ = { C20839CC21515C1F00C86589 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = DD4F7BFB13C30F9F00825C6E /* Project object */; containerPortal = DD4F7BFB13C30F9F00825C6E /* Project object */;
@ -769,7 +761,6 @@
children = ( children = (
9A86E2BC1CE04F1600547EE7 /* ShortcutRecorder.framework */, 9A86E2BC1CE04F1600547EE7 /* ShortcutRecorder.framework */,
9A86E2BE1CE04F1600547EE7 /* PTHotKey.framework */, 9A86E2BE1CE04F1600547EE7 /* PTHotKey.framework */,
9A86E2C01CE04F1600547EE7 /* Demo.app */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -842,6 +833,14 @@
path = Frameworks; path = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
9AEF66812693A6270036142F /* Recovered References */ = {
isa = PBXGroup;
children = (
3531F7F42693882300DF0111 /* Keys.plist */,
);
name = "Recovered References";
sourceTree = "<group>";
};
C2021B89219F30960036C247 /* Onboarding */ = { C2021B89219F30960036C247 /* Onboarding */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -916,6 +915,7 @@
3531F7EC26936DE900DF0111 /* upload-symbols */, 3531F7EC26936DE900DF0111 /* upload-symbols */,
3531F7C026936C6E00DF0111 /* GoogleService-Info.plist */, 3531F7C026936C6E00DF0111 /* GoogleService-Info.plist */,
DD4F7C0513C30F9F00825C6E /* Products */, DD4F7C0513C30F9F00825C6E /* Products */,
9AEF66812693A6270036142F /* Recovered References */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@ -1032,7 +1032,6 @@
DD4F7C0213C30F9F00825C6E /* Resources */, DD4F7C0213C30F9F00825C6E /* Resources */,
9A20A0711C4E808500FB45AB /* Login Item Helper */, 9A20A0711C4E808500FB45AB /* Login Item Helper */,
9A5E75EC204CC39700119939 /* Embed Frameworks */, 9A5E75EC204CC39700119939 /* Embed Frameworks */,
C2A632A020EAC5EE00EB6BEA /* SwiftFormat */,
3531F7F326936F5000DF0111 /* ShellScript */, 3531F7F326936F5000DF0111 /* ShellScript */,
); );
buildRules = ( buildRules = (
@ -1156,13 +1155,6 @@
remoteRef = 9A86E2BD1CE04F1600547EE7 /* PBXContainerItemProxy */; remoteRef = 9A86E2BD1CE04F1600547EE7 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
9A86E2C01CE04F1600547EE7 /* Demo.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = Demo.app;
remoteRef = 9A86E2BF1CE04F1600547EE7 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */ /* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */ /* Begin PBXResourcesBuildPhase section */
@ -1559,7 +1551,7 @@
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 94; CURRENT_PROJECT_VERSION = 95;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@ -1592,7 +1584,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 21.07.01; MARKETING_VERSION = 21.07.02;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = com.abhishek.Clocker; PRODUCT_BUNDLE_IDENTIFIER = com.abhishek.Clocker;
@ -2128,7 +2120,7 @@
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 94; CURRENT_PROJECT_VERSION = 95;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
@ -2162,7 +2154,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 21.07.01; MARKETING_VERSION = 21.07.02;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
"OTHER_SWIFT_FLAGS[arch=*]" = "-D DEBUG"; "OTHER_SWIFT_FLAGS[arch=*]" = "-D DEBUG";
@ -2210,7 +2202,7 @@
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 94; CURRENT_PROJECT_VERSION = 95;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@ -2243,7 +2235,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 21.07.01; MARKETING_VERSION = 21.07.02;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
"OTHER_SWIFT_FLAGS[arch=*]" = "-D RELEASE"; "OTHER_SWIFT_FLAGS[arch=*]" = "-D RELEASE";

4
Clocker/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@ -27,8 +27,8 @@
endingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807"
startingLineNumber = "47" startingLineNumber = "47"
endingLineNumber = "47" endingLineNumber = "47"
landmarkName = "geocodingKey" landmarkName = "unknown"
landmarkType = "24"> landmarkType = "0">
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
</Breakpoints> </Breakpoints>

2
Clocker/ClockerUITests/AboutUsTests.swift

@ -33,7 +33,7 @@ class AboutUsTests: XCTestCase {
tapAboutTab() tapAboutTab()
let appDisplayName = "CFBundleDisplayName".localizedString() let appDisplayName = "CFBundleDisplayName".localizedString()
let expectedVersion = "\(appDisplayName) 21.07.01 (93)" let expectedVersion = "\(appDisplayName) 21.07.02 (95)"
guard let presentVersion = app.windows["Clocker"].staticTexts["ClockerVersion"].value as? String else { guard let presentVersion = app.windows["Clocker"].staticTexts["ClockerVersion"].value as? String else {
XCTFail("Present version not present") XCTFail("Present version not present")

38
Clocker/ClockerUITests/CopyToClipboardTests.swift

@ -10,10 +10,10 @@ class CopyToClipboardTests: XCTestCase {
app = XCUIApplication() app = XCUIApplication()
app.launch() app.launch()
if app.tables["FloatingTableView"].exists == false { // if app.tables["FloatingTableView"].exists == false {
app.tapMenubarIcon() // app.tapMenubarIcon()
app.buttons["Pin"].click() // app.buttons["Pin"].click()
} // }
} }
override func tearDownWithError() throws { override func tearDownWithError() throws {
@ -23,7 +23,7 @@ class CopyToClipboardTests: XCTestCase {
func testFullCopy() throws { func testFullCopy() throws {
let cellCount = app.tables["FloatingTableView"].cells.count let cellCount = app.tables["FloatingTableView"].cells.count
var clipboardValue = String() var clipboardValue = String()
for cellIndex in 0..<cellCount { for cellIndex in 0 ..< cellCount {
let cell = app.tables["FloatingTableView"].cells.element(boundBy: cellIndex) let cell = app.tables["FloatingTableView"].cells.element(boundBy: cellIndex)
let customLabel = cell.staticTexts["CustomNameLabelForCell"].value ?? "Nil Custom Label" let customLabel = cell.staticTexts["CustomNameLabelForCell"].value ?? "Nil Custom Label"
let time = cell.staticTexts["ActualTime"].value ?? "Nil Value" let time = cell.staticTexts["ActualTime"].value ?? "Nil Value"
@ -31,7 +31,7 @@ class CopyToClipboardTests: XCTestCase {
} }
app.buttons["Share"].click() app.buttons["Share"].click()
app/*@START_MENU_TOKEN@*/.menuItems["Copy All Times"]/*[[".dialogs[\"Clocker Panel\"]",".buttons[\"Share\"]",".menus.menuItems[\"Copy All Times\"]",".menuItems[\"Copy All Times\"]"],[[[-1,3],[-1,2],[-1,1,2],[-1,0,1]],[[-1,3],[-1,2],[-1,1,2]],[[-1,3],[-1,2]]],[0]]@END_MENU_TOKEN@*/.click() app/*@START_MENU_TOKEN@*/ .menuItems["Copy All Times"]/*[[".dialogs[\"Clocker Panel\"]",".buttons[\"Share\"]",".menus.menuItems[\"Copy All Times\"]",".menuItems[\"Copy All Times\"]"],[[[-1,3],[-1,2],[-1,1,2],[-1,0,1]],[[-1,3],[-1,2],[-1,1,2]],[[-1,3],[-1,2]]],[0]]@END_MENU_TOKEN@*/ .click()
let clipboard = NSPasteboard.general.string(forType: .string) let clipboard = NSPasteboard.general.string(forType: .string)
XCTAssert(clipboardValue == clipboard) XCTAssert(clipboardValue == clipboard)
@ -50,4 +50,30 @@ class CopyToClipboardTests: XCTestCase {
XCTAssert(expectedValue == clipboard, "Clipboard value (\(clipboard)) doesn't match expected result") XCTAssert(expectedValue == clipboard, "Clipboard value (\(clipboard)) doesn't match expected result")
} }
func testModernSlider() {
if app.buttons["FloatingPin"].exists {
app.buttons["FloatingPin"].click()
}
app.tapMenubarIcon()
let modernSliderExists = app.collectionViews["ModernSlider"].exists
app.buttons["Preferences"].click()
let appearanceTab = app.toolbars.buttons.element(boundBy: 1)
appearanceTab.click()
let miscTab = app.tabs.element(boundBy: 1)
miscTab.click()
if modernSliderExists {
app.radioGroups["FutureSlider"].radioButtons["Legacy"].click()
} else {
app.radioGroups["FutureSlider"].radioButtons["Modern"].click()
}
app.tapMenubarIcon()
let newFloatingSliderExists = app.collectionViews["ModernSlider"].exists
XCTAssertNotEqual(newFloatingSliderExists, modernSliderExists)
}
} }

2
Clocker/ClockerUITests/FloatingWindowTests.swift

@ -24,7 +24,7 @@ class FloatingWindowTests: XCTestCase {
app.buttons["Pin"].click() app.buttons["Pin"].click()
} }
addUIInterruptionMonitor(withDescription: "Reminders Access") { (alert) -> Bool in addUIInterruptionMonitor(withDescription: "Reminders Access") { alert -> Bool in
let alertButton = alert.buttons["OK"] let alertButton = alert.buttons["OK"]
if alertButton.exists { if alertButton.exists {
alertButton.tap() alertButton.tap()

8
Clocker/ClockerUITests/PreferencesTest.swift

@ -31,7 +31,7 @@ class PreferencesTest: XCTestCase {
return return
} }
app.windows["Clocker"].tables["TimezoneTableView"].tableRows.firstMatch.click() app.windows["Clocker"].tables["TimezoneTableView"].tableRows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)).click()
XCTAssertTrue(app.checkBoxes["DeleteTimezone"].isEnabled) XCTAssertTrue(app.checkBoxes["DeleteTimezone"].isEnabled)
} }
@ -334,7 +334,7 @@ class PreferencesTest: XCTestCase {
if rowQueryCount > 0 { if rowQueryCount > 0 {
// Table Rows aren't hittable in Xcode 12.0 (10/7/20) and so we need to find a closer co-ordinate and perform click() // Table Rows aren't hittable in Xcode 12.0 (10/7/20) and so we need to find a closer co-ordinate and perform click()
let currentElement = clockerWindow.tables["TimezoneTableView"].tableRows.firstMatch let currentElement = clockerWindow.tables["TimezoneTableView"].tableRows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))
currentElement.click() currentElement.click()
for _ in 0 ..< rowQueryCount { for _ in 0 ..< rowQueryCount {
@ -416,7 +416,7 @@ extension XCTestCase {
return return
} }
let currentElement = app.windows["Clocker"].tableRows.firstMatch let currentElement = app.windows["Clocker"].tableRows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))
currentElement.click() currentElement.click()
while rowQueryCount > 0 { while rowQueryCount > 0 {
@ -442,7 +442,7 @@ extension XCTestCase {
} }
private func deleteAtRow(_ rowToDelete: XCUIElement, for _: XCUIApplication, shouldSleep: Bool) { private func deleteAtRow(_ rowToDelete: XCUIElement, for _: XCUIApplication, shouldSleep: Bool) {
rowToDelete.click() rowToDelete.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)).click()
rowToDelete.typeKey(XCUIKeyboardKey.delete, modifierFlags: XCUIElement.KeyModifierFlags()) rowToDelete.typeKey(XCUIKeyboardKey.delete, modifierFlags: XCUIElement.KeyModifierFlags())
if shouldSleep { if shouldSleep {
sleep(2) sleep(2)

3
Clocker/ClockerUnitTests/ClockerUnitTests.swift

@ -288,7 +288,8 @@ class ClockerUnitTests: XCTestCase {
guard let newDate = cal?.date(byAdding: .minute, guard let newDate = cal?.date(byAdding: .minute,
value: 0, value: 0,
to: Date(), to: Date(),
options: .matchFirst) else { options: .matchFirst)
else {
XCTFail("Unable to add dates!") XCTFail("Unable to add dates!")
return return
} }

16
Clocker/CoreModelKit/Sources/CoreModelKit/TimezoneData.swift

@ -11,7 +11,7 @@ struct ModelConstants {
static let emptyString = "" static let emptyString = ""
} }
public struct DateFormat { public enum DateFormat {
public static let twelveHour = "h:mm a" public static let twelveHour = "h:mm a"
public static let twelveHourWithSeconds = "h:mm:ss a" public static let twelveHourWithSeconds = "h:mm:ss a"
public static let twentyFourHour = "HH:mm" public static let twentyFourHour = "HH:mm"
@ -82,7 +82,7 @@ public class TimezoneData: NSObject, NSCoding {
public var isSystemTimezone = false public var isSystemTimezone = false
public var overrideFormat: TimezoneOverride = .globalFormat public var overrideFormat: TimezoneOverride = .globalFormat
public override init() { override public init() {
selectionType = .timezone selectionType = .timezone
isFavourite = 0 isFavourite = 0
note = ModelConstants.emptyString note = ModelConstants.emptyString
@ -338,7 +338,7 @@ public class TimezoneData: NSObject, NSCoding {
return formatInString.contains("ss") return formatInString.contains("ss")
} }
public override var hash: Int { override public var hash: Int {
guard let placeIdentifier = placeID, let timezone = timezoneID else { guard let placeIdentifier = placeID, let timezone = timezoneID else {
return -1 return -1
} }
@ -350,14 +350,14 @@ public class TimezoneData: NSObject, NSCoding {
return lhs.placeID == rhs.placeID return lhs.placeID == rhs.placeID
} }
public override func isEqual(to object: Any?) -> Bool { override public func isEqual(to object: Any?) -> Bool {
if let other = object as? TimezoneData { if let other = object as? TimezoneData {
return placeID == other.placeID return placeID == other.placeID
} }
return false return false
} }
public override func isEqual(_ object: Any?) -> Bool { override public func isEqual(_ object: Any?) -> Bool {
guard let compared = object as? TimezoneData else { guard let compared = object as? TimezoneData else {
return false return false
} }
@ -367,12 +367,12 @@ public class TimezoneData: NSObject, NSCoding {
} }
} }
extension TimezoneData { public extension TimezoneData {
public override var description: String { override var description: String {
return objectDescription() return objectDescription()
} }
public override var debugDescription: String { override var debugDescription: String {
return objectDescription() return objectDescription()
} }

6
Clocker/Dependencies/Date Additions/TimePeriodChain.swift

@ -138,15 +138,15 @@ open class TimePeriodChain: TimePeriodGroup {
_end = _end?.addingTimeInterval(duration) _end = _end?.addingTimeInterval(duration)
} }
public override func map<T>(_ transform: (TimePeriodProtocol) throws -> T) rethrows -> [T] { override public func map<T>(_ transform: (TimePeriodProtocol) throws -> T) rethrows -> [T] {
return try periods.map(transform) return try periods.map(transform)
} }
public override func filter(_ isIncluded: (TimePeriodProtocol) throws -> Bool) rethrows -> [TimePeriodProtocol] { override public func filter(_ isIncluded: (TimePeriodProtocol) throws -> Bool) rethrows -> [TimePeriodProtocol] {
return try periods.filter(isIncluded) return try periods.filter(isIncluded)
} }
internal override func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, TimePeriodProtocol) throws -> Result) rethrows -> Result { override internal func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, TimePeriodProtocol) throws -> Result) rethrows -> Result {
return try periods.reduce(initialResult, nextPartialResult) return try periods.reduce(initialResult, nextPartialResult)
} }

6
Clocker/Dependencies/Solar.swift

@ -176,10 +176,10 @@ public struct Solar {
} }
} }
extension Solar { public extension Solar {
/// Whether the location specified by the `latitude` and `longitude` is in daytime on `date` /// Whether the location specified by the `latitude` and `longitude` is in daytime on `date`
/// - Complexity: O(1) /// - Complexity: O(1)
public var isDaytime: Bool { var isDaytime: Bool {
guard guard
let sunrise = sunrise, let sunrise = sunrise,
let sunset = sunset let sunset = sunset
@ -199,7 +199,7 @@ extension Solar {
/// Whether the location specified by the `latitude` and `longitude` is in nighttime on `date` /// Whether the location specified by the `latitude` and `longitude` is in nighttime on `date`
/// - Complexity: O(1) /// - Complexity: O(1)
public var isNighttime: Bool { var isNighttime: Bool {
return !isDaytime return !isDaytime
} }
} }

12
Clocker/Events and Reminders/CalendarHandler.swift

@ -21,7 +21,7 @@ extension EventCenter {
var sourcesAndCalendars: [Any] = [] var sourcesAndCalendars: [Any] = []
// Fetch array of user's calendars sorted first by source title and then by calendar title // Fetch array of user's calendars sorted first by source title and then by calendar title
let calendars = eventStore.calendars(for: .event).sorted { (cal1, cal2) -> Bool in let calendars = eventStore.calendars(for: .event).sorted { cal1, cal2 -> Bool in
if cal1.source.sourceIdentifier == cal2.source.sourceIdentifier { if cal1.source.sourceIdentifier == cal2.source.sourceIdentifier {
return cal1.title < cal2.title return cal1.title < cal2.title
@ -232,7 +232,7 @@ extension EventCenter {
} }
func retrieveAllCalendarIdentifiers() -> [String] { func retrieveAllCalendarIdentifiers() -> [String] {
return eventStore.calendars(for: .event).map { (calendar) -> String in return eventStore.calendars(for: .event).map { calendar -> String in
calendar.calendarIdentifier calendar.calendarIdentifier
} }
} }
@ -242,7 +242,8 @@ extension EventCenter {
dateComps.day = day dateComps.day = day
guard let convertedDate = calendar?.date(byAdding: dateComps, guard let convertedDate = calendar?.date(byAdding: dateComps,
to: Date(), to: Date(),
options: NSCalendar.Options.matchFirst) else { options: NSCalendar.Options.matchFirst)
else {
return Date() return Date()
} }
return convertedDate return convertedDate
@ -313,7 +314,7 @@ extension EventCenter {
// We now sort the array so that AllDay Events are first, then sort by startTime // We now sort the array so that AllDay Events are first, then sort by startTime
for date in eventsForDateMapper.keys { for date in eventsForDateMapper.keys {
let sortedEvents = eventsForDateMapper[date]?.sorted(by: { (event1, event2) -> Bool in let sortedEvents = eventsForDateMapper[date]?.sorted(by: { event1, event2 -> Bool in
if event1.isAllDay { return true } else if event2.isAllDay { return false } else { return event1.event.startDate < event2.event.startDate } if event1.isAllDay { return true } else if event2.isAllDay { return false } else { return event1.event.startDate < event2.event.startDate }
}) })
eventsForDateMapper[date] = sortedEvents eventsForDateMapper[date] = sortedEvents
@ -378,7 +379,8 @@ extension EventCenter {
|| actualLink.contains("indigo.collocall.de") || actualLink.contains("indigo.collocall.de")
|| actualLink.contains("public.senfcall.de") || actualLink.contains("public.senfcall.de")
|| actualLink.contains("youcanbook.me/zoom/") || actualLink.contains("youcanbook.me/zoom/")
|| actualLink.contains("workplace.com/groupcall") { || actualLink.contains("workplace.com/groupcall")
{
if let zoomLink = result.url { if let zoomLink = result.url {
return zoomLink return zoomLink
} }

1
Clocker/Events and Reminders/EventCenter.swift

@ -53,6 +53,5 @@ class EventCenter: NSObject {
self.fetchEvents(-40, 80) self.fetchEvents(-40, 80)
} }
} }
} }
} }

3
Clocker/Events and Reminders/RemindersHandler.swift

@ -51,7 +51,8 @@ extension EventCenter {
timezone: String, timezone: String,
alertIndex: Int, alertIndex: Int,
reminderDate: Date, reminderDate: Date,
additionalNotes: String?) -> Bool { additionalNotes: String?) -> Bool
{
initializeStoreIfNeccesary() initializeStoreIfNeccesary()
if reminderAccessNotDetermined() || reminderAccessDenied() { if reminderAccessNotDetermined() || reminderAccessDenied() {

2
Clocker/Menu Bar/MenubarHandler.swift

@ -19,7 +19,7 @@ class MenubarHandler: NSObject {
} }
if menubarTitles.isEmpty == false { if menubarTitles.isEmpty == false {
let titles = menubarTitles.map { (data) -> String? in let titles = menubarTitles.map { data -> String? in
let timezone = TimezoneData.customObject(from: data) let timezone = TimezoneData.customObject(from: data)
let operationsObject = TimezoneDataOperations(with: timezone!) let operationsObject = TimezoneDataOperations(with: timezone!)
return "\(operationsObject.menuTitle().trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines))" return "\(operationsObject.menuTitle().trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines))"

9
Clocker/Menu Bar/StatusContainerView.swift

@ -31,10 +31,12 @@ func compactWidth(for timezone: TimezoneData) -> Int {
if timeFormat == DateFormat.twelveHour if timeFormat == DateFormat.twelveHour
|| timeFormat == DateFormat.twelveHourWithSeconds || timeFormat == DateFormat.twelveHourWithSeconds
|| timeFormat == DateFormat.twelveHourWithZero || timeFormat == DateFormat.twelveHourWithZero
|| timeFormat == DateFormat.twelveHourWithSeconds { || timeFormat == DateFormat.twelveHourWithSeconds
{
totalWidth += 20 totalWidth += 20
} else if timeFormat == DateFormat.twentyFourHour } else if timeFormat == DateFormat.twentyFourHour
|| timeFormat == DateFormat.twentyFourHourWithSeconds { || timeFormat == DateFormat.twentyFourHourWithSeconds
{
totalWidth += 0 totalWidth += 0
} }
@ -79,7 +81,7 @@ class StatusContainerView: NSView {
] ]
func containerWidth(for timezones: [Data]) -> CGFloat { func containerWidth(for timezones: [Data]) -> CGFloat {
let compressedWidth = timezones.reduce(0.0) { (result, timezone) -> CGFloat in let compressedWidth = timezones.reduce(0.0) { result, timezone -> CGFloat in
if let timezoneObject = TimezoneData.customObject(from: timezone) { if let timezoneObject = TimezoneData.customObject(from: timezone) {
let precalculatedWidth = Double(compactWidth(for: timezoneObject)) let precalculatedWidth = Double(compactWidth(for: timezoneObject))
@ -106,6 +108,7 @@ class StatusContainerView: NSView {
addSubviews() addSubviews()
} }
@available(*, unavailable)
required init?(coder _: NSCoder) { required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }

2
Clocker/Menu Bar/StatusItemHandler.swift

@ -141,7 +141,7 @@ class StatusItemHandler: NSObject {
private func retrieveSyncedMenubarTimezones() -> [Data] { private func retrieveSyncedMenubarTimezones() -> [Data] {
let defaultPreferences = DataStore.shared().retrieve(key: CLDefaultPreferenceKey) as? [Data] ?? [] let defaultPreferences = DataStore.shared().retrieve(key: CLDefaultPreferenceKey) as? [Data] ?? []
let menubarTimezones = defaultPreferences.filter { (data) -> Bool in let menubarTimezones = defaultPreferences.filter { data -> Bool in
if let timezoneObj = TimezoneData.customObject(from: data) { if let timezoneObj = TimezoneData.customObject(from: data) {
return timezoneObj.isFavourite == 1 return timezoneObj.isFavourite == 1
} }

5
Clocker/Menu Bar/StatusItemView.swift

@ -36,8 +36,8 @@ extension NSView {
class StatusItemView: NSView { class StatusItemView: NSView {
// MARK: Private variables // MARK: Private variables
private let locationView: NSTextField = NSTextField(labelWithString: "Hello") private let locationView = NSTextField(labelWithString: "Hello")
private let timeView: NSTextField = NSTextField(labelWithString: "Mon 19:14 PM") private let timeView = NSTextField(labelWithString: "Mon 19:14 PM")
private var operationsObject: TimezoneDataOperations { private var operationsObject: TimezoneDataOperations {
return TimezoneDataOperations(with: dataObject) return TimezoneDataOperations(with: dataObject)
} }
@ -117,6 +117,7 @@ class StatusItemView: NSView {
timeView.attributedStringValue = NSAttributedString(string: operationsObject.compactMenuSubtitle(), attributes: timeAttributes) timeView.attributedStringValue = NSAttributedString(string: operationsObject.compactMenuSubtitle(), attributes: timeAttributes)
} }
@available(*, unavailable)
required init?(coder _: NSCoder) { required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }

6
Clocker/Onboarding/FinalOnboardingViewController.swift

@ -103,7 +103,8 @@ class FinalOnboardingViewController: NSViewController {
} }
guard let shortVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String, guard let shortVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String,
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String else { let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String
else {
return nil return nil
} }
let operatingSystem = ProcessInfo.processInfo.operatingSystemVersion let operatingSystem = ProcessInfo.processInfo.operatingSystemVersion
@ -134,7 +135,8 @@ class EmailTextFieldValidator {
range: range) range: range)
if allMatches.count == 1, if allMatches.count == 1,
allMatches.first?.url?.absoluteString.contains("mailto:") == true { allMatches.first?.url?.absoluteString.contains("mailto:") == true
{
return trimmedText return trimmedText
} }
return nil return nil

5
Clocker/Onboarding/OnboardingSearchController.swift

@ -28,7 +28,8 @@ class OnboardingSearchController: NSViewController {
private var geocodingKey: String = { private var geocodingKey: String = {
guard let path = Bundle.main.path(forResource: "Keys", ofType: "plist"), guard let path = Bundle.main.path(forResource: "Keys", ofType: "plist"),
let dictionary = NSDictionary(contentsOfFile: path), let dictionary = NSDictionary(contentsOfFile: path),
let apiKey = dictionary["GeocodingKey"] as? String else { let apiKey = dictionary["GeocodingKey"] as? String
else {
assertionFailure("Unable to find the API key") assertionFailure("Unable to find the API key")
return "" return ""
} }
@ -398,7 +399,7 @@ class OnboardingSearchController: NSViewController {
} }
private func appendResultsToFilteredArray(_ results: [SearchResult.Result]) { private func appendResultsToFilteredArray(_ results: [SearchResult.Result]) {
let finalTimezones: [TimezoneData] = results.map { (result) -> TimezoneData in let finalTimezones: [TimezoneData] = results.map { result -> TimezoneData in
let location = result.geometry.location let location = result.geometry.location
let latitude = location.lat let latitude = location.lat
let longitude = location.lng let longitude = location.lng

6
Clocker/Overall App/DateFormatterManager.swift

@ -5,9 +5,9 @@ import Cocoa
class DateFormatterManager: NSObject { class DateFormatterManager: NSObject {
public static let sharedInstance = DateFormatterManager() public static let sharedInstance = DateFormatterManager()
private static var dateFormatter: DateFormatter = DateFormatter() private static var dateFormatter = DateFormatter()
private static var calendarDateFormatter: DateFormatter = DateFormatter() private static var calendarDateFormatter = DateFormatter()
private static var simpleFormatter: DateFormatter = DateFormatter() private static var simpleFormatter = DateFormatter()
private static var specializedFormatter = DateFormatter() private static var specializedFormatter = DateFormatter()
private static var localizedForamtter = DateFormatter() private static var localizedForamtter = DateFormatter()
private static var localizedSimpleFormatter = DateFormatter() private static var localizedSimpleFormatter = DateFormatter()

6
Clocker/Overall App/Foundation + Additions.swift

@ -34,9 +34,9 @@ extension NSImage.Name {
static let menubarIcon = NSImage.Name("LightModeIcon") static let menubarIcon = NSImage.Name("LightModeIcon")
} }
extension Data { public extension Data {
// Extracting this out for tests // Extracting this out for tests
public func decode() -> SearchResult? { func decode() -> SearchResult? {
let jsonDecoder = JSONDecoder() let jsonDecoder = JSONDecoder()
do { do {
let decodedObject = try jsonDecoder.decode(SearchResult.self, from: self) let decodedObject = try jsonDecoder.decode(SearchResult.self, from: self)
@ -46,7 +46,7 @@ extension Data {
} }
} }
public func decodeTimezone() -> Timezone? { func decodeTimezone() -> Timezone? {
let jsonDecoder = JSONDecoder() let jsonDecoder = JSONDecoder()
do { do {
let decodedObject = try jsonDecoder.decode(Timezone.self, from: self) let decodedObject = try jsonDecoder.decode(Timezone.self, from: self)

3
Clocker/Overall App/NetworkManager.swift

@ -41,7 +41,8 @@ extension NetworkManager {
let session = URLSession(configuration: configuration) let session = URLSession(configuration: configuration)
guard let encodedPath = path.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), guard let encodedPath = path.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: encodedPath) else { let url = URL(string: encodedPath)
else {
completionHandler(nil, unableToGenerateURL) completionHandler(nil, unableToGenerateURL)
return nil return nil
} }

4
Clocker/Overall App/Reach.swift

@ -54,8 +54,8 @@ open class Reach {
} }
} }
extension ReachabilityStatus { private extension ReachabilityStatus {
fileprivate init(reachabilityFlags flags: SCNetworkReachabilityFlags) { init(reachabilityFlags flags: SCNetworkReachabilityFlags) {
let connectionRequired = flags.contains(.connectionRequired) let connectionRequired = flags.contains(.connectionRequired)
let isReachable = flags.contains(.reachable) let isReachable = flags.contains(.reachable)

2
Clocker/Overall App/VersionUpdateHandler.swift

@ -25,7 +25,7 @@ class VersionUpdateHandler: NSObject {
private var appStoreCountry: String! private var appStoreCountry: String!
private var applicationVersion: String! private var applicationVersion: String!
private var applicationBundleID: String = Bundle.main.bundleIdentifier ?? "N/A" private var applicationBundleID: String = Bundle.main.bundleIdentifier ?? "N/A"
private var updatePriority: VersionUpdateHandlerPriority = VersionUpdateHandlerPriority.defaultPri private var updatePriority = VersionUpdateHandlerPriority.defaultPri
private var useAllAvailableLanguages: Bool = true private var useAllAvailableLanguages: Bool = true
private var onlyPromptIfMainWindowIsAvailable: Bool = true private var onlyPromptIfMainWindowIsAvailable: Bool = true
private var checkAtLaunch: Bool = true private var checkAtLaunch: Bool = true

20
Clocker/Panel/Data Layer/TimezoneDataOperations.swift

@ -7,7 +7,7 @@ import CoreModelKit
class TimezoneDataOperations: NSObject { class TimezoneDataOperations: NSObject {
private var dataObject: TimezoneData! private var dataObject: TimezoneData!
private lazy var nsCalendar: Calendar = Calendar.autoupdatingCurrent private lazy var nsCalendar = Calendar.autoupdatingCurrent
private static var gregorianCalendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian) private static var gregorianCalendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)
private static var swiftyCalendar = Calendar(identifier: .gregorian) private static var swiftyCalendar = Calendar(identifier: .gregorian)
private static let currentLocale = Locale.current.identifier private static let currentLocale = Locale.current.identifier
@ -22,12 +22,13 @@ extension TimezoneDataOperations {
guard let newDate = TimezoneDataOperations.gregorianCalendar?.date(byAdding: .minute, guard let newDate = TimezoneDataOperations.gregorianCalendar?.date(byAdding: .minute,
value: sliderValue, value: sliderValue,
to: Date(), to: Date(),
options: .matchFirst) else { options: .matchFirst)
else {
assertionFailure("Data was unexpectedly nil") assertionFailure("Data was unexpectedly nil")
return CLEmptyString return CLEmptyString
} }
if (dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == DateFormat.epochTime) { if dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == DateFormat.epochTime {
let timezone = TimeZone(identifier: dataObject.timezone()) let timezone = TimeZone(identifier: dataObject.timezone())
let offset = timezone?.secondsFromGMT(for: newDate) ?? 0 let offset = timezone?.secondsFromGMT(for: newDate) ?? 0
let value = Int(Date().timeIntervalSince1970 + Double(offset)) let value = Int(Date().timeIntervalSince1970 + Double(offset))
@ -39,7 +40,6 @@ extension TimezoneDataOperations {
timezoneIdentifier: dataObject.timezone(), timezoneIdentifier: dataObject.timezone(),
locale: Locale.autoupdatingCurrent) locale: Locale.autoupdatingCurrent)
return dateFormatter.string(from: newDate) return dateFormatter.string(from: newDate)
} }
@ -52,7 +52,8 @@ extension TimezoneDataOperations {
guard let newDate = TimezoneDataOperations.gregorianCalendar?.date(byAdding: .minute, guard let newDate = TimezoneDataOperations.gregorianCalendar?.date(byAdding: .minute,
value: sliderValue, value: sliderValue,
to: Date(), to: Date(),
options: .matchFirst) else { options: .matchFirst)
else {
assertionFailure("Data was unexpectedly nil") assertionFailure("Data was unexpectedly nil")
return nil return nil
} }
@ -204,8 +205,8 @@ extension TimezoneDataOperations {
let sourceTimezone = TimeZone.current let sourceTimezone = TimeZone.current
let destinationTimezone = TimeZone(identifier: dataObject.timezone()) let destinationTimezone = TimeZone(identifier: dataObject.timezone())
let sourceGMTOffset: Double = Double(sourceTimezone.secondsFromGMT(for: source)) let sourceGMTOffset = Double(sourceTimezone.secondsFromGMT(for: source))
let destinationGMTOffset: Double = Double(destinationTimezone?.secondsFromGMT(for: source) ?? 0) let destinationGMTOffset = Double(destinationTimezone?.secondsFromGMT(for: source) ?? 0)
let interval = destinationGMTOffset - sourceGMTOffset let interval = destinationGMTOffset - sourceGMTOffset
return Date(timeInterval: interval, since: source) return Date(timeInterval: interval, since: source)
@ -367,12 +368,13 @@ extension TimezoneDataOperations {
to: Date()) to: Date())
guard let lat = dataObject.latitude, guard let lat = dataObject.latitude,
let long = dataObject.longitude else { let long = dataObject.longitude
else {
assertionFailure("Data was unexpectedly nil.") assertionFailure("Data was unexpectedly nil.")
return return
} }
let coordinates: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: lat, longitude: long) let coordinates = CLLocationCoordinate2D(latitude: lat, longitude: long)
guard let dateForCalculation = currentDate, let solar = Solar(for: dateForCalculation, coordinate: coordinates) else { guard let dateForCalculation = currentDate, let solar = Solar(for: dateForCalculation, coordinate: coordinates) else {
return return

2
Clocker/Panel/FloatingWindowController.swift

@ -5,7 +5,7 @@ import Cocoa
class FloatingWindowController: ParentPanelController { class FloatingWindowController: ParentPanelController {
private var repeater: Repeater? private var repeater: Repeater?
static var sharedWindow: FloatingWindowController = FloatingWindowController(windowNibName: NSNib.Name.floatingWindowIdentifier) static var sharedWindow = FloatingWindowController(windowNibName: NSNib.Name.floatingWindowIdentifier)
override func windowDidLoad() { override func windowDidLoad() {
super.windowDidLoad() super.windowDidLoad()

12
Clocker/Panel/Notes Popover/NotesPopover.swift

@ -175,7 +175,8 @@ class NotesPopover: NSViewController {
guard let initialStart = calendar?.nextDate(after: currentDate, guard let initialStart = calendar?.nextDate(after: currentDate,
matching: NSCalendar.Unit.hour, matching: NSCalendar.Unit.hour,
value: hour, value: hour,
options: NSCalendar.Options.matchPreviousTimePreservingSmallerUnits) else { options: NSCalendar.Options.matchPreviousTimePreservingSmallerUnits)
else {
assertionFailure("Initial Date object was unexepectedly nil") assertionFailure("Initial Date object was unexepectedly nil")
return return
} }
@ -196,7 +197,8 @@ class NotesPopover: NSViewController {
guard let newDate = currentCalendar?.date(byAdding: NSCalendar.Unit.minute, guard let newDate = currentCalendar?.date(byAdding: NSCalendar.Unit.minute,
value: 0, value: 0,
to: Date(), to: Date(),
options: NSCalendar.Options.matchLast) else { options: NSCalendar.Options.matchLast)
else {
assertionFailure("Initial Date object was unexepectedly nil") assertionFailure("Initial Date object was unexepectedly nil")
completionHandler(nil) completionHandler(nil)
return return
@ -320,7 +322,8 @@ class NotesPopover: NSViewController {
} }
private func updateTimezoneInDefaultPreferences(with override: Int, private func updateTimezoneInDefaultPreferences(with override: Int,
_: OverrideType) { _: OverrideType)
{
let timezones = DataStore.shared().timezones() let timezones = DataStore.shared().timezones()
var timezoneObjects: [TimezoneData] = [] var timezoneObjects: [TimezoneData] = []
@ -389,7 +392,8 @@ class NotesPopover: NSViewController {
timezone: model.timezone(), timezone: model.timezone(),
alertIndex: alertIndex, alertIndex: alertIndex,
reminderDate: reminderPicker.dateValue, reminderDate: reminderPicker.dateValue,
additionalNotes: model.note) { additionalNotes: model.note)
{
showSuccessMessage() showSuccessMessage()
} }
} }

8
Clocker/Panel/PanelController.swift

@ -152,7 +152,8 @@ class PanelController: ParentPanelController {
} }
if let statusWindow = statusBackgroundWindow, if let statusWindow = statusBackgroundWindow,
let statusButton = statusView { let statusButton = statusView
{
var statusItemFrame = statusWindow.convertToScreen(statusButton.frame) var statusItemFrame = statusWindow.convertToScreen(statusButton.frame)
var statusItemScreen = NSScreen.main var statusItemScreen = NSScreen.main
var testPoint = statusItemFrame.origin var testPoint = statusItemFrame.origin
@ -193,7 +194,8 @@ class PanelController: ParentPanelController {
let showDateInMenu = DataStore.shared().retrieve(key: CLShowDateInMenu) as? NSNumber, let showDateInMenu = DataStore.shared().retrieve(key: CLShowDateInMenu) as? NSNumber,
let showPlaceInMenu = DataStore.shared().retrieve(key: CLShowPlaceInMenu) as? NSNumber, let showPlaceInMenu = DataStore.shared().retrieve(key: CLShowPlaceInMenu) as? NSNumber,
let showUpcomingEventView = DataStore.shared().retrieve(key: CLShowUpcomingEventView) as? String, let showUpcomingEventView = DataStore.shared().retrieve(key: CLShowUpcomingEventView) as? String,
let country = Locale.autoupdatingCurrent.regionCode else { let country = Locale.autoupdatingCurrent.regionCode
else {
return return
} }
@ -313,7 +315,7 @@ class PanelController: ParentPanelController {
} }
class func panel() -> PanelController? { class func panel() -> PanelController? {
let panel = NSApplication.shared.windows.compactMap { (window) -> PanelController? in let panel = NSApplication.shared.windows.compactMap { window -> PanelController? in
guard let parent = window.windowController as? PanelController else { guard let parent = window.windowController as? PanelController else {
return nil return nil

1
Clocker/Panel/ParentPanelController+ModernSlider.swift

@ -20,6 +20,7 @@ extension ParentPanelController {
if modernSlider != nil { if modernSlider != nil {
modernSlider.enclosingScrollView?.scrollerInsets = NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) modernSlider.enclosingScrollView?.scrollerInsets = NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
modernSlider.enclosingScrollView?.backgroundColor = NSColor.clear modernSlider.enclosingScrollView?.backgroundColor = NSColor.clear
modernSlider.setAccessibility("ModernSlider")
modernSlider.postsBoundsChangedNotifications = true modernSlider.postsBoundsChangedNotifications = true
NotificationCenter.default.addObserver(self, NotificationCenter.default.addObserver(self,
selector: #selector(collectionViewDidScroll(_:)), selector: #selector(collectionViewDidScroll(_:)),

21
Clocker/Panel/ParentPanelController.swift

@ -37,7 +37,7 @@ class ParentPanelController: NSWindowController {
var datasource: TimezoneDataSource? var datasource: TimezoneDataSource?
private lazy var feedbackWindow: AppFeedbackWindowController = AppFeedbackWindowController.shared() private lazy var feedbackWindow = AppFeedbackWindowController.shared()
private var notePopover: NotesPopover? private var notePopover: NotesPopover?
@ -395,7 +395,7 @@ class ParentPanelController: NSWindowController {
var current = main.frame.height var current = main.frame.height
let activeScreens = NSScreen.screens.filter { (current) -> Bool in let activeScreens = NSScreen.screens.filter { current -> Bool in
NSMouseInRect(mouseLocation, current.frame, false) NSMouseInRect(mouseLocation, current.frame, false)
} }
@ -426,7 +426,8 @@ class ParentPanelController: NSWindowController {
newHeight += 20 newHeight += 20
} else if DataStore.shared().shouldDisplay(.dstTransitionInfo), } else if DataStore.shared().shouldDisplay(.dstTransitionInfo),
let obj = object, let obj = object,
TimezoneDataOperations(with: obj).nextDaylightSavingsTransitionIfAvailable(with: futureSliderValue) != nil { TimezoneDataOperations(with: obj).nextDaylightSavingsTransitionIfAvailable(with: futureSliderValue) != nil
{
newHeight += 20 newHeight += 20
} }
} }
@ -496,7 +497,7 @@ class ParentPanelController: NSWindowController {
updatePanelColor() updatePanelColor()
let defaults = DataStore.shared().timezones() let defaults = DataStore.shared().timezones()
let convertedTimezones = defaults.map { (data) -> TimezoneData in let convertedTimezones = defaults.map { data -> TimezoneData in
TimezoneData.customObject(from: data)! TimezoneData.customObject(from: data)!
} }
@ -533,7 +534,8 @@ class ParentPanelController: NSWindowController {
let currentCalendar = Calendar(identifier: .gregorian) let currentCalendar = Calendar(identifier: .gregorian)
guard let newDate = currentCalendar.date(byAdding: .minute, guard let newDate = currentCalendar.date(byAdding: .minute,
value: Int(futureSlider.doubleValue), value: Int(futureSlider.doubleValue),
to: Date()) else { to: Date())
else {
assertionFailure("Data was unexpectedly nil") assertionFailure("Data was unexpectedly nil")
return return
} }
@ -600,7 +602,8 @@ class ParentPanelController: NSWindowController {
if $0 < mainTableView.numberOfRows, if $0 < mainTableView.numberOfRows,
let cellView = mainTableView.view(atColumn: 0, row: $0, makeIfNecessary: false) as? TimezoneCellView, let cellView = mainTableView.view(atColumn: 0, row: $0, makeIfNecessary: false) as? TimezoneCellView,
let model = TimezoneData.customObject(from: current) { 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
} }
@ -620,7 +623,8 @@ class ParentPanelController: NSWindowController {
if let note = model.note, !note.isEmpty { if let note = model.note, !note.isEmpty {
cellView.noteLabel.stringValue = note cellView.noteLabel.stringValue = note
} else if DataStore.shared().shouldDisplay(.dstTransitionInfo), } else if DataStore.shared().shouldDisplay(.dstTransitionInfo),
let value = TimezoneDataOperations(with: model).nextDaylightSavingsTransitionIfAvailable(with: futureSliderValue) { let value = TimezoneDataOperations(with: model).nextDaylightSavingsTransitionIfAvailable(with: futureSliderValue)
{
cellView.noteLabel.stringValue = value cellView.noteLabel.stringValue = value
} else { } else {
cellView.noteLabel.stringValue = CLEmptyString cellView.noteLabel.stringValue = CLEmptyString
@ -719,7 +723,8 @@ class ParentPanelController: NSWindowController {
@IBAction func calendarButtonAction(_: NSButton) { @IBAction func calendarButtonAction(_: NSButton) {
if calendarButton.title == NSLocalizedString("Click here to start.", if calendarButton.title == NSLocalizedString("Click here to start.",
comment: "Button Title for no Calendar access") { comment: "Button Title for no Calendar access")
{
showPermissionsWindow() showPermissionsWindow()
} else { } else {
retrieveCalendarEvents() retrieveCalendarEvents()

5
Clocker/Panel/UI/TimezoneCellView.swift

@ -128,7 +128,8 @@ class TimezoneCellView: NSTableCellView {
} }
guard let customFont = customName.font, guard let customFont = customName.font,
let timeFont = time.font else { let timeFont = time.font
else {
assertionFailure("User Font Size is in unexpectedly nil") assertionFailure("User Font Size is in unexpectedly nil")
return return
} }
@ -204,7 +205,7 @@ class TimezoneCellView: NSTableCellView {
pasteboard.declareTypes([.string], owner: nil) pasteboard.declareTypes([.string], owner: nil)
pasteboard.setString(clipboardCopy, forType: .string) pasteboard.setString(clipboardCopy, forType: .string)
self.window?.contentView?.makeToast("Copied to Clipboard".localized()) window?.contentView?.makeToast("Copied to Clipboard".localized())
window?.endEditing(for: nil) window?.endEditing(for: nil)
} }

84
Clocker/Panel/UI/Toasty.swift

@ -1,13 +1,14 @@
// Copyright © 2015 Abhishek Banthia // Copyright © 2015 Abhishek Banthia
import Foundation
import AppKit import AppKit
import Foundation
extension CGRect { extension CGRect {
static func center(of layer: CALayer) -> CGPoint { static func center(of layer: CALayer) -> CGPoint {
let parentSize = layer.frame.size let parentSize = layer.frame.size
return CGPoint(x: parentSize.width / 2, y: parentSize.height / 2) return CGPoint(x: parentSize.width / 2, y: parentSize.height / 2)
} }
static func center(of parent: NSView) -> CGPoint { static func center(of parent: NSView) -> CGPoint {
let parentSize = parent.frame.size let parentSize = parent.frame.size
return CGPoint(x: parentSize.width / 2, y: parentSize.height / 6) return CGPoint(x: parentSize.width / 2, y: parentSize.height / 6)
@ -22,18 +23,21 @@ extension String {
} }
} }
fileprivate class HideAnimationDelegate: NSObject, CAAnimationDelegate { private class HideAnimationDelegate: NSObject, CAAnimationDelegate {
private weak var view: NSView? private weak var view: NSView?
fileprivate init(view: NSView) { fileprivate init(view: NSView) {
self.view = view self.view = view
} }
fileprivate static func delegate(forView NSView: NSView) -> CAAnimationDelegate { fileprivate static func delegate(forView NSView: NSView) -> CAAnimationDelegate {
return HideAnimationDelegate(view: NSView) return HideAnimationDelegate(view: NSView)
} }
fileprivate func animationDidStart(_ anim: CAAnimation) {
fileprivate func animationDidStart(_: CAAnimation) {
view?.layer?.opacity = 0.0 view?.layer?.opacity = 0.0
} }
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
func animationDidStop(_: CAAnimation, finished _: Bool) {
view?.removeFromSuperview() view?.removeFromSuperview()
view = nil view = nil
} }
@ -55,45 +59,47 @@ func hideAnimation(view: NSView, style: Style) {
} }
public protocol Style { public protocol Style {
var fontSize: CGFloat {get} var fontSize: CGFloat { get }
var horizontalMargin: CGFloat {get} var horizontalMargin: CGFloat { get }
var verticalMargin: CGFloat {get} var verticalMargin: CGFloat { get }
var cornerRadius: CGFloat {get} var cornerRadius: CGFloat { get }
var font: NSFont {get} var font: NSFont { get }
var backgroundColor: NSColor {get} var backgroundColor: NSColor { get }
var foregroundColor: NSColor {get} var foregroundColor: NSColor { get }
var fadeInOutDuration: CGFloat {get} var fadeInOutDuration: CGFloat { get }
var fadeInOutDelay: CGFloat {get} var fadeInOutDelay: CGFloat { get }
var labelOriginWithMargin: CGPoint {get} var labelOriginWithMargin: CGPoint { get }
var activitySize: CGSize {get} var activitySize: CGSize { get }
} }
extension Style { public extension Style {
public var labelOriginWithMargin: CGPoint { var labelOriginWithMargin: CGPoint {
return CGPoint(x: horizontalMargin, y: verticalMargin) return CGPoint(x: horizontalMargin, y: verticalMargin)
} }
public var fontSize: CGFloat {return 12}
public var font: NSFont { var fontSize: CGFloat { return 12 }
var font: NSFont {
if let avenirFont = NSFont(name: "Avenir-Light", size: fontSize) { if let avenirFont = NSFont(name: "Avenir-Light", size: fontSize) {
return avenirFont return avenirFont
} }
return NSFont.systemFont(ofSize: fontSize) return NSFont.systemFont(ofSize: fontSize)
} }
public var horizontalMargin: CGFloat {return 10}
public var verticalMargin: CGFloat {return 5} var horizontalMargin: CGFloat { return 10 }
public var cornerRadius: CGFloat {return 8} var verticalMargin: CGFloat { return 5 }
public var backgroundColor: NSColor {return .black} var cornerRadius: CGFloat { return 8 }
public var foregroundColor: NSColor {return .white} var backgroundColor: NSColor { return .black }
public var activitySize: CGSize {return CGSize(width: 100, height: 100)} var foregroundColor: NSColor { return .white }
public var fadeInOutDuration: CGFloat {return 1.0} var activitySize: CGSize { return CGSize(width: 100, height: 100) }
public var fadeInOutDelay: CGFloat {return 1.0} var fadeInOutDuration: CGFloat { return 1.0 }
var fadeInOutDelay: CGFloat { return 1.0 }
} }
public struct DefaultStyle: Style { public struct DefaultStyle: Style {
public static let shared = DefaultStyle() public static let shared = DefaultStyle()
} }
private struct ToastKeys { private enum ToastKeys {
static var ActiveToast = "TSToastActiveToastKey" static var ActiveToast = "TSToastActiveToastKey"
} }
@ -103,17 +109,19 @@ class ToastView: NSView {
private let style: Style private let style: Style
init(message: String) { init(message: String) {
self.message = message self.message = message
self.style = DefaultStyle() style = DefaultStyle()
self.labelSize = message.size(with: style.fontSize) labelSize = message.size(with: style.fontSize)
let size = CGSize( let size = CGSize(
width: labelSize.width + style.horizontalMargin*2, width: labelSize.width + style.horizontalMargin * 2,
height: labelSize.height + style.verticalMargin*2 height: labelSize.height + style.verticalMargin * 2
) )
let rect = CGRect(origin: .zero, size: size) let rect = CGRect(origin: .zero, size: size)
super.init(frame: rect) super.init(frame: rect)
wantsLayer = true wantsLayer = true
} }
required init?(coder aDecoder: NSCoder) { fatalError() }
@available(*, unavailable)
required init?(coder _: NSCoder) { fatalError() }
override func viewDidMoveToSuperview() { override func viewDidMoveToSuperview() {
super.viewDidMoveToSuperview() super.viewDidMoveToSuperview()
@ -126,8 +134,8 @@ class ToastView: NSView {
frame = superview?.bounds ?? NSRect.zero frame = superview?.bounds ?? NSRect.zero
let rect = CGRect(origin: style.labelOriginWithMargin, size: labelSize) let rect = CGRect(origin: style.labelOriginWithMargin, size: labelSize)
let sizeWithMargin = CGSize( let sizeWithMargin = CGSize(
width: rect.width + style.horizontalMargin*2, width: rect.width + style.horizontalMargin * 2,
height: rect.height + style.verticalMargin*2 height: rect.height + style.verticalMargin * 2
) )
let rectWithMargin = CGRect( let rectWithMargin = CGRect(
origin: .zero, // position is manipulated later anyways origin: .zero, // position is manipulated later anyways
@ -155,10 +163,10 @@ class ToastView: NSView {
} }
} }
extension NSView { public extension NSView {
public func makeToast(_ message: String) { func makeToast(_ message: String) {
let toast = ToastView(message: message) let toast = ToastView(message: message)
self.addSubview(toast) addSubview(toast)
hideAnimation(view: toast, style: DefaultStyle.shared) hideAnimation(view: toast, style: DefaultStyle.shared)
} }
} }

8
Clocker/Preferences/App Feedback/AppFeedbackWindowController.swift

@ -11,7 +11,7 @@ extension NSNib.Name {
static let startAtLoginViewIdentifier = NSNib.Name("StartAtLoginView") static let startAtLoginViewIdentifier = NSNib.Name("StartAtLoginView")
} }
struct AppFeedbackConstants { enum AppFeedbackConstants {
static let CLAppFeedbackNibIdentifier = "AppFeedbackWindow" static let CLAppFeedbackNibIdentifier = "AppFeedbackWindow"
static let CLAppFeedbackNoResponseString = "Not Provided" static let CLAppFeedbackNoResponseString = "Not Provided"
static let CLAppFeedbackNameProperty = "name" static let CLAppFeedbackNameProperty = "name"
@ -59,7 +59,7 @@ class AppFeedbackWindowController: NSWindowController {
} }
} }
static var sharedWindow: AppFeedbackWindowController = AppFeedbackWindowController(windowNibName: NSNib.Name.appFeedbackWindowIdentifier) static var sharedWindow = AppFeedbackWindowController(windowNibName: NSNib.Name.appFeedbackWindowIdentifier)
override func windowDidLoad() { override func windowDidLoad() {
super.windowDidLoad() super.windowDidLoad()
@ -100,6 +100,7 @@ class AppFeedbackWindowController: NSWindowController {
} }
} }
@available(*, unavailable)
required init?(coder _: NSCoder) { required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@ -144,7 +145,8 @@ class AppFeedbackWindowController: NSWindowController {
private func retrieveDataForSending() -> [String: String] { private func retrieveDataForSending() -> [String: String] {
guard let shortVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String, guard let shortVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String,
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String else { let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String
else {
return [:] return [:]
} }

5
Clocker/Preferences/Appearance/AppearanceViewController.swift

@ -183,7 +183,8 @@ class AppearanceViewController: ParentViewController {
refresh(panel: true, floating: true) refresh(panel: true, floating: true)
if let selectedFormat = sender.selectedItem?.title, if let selectedFormat = sender.selectedItem?.title,
selectedFormat.contains("ss") { selectedFormat.contains("ss")
{
print("Seconds are contained") print("Seconds are contained")
guard let panelController = PanelController.panel() else { return } guard let panelController = PanelController.panel() else { return }
panelController.pauseTimer() panelController.pauseTimer()
@ -193,7 +194,7 @@ class AppearanceViewController: ParentViewController {
previewPanelTableView.reloadData() previewPanelTableView.reloadData()
} }
private var previousBackgroundColor: NSColor = NSColor.white private var previousBackgroundColor = NSColor.white
@IBAction func themeChanged(_ sender: NSSegmentedControl) { @IBAction func themeChanged(_ sender: NSSegmentedControl) {
previousBackgroundColor = Themer.shared().mainBackgroundColor() previousBackgroundColor = Themer.shared().mainBackgroundColor()

6
Clocker/Preferences/Calendar/CalendarViewController.swift

@ -239,13 +239,15 @@ extension CalendarViewController: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? { func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? {
if let currentSource = calendars[row] as? String, if let currentSource = calendars[row] as? String,
let message = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "sourceCellView"), owner: self) as? SourceTableViewCell { 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, if let currentSource = calendars[row] as? CalendarInfo,
let calendarCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "calendarCellView"), owner: self) as? CalendarTableViewCell { 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

3
Clocker/Preferences/General/PreferencesDataSource.swift

@ -104,7 +104,8 @@ extension PreferencesDataSource: NSTableViewDataSource {
var selectedDataSource: TimezoneData? var selectedDataSource: TimezoneData?
if selectedTimezones.count > row, if selectedTimezones.count > row,
let model = TimezoneData.customObject(from: selectedTimezones[row]) { let model = TimezoneData.customObject(from: selectedTimezones[row])
{
selectedDataSource = model selectedDataSource = model
} }

31
Clocker/Preferences/General/PreferencesViewController.swift

@ -43,7 +43,8 @@ class PreferencesViewController: ParentViewController {
private var geocodingKey: String = { private var geocodingKey: String = {
guard let path = Bundle.main.path(forResource: "Keys", ofType: "plist"), guard let path = Bundle.main.path(forResource: "Keys", ofType: "plist"),
let dictionary = NSDictionary(contentsOfFile: path), let dictionary = NSDictionary(contentsOfFile: path),
let apiKey = dictionary["GeocodingKey"] as? String else { let apiKey = dictionary["GeocodingKey"] as? String
else {
assertionFailure("Unable to find the API key") assertionFailure("Unable to find the API key")
return "" return ""
} }
@ -203,7 +204,6 @@ class PreferencesViewController: ParentViewController {
timezoneTableView.enclosingScrollView?.isHidden = true timezoneTableView.enclosingScrollView?.isHidden = true
showNoTimezoneState() showNoTimezoneState()
cleanup() cleanup()
return
} }
private func cleanup() { private func cleanup() {
@ -274,7 +274,7 @@ class PreferencesViewController: ParentViewController {
return return
} }
let newHotKey: PTHotKey = PTHotKey(identifier: keyPath, let newHotKey = PTHotKey(identifier: keyPath,
keyCombo: newShortcut, keyCombo: newShortcut,
target: self, target: self,
action: #selector(ping(_:))) action: #selector(ping(_:)))
@ -335,7 +335,8 @@ extension PreferencesViewController: NSTableViewDataSource, NSTableViewDelegate
if let appDelegate = NSApplication.shared.delegate as? AppDelegate, if let appDelegate = NSApplication.shared.delegate as? AppDelegate,
let menubarFavourites = DataStore.shared().menubarTimezones(), let menubarFavourites = DataStore.shared().menubarTimezones(),
menubarFavourites.isEmpty, menubarFavourites.isEmpty,
DataStore.shared().shouldDisplay(.showMeetingInMenubar) == false { DataStore.shared().shouldDisplay(.showMeetingInMenubar) == false
{
appDelegate.invalidateMenubarTimer(true) appDelegate.invalidateMenubarTimer(true)
} }
@ -817,7 +818,7 @@ extension PreferencesViewController {
var newDefaults = selectedTimeZones var newDefaults = selectedTimeZones
let objectsToRemove = timezoneTableView.selectedRowIndexes.map { (index) -> Data in let objectsToRemove = timezoneTableView.selectedRowIndexes.map { index -> Data in
selectedTimeZones[index] selectedTimeZones[index]
} }
@ -896,12 +897,13 @@ extension PreferencesViewController {
} }
@IBAction func sortByTime(_ sender: NSButton) { @IBAction func sortByTime(_ sender: NSButton) {
let sortedByTime = selectedTimeZones.sorted { (obj1, obj2) -> Bool in let sortedByTime = selectedTimeZones.sorted { obj1, obj2 -> Bool in
let system = NSTimeZone.system let system = NSTimeZone.system
guard let object1 = TimezoneData.customObject(from: obj1), guard let object1 = TimezoneData.customObject(from: obj1),
let object2 = TimezoneData.customObject(from: obj2) else { let object2 = TimezoneData.customObject(from: obj2)
else {
assertionFailure("Data was unexpectedly nil") assertionFailure("Data was unexpectedly nil")
return false return false
} }
@ -925,10 +927,11 @@ extension PreferencesViewController {
} }
@IBAction func sortByLabel(_ sender: NSButton) { @IBAction func sortByLabel(_ sender: NSButton) {
let sortedLabels = selectedTimeZones.sorted { (obj1, obj2) -> Bool in let sortedLabels = selectedTimeZones.sorted { obj1, obj2 -> Bool in
guard let object1 = TimezoneData.customObject(from: obj1), guard let object1 = TimezoneData.customObject(from: obj1),
let object2 = TimezoneData.customObject(from: obj2) else { let object2 = TimezoneData.customObject(from: obj2)
else {
assertionFailure("Data was unexpectedly nil") assertionFailure("Data was unexpectedly nil")
return false return false
} }
@ -948,10 +951,11 @@ extension PreferencesViewController {
} }
@IBAction func sortByFormattedAddress(_ sender: NSButton) { @IBAction func sortByFormattedAddress(_ sender: NSButton) {
let sortedByAddress = selectedTimeZones.sorted { (obj1, obj2) -> Bool in let sortedByAddress = selectedTimeZones.sorted { obj1, obj2 -> Bool in
guard let object1 = TimezoneData.customObject(from: obj1), guard let object1 = TimezoneData.customObject(from: obj1),
let object2 = TimezoneData.customObject(from: obj2) else { let object2 = TimezoneData.customObject(from: obj2)
else {
assertionFailure("Data was unexpectedly nil") assertionFailure("Data was unexpectedly nil")
return false return false
} }
@ -1014,10 +1018,11 @@ extension PreferencesViewController: PreferenceSelectionUpdates {
return return
} }
let sortedTimezones = selectedTimeZones.sorted { (obj1, obj2) -> Bool in let sortedTimezones = selectedTimeZones.sorted { obj1, obj2 -> Bool in
guard let object1 = TimezoneData.customObject(from: obj1), guard let object1 = TimezoneData.customObject(from: obj1),
let object2 = TimezoneData.customObject(from: obj2) else { let object2 = TimezoneData.customObject(from: obj2)
else {
assertionFailure("Data was unexpectedly nil") assertionFailure("Data was unexpectedly nil")
return false return false
} }

2
Clocker/Preferences/General/SearchDataSource.swift

@ -151,7 +151,7 @@ class SearchDataSource: NSObject {
func searchTimezones(_ searchString: String) { func searchTimezones(_ searchString: String) {
timezoneFilteredArray = [] timezoneFilteredArray = []
timezoneFilteredArray = timezoneArray.filter { (timezoneMetadata) -> Bool in timezoneFilteredArray = timezoneArray.filter { timezoneMetadata -> Bool in
let tags = timezoneMetadata.tags let tags = timezoneMetadata.tags
for tag in tags where tag.contains(searchString) { for tag in tags where tag.contains(searchString) {
return true return true

2
Clocker/Preferences/Menu Bar/MenubarHandler.swift

@ -21,7 +21,7 @@ class MenubarHandler: NSObject {
} }
if menubarTitles.isEmpty == false { if menubarTitles.isEmpty == false {
let titles = menubarTitles.map { (data) -> String? in let titles = menubarTitles.map { data -> String? in
let timezone = TimezoneData.customObject(from: data) let timezone = TimezoneData.customObject(from: data)
let operationsObject = TimezoneDataOperations(with: timezone!) let operationsObject = TimezoneDataOperations(with: timezone!)
return "\(operationsObject.menuTitle().trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines))" return "\(operationsObject.menuTitle().trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines))"

9
Clocker/Preferences/Menu Bar/StatusContainerView.swift

@ -33,10 +33,12 @@ func compactWidth(for timezone: TimezoneData) -> Int {
if timeFormat == DateFormat.twelveHour if timeFormat == DateFormat.twelveHour
|| timeFormat == DateFormat.twelveHourWithSeconds || timeFormat == DateFormat.twelveHourWithSeconds
|| timeFormat == DateFormat.twelveHourWithZero || timeFormat == DateFormat.twelveHourWithZero
|| timeFormat == DateFormat.twelveHourWithSeconds { || timeFormat == DateFormat.twelveHourWithSeconds
{
totalWidth += 20 totalWidth += 20
} else if timeFormat == DateFormat.twentyFourHour } else if timeFormat == DateFormat.twentyFourHour
|| timeFormat == DateFormat.twentyFourHourWithSeconds { || timeFormat == DateFormat.twentyFourHourWithSeconds
{
totalWidth += 0 totalWidth += 0
} }
@ -81,7 +83,7 @@ class StatusContainerView: NSView {
] ]
func containerWidth(for timezones: [Data]) -> CGFloat { func containerWidth(for timezones: [Data]) -> CGFloat {
let compressedWidth = timezones.reduce(0.0) { (result, timezone) -> CGFloat in let compressedWidth = timezones.reduce(0.0) { result, timezone -> CGFloat in
if let timezoneObject = TimezoneData.customObject(from: timezone) { if let timezoneObject = TimezoneData.customObject(from: timezone) {
let precalculatedWidth = Double(compactWidth(for: timezoneObject)) let precalculatedWidth = Double(compactWidth(for: timezoneObject))
@ -108,6 +110,7 @@ class StatusContainerView: NSView {
addSubviews() addSubviews()
} }
@available(*, unavailable)
required init?(coder _: NSCoder) { required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }

2
Clocker/Preferences/Menu Bar/StatusItemHandler.swift

@ -144,7 +144,7 @@ class StatusItemHandler: NSObject {
private func retrieveSyncedMenubarTimezones() -> [Data] { private func retrieveSyncedMenubarTimezones() -> [Data] {
let defaultPreferences = DataStore.shared().retrieve(key: CLDefaultPreferenceKey) as? [Data] ?? [] let defaultPreferences = DataStore.shared().retrieve(key: CLDefaultPreferenceKey) as? [Data] ?? []
let menubarTimezones = defaultPreferences.filter { (data) -> Bool in let menubarTimezones = defaultPreferences.filter { data -> Bool in
if let timezoneObj = TimezoneData.customObject(from: data) { if let timezoneObj = TimezoneData.customObject(from: data) {
return timezoneObj.isFavourite == 1 return timezoneObj.isFavourite == 1
} }

5
Clocker/Preferences/Menu Bar/StatusItemView.swift

@ -37,8 +37,8 @@ extension NSView {
class StatusItemView: NSView { class StatusItemView: NSView {
// MARK: Private variables // MARK: Private variables
private let locationView: NSTextField = NSTextField(labelWithString: "Hello") private let locationView = NSTextField(labelWithString: "Hello")
private let timeView: NSTextField = NSTextField(labelWithString: "Mon 19:14 PM") private let timeView = NSTextField(labelWithString: "Mon 19:14 PM")
private var operationsObject: TimezoneDataOperations { private var operationsObject: TimezoneDataOperations {
return TimezoneDataOperations(with: dataObject) return TimezoneDataOperations(with: dataObject)
} }
@ -118,6 +118,7 @@ class StatusItemView: NSView {
timeView.attributedStringValue = NSAttributedString(string: operationsObject.compactMenuSubtitle(), attributes: timeAttributes) timeView.attributedStringValue = NSAttributedString(string: operationsObject.compactMenuSubtitle(), attributes: timeAttributes)
} }
@available(*, unavailable)
required init?(coder _: NSCoder) { required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }

Loading…
Cancel
Save