Browse Source

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

pull/101/head
Abhishek 3 years ago
parent
commit
30af3b1426
  1. 14
      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. 46
      Clocker/ClockerUITests/CopyToClipboardTests.swift
  6. 2
      Clocker/ClockerUITests/FloatingWindowTests.swift
  7. 8
      Clocker/ClockerUITests/PreferencesTest.swift
  8. 9
      Clocker/ClockerUnitTests/ClockerUnitTests.swift
  9. 18
      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. 5
      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. 4
      Clocker/Menu Bar/StatusItemHandler.swift
  18. 5
      Clocker/Menu Bar/StatusItemView.swift
  19. 6
      Clocker/Onboarding/FinalOnboardingViewController.swift
  20. 9
      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. 22
      Clocker/Panel/Data Layer/TimezoneDataOperations.swift
  27. 2
      Clocker/Panel/FloatingWindowController.swift
  28. 14
      Clocker/Panel/Notes Popover/NotesPopover.swift
  29. 26
      Clocker/Panel/PanelController.swift
  30. 1
      Clocker/Panel/ParentPanelController+ModernSlider.swift
  31. 31
      Clocker/Panel/ParentPanelController.swift
  32. 4
      Clocker/Panel/Rate Controller/ReviewController.swift
  33. 2
      Clocker/Panel/Rate Controller/UpcomingEventView.swift
  34. 13
      Clocker/Panel/UI/TimezoneCellView.swift
  35. 2
      Clocker/Panel/UI/TimezoneDataSource.swift
  36. 90
      Clocker/Panel/UI/Toasty.swift
  37. 6
      Clocker/Preferences/About/AboutViewController.swift
  38. 12
      Clocker/Preferences/App Feedback/AppFeedbackWindowController.swift
  39. 5
      Clocker/Preferences/Appearance/AppearanceViewController.swift
  40. 6
      Clocker/Preferences/Calendar/CalendarViewController.swift
  41. 7
      Clocker/Preferences/General/PreferencesDataSource.swift
  42. 45
      Clocker/Preferences/General/PreferencesViewController.swift
  43. 2
      Clocker/Preferences/General/SearchDataSource.swift
  44. 2
      Clocker/Preferences/Menu Bar/MenubarHandler.swift
  45. 9
      Clocker/Preferences/Menu Bar/StatusContainerView.swift
  46. 4
      Clocker/Preferences/Menu Bar/StatusItemHandler.swift
  47. 5
      Clocker/Preferences/Menu Bar/StatusItemView.swift

14
Clocker/AppDelegate.swift

@ -7,8 +7,8 @@ import FirebaseCore
import FirebaseCrashlytics
open class AppDelegate: NSObject, NSApplicationDelegate {
private lazy var floatingWindow: FloatingWindowController = FloatingWindowController.shared()
private lazy var panelController: PanelController = PanelController.shared()
private lazy var floatingWindow = FloatingWindowController.shared()
private lazy var panelController = PanelController.shared()
private var statusBarHandler: StatusItemHandler!
private var panelObserver: NSKeyValueObservation?
@ -16,7 +16,7 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
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 {
let hotKeyCenter = PTHotKeyCenter.shared()
@ -30,10 +30,10 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
}
// Register new key
let newHotKey: PTHotKey = PTHotKey(identifier: keyPath,
keyCombo: newShortcut,
target: self,
action: #selector(ping(_:)))
let newHotKey = PTHotKey(identifier: keyPath,
keyCombo: newShortcut,
target: self,
action: #selector(ping(_:)))
hotKeyCenter?.register(newHotKey)
}

38
Clocker/Clocker.xcodeproj/project.pbxproj

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

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

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

2
Clocker/ClockerUITests/AboutUsTests.swift

@ -33,7 +33,7 @@ class AboutUsTests: XCTestCase {
tapAboutTab()
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 {
XCTFail("Present version not present")

46
Clocker/ClockerUITests/CopyToClipboardTests.swift

@ -4,16 +4,16 @@ import XCTest
class CopyToClipboardTests: XCTestCase {
var app: XCUIApplication!
override func setUp() {
continueAfterFailure = false
app = XCUIApplication()
app.launch()
if app.tables["FloatingTableView"].exists == false {
app.tapMenubarIcon()
app.buttons["Pin"].click()
}
// if app.tables["FloatingTableView"].exists == false {
// app.tapMenubarIcon()
// app.buttons["Pin"].click()
// }
}
override func tearDownWithError() throws {
@ -23,20 +23,20 @@ class CopyToClipboardTests: XCTestCase {
func testFullCopy() throws {
let cellCount = app.tables["FloatingTableView"].cells.count
var clipboardValue = String()
for cellIndex in 0..<cellCount {
for cellIndex in 0 ..< cellCount {
let cell = app.tables["FloatingTableView"].cells.element(boundBy: cellIndex)
let customLabel = cell.staticTexts["CustomNameLabelForCell"].value ?? "Nil Custom Label"
let time = cell.staticTexts["ActualTime"].value ?? "Nil Value"
clipboardValue.append(contentsOf: "\(customLabel) - \(time)\n")
}
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)
XCTAssert(clipboardValue == clipboard)
}
func testIndividualTimezoneCopy() {
let cell = app.tables["FloatingTableView"].cells.firstMatch
let customLabel = cell.staticTexts["CustomNameLabelForCell"].value ?? "Nil Custom Label"
@ -45,9 +45,35 @@ class CopyToClipboardTests: XCTestCase {
// Tap to copy!
cell.tap()
let clipboard = NSPasteboard.general.string(forType: .string) ?? "Empty Pasteboard"
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()
}
addUIInterruptionMonitor(withDescription: "Reminders Access") { (alert) -> Bool in
addUIInterruptionMonitor(withDescription: "Reminders Access") { alert -> Bool in
let alertButton = alert.buttons["OK"]
if alertButton.exists {
alertButton.tap()

8
Clocker/ClockerUITests/PreferencesTest.swift

@ -31,7 +31,7 @@ class PreferencesTest: XCTestCase {
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)
}
@ -334,7 +334,7 @@ class PreferencesTest: XCTestCase {
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()
let currentElement = clockerWindow.tables["TimezoneTableView"].tableRows.firstMatch
let currentElement = clockerWindow.tables["TimezoneTableView"].tableRows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))
currentElement.click()
for _ in 0 ..< rowQueryCount {
@ -416,7 +416,7 @@ extension XCTestCase {
return
}
let currentElement = app.windows["Clocker"].tableRows.firstMatch
let currentElement = app.windows["Clocker"].tableRows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))
currentElement.click()
while rowQueryCount > 0 {
@ -442,7 +442,7 @@ extension XCTestCase {
}
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())
if shouldSleep {
sleep(2)

9
Clocker/ClockerUnitTests/ClockerUnitTests.swift

@ -120,16 +120,16 @@ class ClockerUnitTests: XCTestCase {
let timezone = TimezoneData.customObject(from: $0)
return timezone?.placeID == "TestIdentifier"
}
// California is absent. Add it!
if filteredCount.count == 0 {
let timezoneData = TimezoneData(with: california)
let operationsObject = TimezoneDataOperations(with: timezoneData)
operationsObject.saveObject()
}
let oldCount = (defaults.object(forKey: CLDefaultPreferenceKey) as? [Data])?.count ?? 0
currentFavourites = currentFavourites.filter {
let timezone = TimezoneData.customObject(from: $0)
return timezone?.placeID != "TestIdentifier"
@ -288,7 +288,8 @@ class ClockerUnitTests: XCTestCase {
guard let newDate = cal?.date(byAdding: .minute,
value: 0,
to: Date(),
options: .matchFirst) else {
options: .matchFirst)
else {
XCTFail("Unable to add dates!")
return
}

18
Clocker/CoreModelKit/Sources/CoreModelKit/TimezoneData.swift

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

6
Clocker/Dependencies/Date Additions/TimePeriodChain.swift

@ -138,15 +138,15 @@ open class TimePeriodChain: TimePeriodGroup {
_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)
}
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)
}
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)
}

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

12
Clocker/Events and Reminders/CalendarHandler.swift

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

5
Clocker/Events and Reminders/EventCenter.swift

@ -16,7 +16,7 @@ class EventCenter: NSObject {
var eventsForDate: [Date: [EventInfo]] = [:]
var filteredEvents: [Date: [EventInfo]] = [:]
private let fetchQueue = DispatchQueue(label: "com.abhishek.fetch")
@discardableResult class func sharedCenter() -> EventCenter {
@ -43,7 +43,7 @@ class EventCenter: NSObject {
private func refetchAll() {
Logger.info("\nRefetching events from the store")
eventsForDate = [:]
filteredEvents = [:]
autoreleasepool {
@ -53,6 +53,5 @@ class EventCenter: NSObject {
self.fetchEvents(-40, 80)
}
}
}
}

3
Clocker/Events and Reminders/RemindersHandler.swift

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

2
Clocker/Menu Bar/MenubarHandler.swift

@ -19,7 +19,7 @@ class MenubarHandler: NSObject {
}
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 operationsObject = TimezoneDataOperations(with: timezone!)
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
|| timeFormat == DateFormat.twelveHourWithSeconds
|| timeFormat == DateFormat.twelveHourWithZero
|| timeFormat == DateFormat.twelveHourWithSeconds {
|| timeFormat == DateFormat.twelveHourWithSeconds
{
totalWidth += 20
} else if timeFormat == DateFormat.twentyFourHour
|| timeFormat == DateFormat.twentyFourHourWithSeconds {
|| timeFormat == DateFormat.twentyFourHourWithSeconds
{
totalWidth += 0
}
@ -79,7 +81,7 @@ class StatusContainerView: NSView {
]
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) {
let precalculatedWidth = Double(compactWidth(for: timezoneObject))
@ -106,6 +108,7 @@ class StatusContainerView: NSView {
addSubviews()
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

4
Clocker/Menu Bar/StatusItemHandler.swift

@ -141,7 +141,7 @@ class StatusItemHandler: NSObject {
private func retrieveSyncedMenubarTimezones() -> [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) {
return timezoneObj.isFavourite == 1
}
@ -185,7 +185,7 @@ class StatusItemHandler: NSObject {
if let strongSelf = self {
strongSelf.performTimerWork()
}
})
})
// Tolerance, even a small amount, has a positive imapct on the power usage. As a rule, we set it to 10% of the interval
menubarTimer?.tolerance = shouldDisplaySeconds ? 0.5 : 20

5
Clocker/Menu Bar/StatusItemView.swift

@ -36,8 +36,8 @@ extension NSView {
class StatusItemView: NSView {
// MARK: Private variables
private let locationView: NSTextField = NSTextField(labelWithString: "Hello")
private let timeView: NSTextField = NSTextField(labelWithString: "Mon 19:14 PM")
private let locationView = NSTextField(labelWithString: "Hello")
private let timeView = NSTextField(labelWithString: "Mon 19:14 PM")
private var operationsObject: TimezoneDataOperations {
return TimezoneDataOperations(with: dataObject)
}
@ -117,6 +117,7 @@ class StatusItemView: NSView {
timeView.attributedStringValue = NSAttributedString(string: operationsObject.compactMenuSubtitle(), attributes: timeAttributes)
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
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,
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String else {
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String
else {
return nil
}
let operatingSystem = ProcessInfo.processInfo.operatingSystemVersion
@ -134,7 +135,8 @@ class EmailTextFieldValidator {
range: range)
if allMatches.count == 1,
allMatches.first?.url?.absoluteString.contains("mailto:") == true {
allMatches.first?.url?.absoluteString.contains("mailto:") == true
{
return trimmedText
}
return nil

9
Clocker/Onboarding/OnboardingSearchController.swift

@ -27,8 +27,9 @@ class OnboardingSearchController: NSViewController {
private var geocodingKey: String = {
guard let path = Bundle.main.path(forResource: "Keys", ofType: "plist"),
let dictionary = NSDictionary(contentsOfFile: path),
let apiKey = dictionary["GeocodingKey"] as? String else {
let dictionary = NSDictionary(contentsOfFile: path),
let apiKey = dictionary["GeocodingKey"] as? String
else {
assertionFailure("Unable to find the API key")
return ""
}
@ -373,7 +374,7 @@ class OnboardingSearchController: NSViewController {
self.findLocalSearchResultsForTimezones()
self.prepareUIForPresentingResults()
}
})
})
}
private func presentErrorMessage(_ errorMessage: String) {
@ -398,7 +399,7 @@ class OnboardingSearchController: NSViewController {
}
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 latitude = location.lat
let longitude = location.lng

6
Clocker/Overall App/DateFormatterManager.swift

@ -5,9 +5,9 @@ import Cocoa
class DateFormatterManager: NSObject {
public static let sharedInstance = DateFormatterManager()
private static var dateFormatter: DateFormatter = DateFormatter()
private static var calendarDateFormatter: DateFormatter = DateFormatter()
private static var simpleFormatter: DateFormatter = DateFormatter()
private static var dateFormatter = DateFormatter()
private static var calendarDateFormatter = DateFormatter()
private static var simpleFormatter = DateFormatter()
private static var specializedFormatter = DateFormatter()
private static var localizedForamtter = 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")
}
extension Data {
public extension Data {
// Extracting this out for tests
public func decode() -> SearchResult? {
func decode() -> SearchResult? {
let jsonDecoder = JSONDecoder()
do {
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()
do {
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)
guard let encodedPath = path.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: encodedPath) else {
let url = URL(string: encodedPath)
else {
completionHandler(nil, unableToGenerateURL)
return nil
}

4
Clocker/Overall App/Reach.swift

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

2
Clocker/Overall App/VersionUpdateHandler.swift

@ -25,7 +25,7 @@ class VersionUpdateHandler: NSObject {
private var appStoreCountry: String!
private var applicationVersion: String!
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 onlyPromptIfMainWindowIsAvailable: Bool = true
private var checkAtLaunch: Bool = true

22
Clocker/Panel/Data Layer/TimezoneDataOperations.swift

@ -7,7 +7,7 @@ import CoreModelKit
class TimezoneDataOperations: NSObject {
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 swiftyCalendar = Calendar(identifier: .gregorian)
private static let currentLocale = Locale.current.identifier
@ -22,12 +22,13 @@ extension TimezoneDataOperations {
guard let newDate = TimezoneDataOperations.gregorianCalendar?.date(byAdding: .minute,
value: sliderValue,
to: Date(),
options: .matchFirst) else {
options: .matchFirst)
else {
assertionFailure("Data was unexpectedly nil")
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 offset = timezone?.secondsFromGMT(for: newDate) ?? 0
let value = Int(Date().timeIntervalSince1970 + Double(offset))
@ -38,7 +39,6 @@ extension TimezoneDataOperations {
format: dataObject.timezoneFormat(DataStore.shared().timezoneFormat()),
timezoneIdentifier: dataObject.timezone(),
locale: Locale.autoupdatingCurrent)
return dateFormatter.string(from: newDate)
}
@ -52,7 +52,8 @@ extension TimezoneDataOperations {
guard let newDate = TimezoneDataOperations.gregorianCalendar?.date(byAdding: .minute,
value: sliderValue,
to: Date(),
options: .matchFirst) else {
options: .matchFirst)
else {
assertionFailure("Data was unexpectedly nil")
return nil
}
@ -204,8 +205,8 @@ extension TimezoneDataOperations {
let sourceTimezone = TimeZone.current
let destinationTimezone = TimeZone(identifier: dataObject.timezone())
let sourceGMTOffset: Double = Double(sourceTimezone.secondsFromGMT(for: source))
let destinationGMTOffset: Double = Double(destinationTimezone?.secondsFromGMT(for: source) ?? 0)
let sourceGMTOffset = Double(sourceTimezone.secondsFromGMT(for: source))
let destinationGMTOffset = Double(destinationTimezone?.secondsFromGMT(for: source) ?? 0)
let interval = destinationGMTOffset - sourceGMTOffset
return Date(timeInterval: interval, since: source)
@ -367,12 +368,13 @@ extension TimezoneDataOperations {
to: Date())
guard let lat = dataObject.latitude,
let long = dataObject.longitude else {
let long = dataObject.longitude
else {
assertionFailure("Data was unexpectedly nil.")
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 {
return

2
Clocker/Panel/FloatingWindowController.swift

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

14
Clocker/Panel/Notes Popover/NotesPopover.swift

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

26
Clocker/Panel/PanelController.swift

@ -152,7 +152,8 @@ class PanelController: ParentPanelController {
}
if let statusWindow = statusBackgroundWindow,
let statusButton = statusView {
let statusButton = statusView
{
var statusItemFrame = statusWindow.convertToScreen(statusButton.frame)
var statusItemScreen = NSScreen.main
var testPoint = statusItemFrame.origin
@ -184,16 +185,17 @@ class PanelController: ParentPanelController {
let preferences = DataStore.shared().timezones()
guard let theme = DataStore.shared().retrieve(key: CLThemeKey) as? NSNumber,
let displayFutureSliderKey = DataStore.shared().retrieve(key: CLThemeKey) as? NSNumber,
let showAppInForeground = DataStore.shared().retrieve(key: CLShowAppInForeground) as? NSNumber,
let relativeDateKey = DataStore.shared().retrieve(key: CLRelativeDateKey) as? NSNumber,
let fontSize = DataStore.shared().retrieve(key: CLUserFontSizePreference) as? NSNumber,
let sunriseTime = DataStore.shared().retrieve(key: CLSunriseSunsetTime) as? NSNumber,
let showDayInMenu = DataStore.shared().retrieve(key: CLShowDayInMenu) as? NSNumber,
let showDateInMenu = DataStore.shared().retrieve(key: CLShowDateInMenu) as? NSNumber,
let showPlaceInMenu = DataStore.shared().retrieve(key: CLShowPlaceInMenu) as? NSNumber,
let showUpcomingEventView = DataStore.shared().retrieve(key: CLShowUpcomingEventView) as? String,
let country = Locale.autoupdatingCurrent.regionCode else {
let displayFutureSliderKey = DataStore.shared().retrieve(key: CLThemeKey) as? NSNumber,
let showAppInForeground = DataStore.shared().retrieve(key: CLShowAppInForeground) as? NSNumber,
let relativeDateKey = DataStore.shared().retrieve(key: CLRelativeDateKey) as? NSNumber,
let fontSize = DataStore.shared().retrieve(key: CLUserFontSizePreference) as? NSNumber,
let sunriseTime = DataStore.shared().retrieve(key: CLSunriseSunsetTime) as? NSNumber,
let showDayInMenu = DataStore.shared().retrieve(key: CLShowDayInMenu) as? NSNumber,
let showDateInMenu = DataStore.shared().retrieve(key: CLShowDateInMenu) as? NSNumber,
let showPlaceInMenu = DataStore.shared().retrieve(key: CLShowPlaceInMenu) as? NSNumber,
let showUpcomingEventView = DataStore.shared().retrieve(key: CLShowUpcomingEventView) as? String,
let country = Locale.autoupdatingCurrent.regionCode
else {
return
}
@ -313,7 +315,7 @@ class PanelController: ParentPanelController {
}
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 {
return nil

1
Clocker/Panel/ParentPanelController+ModernSlider.swift

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

31
Clocker/Panel/ParentPanelController.swift

@ -37,7 +37,7 @@ class ParentPanelController: NSWindowController {
var datasource: TimezoneDataSource?
private lazy var feedbackWindow: AppFeedbackWindowController = AppFeedbackWindowController.shared()
private lazy var feedbackWindow = AppFeedbackWindowController.shared()
private var notePopover: NotesPopover?
@ -395,7 +395,7 @@ class ParentPanelController: NSWindowController {
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)
}
@ -425,8 +425,9 @@ class ParentPanelController: NSWindowController {
if let note = object?.note, note.isEmpty == false {
newHeight += 20
} else if DataStore.shared().shouldDisplay(.dstTransitionInfo),
let obj = object,
TimezoneDataOperations(with: obj).nextDaylightSavingsTransitionIfAvailable(with: futureSliderValue) != nil {
let obj = object,
TimezoneDataOperations(with: obj).nextDaylightSavingsTransitionIfAvailable(with: futureSliderValue) != nil
{
newHeight += 20
}
}
@ -496,7 +497,7 @@ class ParentPanelController: NSWindowController {
updatePanelColor()
let defaults = DataStore.shared().timezones()
let convertedTimezones = defaults.map { (data) -> TimezoneData in
let convertedTimezones = defaults.map { data -> TimezoneData in
TimezoneData.customObject(from: data)!
}
@ -533,7 +534,8 @@ class ParentPanelController: NSWindowController {
let currentCalendar = Calendar(identifier: .gregorian)
guard let newDate = currentCalendar.date(byAdding: .minute,
value: Int(futureSlider.doubleValue),
to: Date()) else {
to: Date())
else {
assertionFailure("Data was unexpectedly nil")
return
}
@ -599,8 +601,9 @@ class ParentPanelController: NSWindowController {
let current = preferences[$0]
if $0 < mainTableView.numberOfRows,
let cellView = mainTableView.view(atColumn: 0, row: $0, makeIfNecessary: false) as? TimezoneCellView,
let model = TimezoneData.customObject(from: current) {
let cellView = mainTableView.view(atColumn: 0, row: $0, makeIfNecessary: false) as? TimezoneCellView,
let model = TimezoneData.customObject(from: current)
{
if let futureSliderCell = futureSlider.cell as? CustomSliderCell, futureSliderCell.tracking == true {
return
}
@ -620,7 +623,8 @@ class ParentPanelController: NSWindowController {
if let note = model.note, !note.isEmpty {
cellView.noteLabel.stringValue = note
} 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
} else {
cellView.noteLabel.stringValue = CLEmptyString
@ -719,7 +723,8 @@ class ParentPanelController: NSWindowController {
@IBAction func calendarButtonAction(_: NSButton) {
if calendarButton.title == NSLocalizedString("Click here to start.",
comment: "Button Title for no Calendar access") {
comment: "Button Title for no Calendar access")
{
showPermissionsWindow()
} else {
retrieveCalendarEvents()
@ -840,7 +845,7 @@ class ParentPanelController: NSWindowController {
let withoutAgo = withoutAn.replacingOccurrences(of: "ago", with: CLEmptyString)
self.setCalendarButtonTitle(buttonTitle: "in \(withoutAgo.lowercased())")
if upcomingEvent.meetingURL != nil {
self.whiteRemoveButton.image = Themer.shared().videoCallImage()
}
@ -1033,7 +1038,7 @@ class ParentPanelController: NSWindowController {
@objc func openCrowdin() {
guard let localizationURL = URL(string: AboutUsConstants.CrowdInLocalizationLink),
let languageCode = Locale.preferredLanguages.first else { return }
let languageCode = Locale.preferredLanguages.first else { return }
NSWorkspace.shared.open(localizationURL)
@ -1112,7 +1117,7 @@ extension ParentPanelController: NSSharingServicePickerDelegate {
let filteredServices = proposed.filter { service in
allowedServices.contains(service.title)
}
var newProposedServices: [NSSharingService] = [copySharingService]
newProposedServices.append(contentsOf: filteredServices)
return newProposedServices

4
Clocker/Panel/Rate Controller/ReviewController.swift

@ -42,12 +42,12 @@ final class ReviewController {
// Check if the app has been installed for atleast 7 days
guard let install = storage.object(forKey: Keys.install) as? Date,
install.timeIntervalSinceNow < minInstall
install.timeIntervalSinceNow < minInstall
else { return false }
// If we have never been prompted before, go ahead and prompt
guard let lastPrompt = storage.object(forKey: Keys.lastPrompt) as? Date,
let lastVersion = storage.object(forKey: Keys.lastVersion) as? String
let lastVersion = storage.object(forKey: Keys.lastVersion) as? String
else { return true }
// Minimum interval between two versions should be 45

2
Clocker/Panel/Rate Controller/UpcomingEventView.swift

@ -89,7 +89,7 @@ class ThinScroller: NSScroller {
class DraggableClipView: NSClipView {
private var clickPoint: NSPoint!
private var trackingArea: NSTrackingArea?
override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
clickPoint = event.locationInWindow

13
Clocker/Panel/UI/TimezoneCellView.swift

@ -39,7 +39,7 @@ class TimezoneCellView: NSTableCellView {
func setupLayout() {
guard let relativeFont = relativeDate.font,
let sunriseFont = sunriseSetTime.font
let sunriseFont = sunriseSetTime.font
else {
assertionFailure("Unable to convert to NSString")
return
@ -128,7 +128,8 @@ class TimezoneCellView: NSTableCellView {
}
guard let customFont = customName.font,
let timeFont = time.font else {
let timeFont = time.font
else {
assertionFailure("User Font Size is in unexpectedly nil")
return
}
@ -164,7 +165,7 @@ class TimezoneCellView: NSTableCellView {
}
guard let panelTableView = searchView as? PanelTableView,
let enclosingScroller = panelTableView.enclosingScrollView
let enclosingScroller = panelTableView.enclosingScrollView
else {
// We might be coming from the preview tableview!
return
@ -203,9 +204,9 @@ class TimezoneCellView: NSTableCellView {
let pasteboard = NSPasteboard.general
pasteboard.declareTypes([.string], owner: nil)
pasteboard.setString(clipboardCopy, forType: .string)
self.window?.contentView?.makeToast("Copied to Clipboard".localized())
window?.contentView?.makeToast("Copied to Clipboard".localized())
window?.endEditing(for: nil)
}

2
Clocker/Panel/UI/TimezoneDataSource.swift

@ -145,7 +145,7 @@ extension TimezoneDataSource: NSTableViewDataSource, NSTableViewDelegate {
panelController.deleteTimezone(at: row)
}
})
})
if #available(OSX 11.0, *) {
swipeToDelete.image = Themer.shared().symbolImage(for: "trash.fill")

90
Clocker/Panel/UI/Toasty.swift

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

6
Clocker/Preferences/About/AboutViewController.swift

@ -98,7 +98,7 @@ class AboutViewController: ParentViewController {
@IBAction func openMyTwitter(_: Any) {
guard let twitterURL = URL(string: AboutUsConstants.TwitterLink),
let countryCode = Locale.autoupdatingCurrent.regionCode else { return }
let countryCode = Locale.autoupdatingCurrent.regionCode else { return }
NSWorkspace.shared.open(twitterURL)
@ -109,7 +109,7 @@ class AboutViewController: ParentViewController {
@IBAction func viewSource(_: Any) {
guard let sourceURL = URL(string: AboutUsConstants.AppStoreLink),
let countryCode = Locale.autoupdatingCurrent.regionCode else { return }
let countryCode = Locale.autoupdatingCurrent.regionCode else { return }
NSWorkspace.shared.open(sourceURL)
@ -131,7 +131,7 @@ class AboutViewController: ParentViewController {
@IBAction func openGitHub(_: Any) {
guard let localizationURL = URL(string: AboutUsConstants.CrowdInLocalizationLink),
let languageCode = Locale.preferredLanguages.first else { return }
let languageCode = Locale.preferredLanguages.first else { return }
NSWorkspace.shared.open(localizationURL)

12
Clocker/Preferences/App Feedback/AppFeedbackWindowController.swift

@ -11,7 +11,7 @@ extension NSNib.Name {
static let startAtLoginViewIdentifier = NSNib.Name("StartAtLoginView")
}
struct AppFeedbackConstants {
enum AppFeedbackConstants {
static let CLAppFeedbackNibIdentifier = "AppFeedbackWindow"
static let CLAppFeedbackNoResponseString = "Not Provided"
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() {
super.windowDidLoad()
@ -100,6 +100,7 @@ class AppFeedbackWindowController: NSWindowController {
}
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@ -132,7 +133,7 @@ class AppFeedbackWindowController: NSWindowController {
repeats: false,
block: { _ in
self.resetInformativeLabel()
})
})
isActivityInProgress = false
@ -144,7 +145,8 @@ class AppFeedbackWindowController: NSWindowController {
private func retrieveDataForSending() -> [String: 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 [:]
}
@ -248,7 +250,7 @@ class AppFeedbackWindowController: NSWindowController {
@IBAction func navigateToSupportTwitter(_: Any) {
guard let twitterURL = URL(string: AboutUsConstants.TwitterLink),
let countryCode = Locale.autoupdatingCurrent.regionCode else { return }
let countryCode = Locale.autoupdatingCurrent.regionCode else { return }
NSWorkspace.shared.open(twitterURL)

5
Clocker/Preferences/Appearance/AppearanceViewController.swift

@ -183,7 +183,8 @@ class AppearanceViewController: ParentViewController {
refresh(panel: true, floating: true)
if let selectedFormat = sender.selectedItem?.title,
selectedFormat.contains("ss") {
selectedFormat.contains("ss")
{
print("Seconds are contained")
guard let panelController = PanelController.panel() else { return }
panelController.pauseTimer()
@ -193,7 +194,7 @@ class AppearanceViewController: ParentViewController {
previewPanelTableView.reloadData()
}
private var previousBackgroundColor: NSColor = NSColor.white
private var previousBackgroundColor = NSColor.white
@IBAction func themeChanged(_ sender: NSSegmentedControl) {
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? {
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
return message
}
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.calendarSelected.state = currentSource.selected ? NSControl.StateValue.on : NSControl.StateValue.off
calendarCell.calendarSelected.target = self

7
Clocker/Preferences/General/PreferencesDataSource.swift

@ -104,7 +104,8 @@ extension PreferencesDataSource: NSTableViewDataSource {
var selectedDataSource: TimezoneData?
if selectedTimezones.count > row,
let model = TimezoneData.customObject(from: selectedTimezones[row]) {
let model = TimezoneData.customObject(from: selectedTimezones[row])
{
selectedDataSource = model
}
@ -163,7 +164,7 @@ extension PreferencesDataSource: NSTableViewDataSource {
"Old Label": dataObject.customLabel ?? "Error",
"New Label": formattedValue,
],
for: "Custom Label Changed")
for: "Custom Label Changed")
dataObject.setLabel(formattedValue)
@ -176,7 +177,7 @@ extension PreferencesDataSource: NSTableViewDataSource {
"Selected Timezone Count": selectedTimezones.count,
"Current Row": row,
],
for: "Error in selected row count")
for: "Error in selected row count")
}
}

45
Clocker/Preferences/General/PreferencesViewController.swift

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

2
Clocker/Preferences/General/SearchDataSource.swift

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

2
Clocker/Preferences/Menu Bar/MenubarHandler.swift

@ -21,7 +21,7 @@ class MenubarHandler: NSObject {
}
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 operationsObject = TimezoneDataOperations(with: timezone!)
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
|| timeFormat == DateFormat.twelveHourWithSeconds
|| timeFormat == DateFormat.twelveHourWithZero
|| timeFormat == DateFormat.twelveHourWithSeconds {
|| timeFormat == DateFormat.twelveHourWithSeconds
{
totalWidth += 20
} else if timeFormat == DateFormat.twentyFourHour
|| timeFormat == DateFormat.twentyFourHourWithSeconds {
|| timeFormat == DateFormat.twentyFourHourWithSeconds
{
totalWidth += 0
}
@ -81,7 +83,7 @@ class StatusContainerView: NSView {
]
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) {
let precalculatedWidth = Double(compactWidth(for: timezoneObject))
@ -108,6 +110,7 @@ class StatusContainerView: NSView {
addSubviews()
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

4
Clocker/Preferences/Menu Bar/StatusItemHandler.swift

@ -144,7 +144,7 @@ class StatusItemHandler: NSObject {
private func retrieveSyncedMenubarTimezones() -> [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) {
return timezoneObj.isFavourite == 1
}
@ -188,7 +188,7 @@ class StatusItemHandler: NSObject {
if let strongSelf = self {
strongSelf.performTimerWork()
}
})
})
// Tolerance, even a small amount, has a positive imapct on the power usage. As a rule, we set it to 10% of the interval
menubarTimer?.tolerance = shouldDisplaySeconds ? 0.5 : 20

5
Clocker/Preferences/Menu Bar/StatusItemView.swift

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

Loading…
Cancel
Save