Browse Source

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

pull/113/head
Abhishek 3 years ago
parent
commit
ac4b0bdfa4
  1. 25
      Clocker/AppDelegate.swift
  2. 26
      Clocker/Clocker.xcodeproj/project.pbxproj
  3. 34
      Clocker/Clocker/Utilities/CommonStrings.h
  4. 33
      Clocker/Clocker/Utilities/CommonStrings.m
  5. 1
      Clocker/ClockerUITests/ClockerUITests.m
  6. 130
      Clocker/ClockerUnitTests/ClockerUnitTests.swift
  7. 6
      Clocker/ClockerUnitTests/StandardMenubarHandlerTests.swift
  8. 38
      Clocker/CoreModelKit/Sources/CoreModelKit/TimezoneData.swift
  9. 6
      Clocker/CoreModelKit/Tests/CoreModelKitTests/TimezoneDataEqualityTests.swift
  10. 8
      Clocker/Overall App/AppDefaults.swift
  11. 23
      Clocker/Overall App/DataStore.swift
  12. 49
      Clocker/Panel/ParentPanelController.swift
  13. 2
      Clocker/Preferences/Appearance/AppearanceViewController.swift
  14. 8
      Clocker/Preferences/Menu Bar/StatusContainerView.swift
  15. 2
      Clocker/Preferences/Menu Bar/StatusItemHandler.swift

25
Clocker/AppDelegate.swift

@ -53,9 +53,6 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
AppDefaults.initialize() AppDefaults.initialize()
// For users, still on the old timezones, only migrate timezonezes once setClass has been called
migrateOverridenTimezones()
// Check if we can show the onboarding flow! // Check if we can show the onboarding flow!
showOnboardingFlowIfEligible() showOnboardingFlowIfEligible()
@ -68,28 +65,6 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
#endif #endif
} }
private func migrateOverridenTimezones() {
let defaults = UserDefaults.standard
if let shortCircuit = defaults.object(forKey: "MigrateIndividualTimezoneFormat") as? Bool, shortCircuit == true {
return
}
let timezones = DataStore.shared().timezones()
var migratedTimezones: [Data] = []
for encodedTimezone in timezones {
if let timezoneObject = TimezoneData.customObject(from: encodedTimezone) {
timezoneObject.setShouldOverrideGlobalTimeFormat(0)
migratedTimezones.append(NSKeyedArchiver.archivedData(withRootObject: timezoneObject))
}
}
if migratedTimezones.count > 0 {
defaults.set(migratedTimezones, forKey: CLDefaultPreferenceKey)
defaults.set(true, forKey: "MigrateIndividualTimezoneFormat")
}
}
public func applicationDockMenu(_: NSApplication) -> NSMenu? { public func applicationDockMenu(_: NSApplication) -> NSMenu? {
let menu = NSMenu(title: "Quick Access") let menu = NSMenu(title: "Quick Access")

26
Clocker/Clocker.xcodeproj/project.pbxproj

@ -123,7 +123,6 @@
35C36FA22259ED6D002FA5C6 /* RemindersHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F9F2259ED6D002FA5C6 /* RemindersHandler.swift */; }; 35C36FA22259ED6D002FA5C6 /* RemindersHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F9F2259ED6D002FA5C6 /* RemindersHandler.swift */; };
35C36FA42259EEC2002FA5C6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36FA32259EEC2002FA5C6 /* AppDelegate.swift */; }; 35C36FA42259EEC2002FA5C6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36FA32259EEC2002FA5C6 /* AppDelegate.swift */; };
35DFBCEF26A8468900D6648B /* ConfigExport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35DFBCEE26A8468900D6648B /* ConfigExport.swift */; }; 35DFBCEF26A8468900D6648B /* ConfigExport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35DFBCEE26A8468900D6648B /* ConfigExport.swift */; };
35DFBCF126A8479000D6648B /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 35DFBCF026A8479000D6648B /* Keys.plist */; };
35E65125268EDD2E00E3E1E3 /* Toasty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35E65124268EDD2E00E3E1E3 /* Toasty.swift */; }; 35E65125268EDD2E00E3E1E3 /* Toasty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35E65124268EDD2E00E3E1E3 /* Toasty.swift */; };
9A0385BB269E3434003B5E72 /* StandardMenubarHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0385BA269E3434003B5E72 /* StandardMenubarHandlerTests.swift */; }; 9A0385BB269E3434003B5E72 /* StandardMenubarHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0385BA269E3434003B5E72 /* StandardMenubarHandlerTests.swift */; };
9A0385C0269E8891003B5E72 /* PermissionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0385BF269E8891003B5E72 /* PermissionsTests.swift */; }; 9A0385C0269E8891003B5E72 /* PermissionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0385BF269E8891003B5E72 /* PermissionsTests.swift */; };
@ -131,12 +130,12 @@
9A13BAD61CA87F08007C6CBE /* Panel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9A13BAD81CA87F08007C6CBE /* Panel.xib */; }; 9A13BAD61CA87F08007C6CBE /* Panel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9A13BAD81CA87F08007C6CBE /* Panel.xib */; };
9A13BAE01CA882FA007C6CBE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9A13BAE21CA882FA007C6CBE /* InfoPlist.strings */; }; 9A13BAE01CA882FA007C6CBE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9A13BAE21CA882FA007C6CBE /* InfoPlist.strings */; };
9A13BAEA1CA88A76007C6CBE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9A13BAEC1CA88A76007C6CBE /* Localizable.strings */; }; 9A13BAEA1CA88A76007C6CBE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9A13BAEC1CA88A76007C6CBE /* Localizable.strings */; };
9A159CEB27B00E3300570529 /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A159CEA27B00E3300570529 /* Keys.plist */; };
9A20A04B1C4DEED200FB45AB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A20A04A1C4DEED200FB45AB /* IOKit.framework */; }; 9A20A04B1C4DEED200FB45AB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A20A04A1C4DEED200FB45AB /* IOKit.framework */; };
9A24A1881ED902CC0095201E /* EventKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A24A1871ED902CC0095201E /* EventKit.framework */; }; 9A24A1881ED902CC0095201E /* EventKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A24A1871ED902CC0095201E /* EventKit.framework */; };
9A3169C11D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A3169C01D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist */; }; 9A3169C11D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A3169C01D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist */; };
9A43792A1BEC230A00F4E27F /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4379291BEC230A00F4E27F /* libc++.tbd */; }; 9A43792A1BEC230A00F4E27F /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4379291BEC230A00F4E27F /* libc++.tbd */; };
9A56DB801C1CFB73004CE6AF /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9A56DB7D1C1CFB73004CE6AF /* MainMenu.xib */; }; 9A56DB801C1CFB73004CE6AF /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9A56DB7D1C1CFB73004CE6AF /* MainMenu.xib */; };
9A5951BD1C1D0A8D009C17AA /* CommonStrings.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A5951BB1C1D0A8D009C17AA /* CommonStrings.m */; };
9A5E75E4204CC39700119939 /* ShortcutRecorder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A86E2BC1CE04F1600547EE7 /* ShortcutRecorder.framework */; }; 9A5E75E4204CC39700119939 /* ShortcutRecorder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A86E2BC1CE04F1600547EE7 /* ShortcutRecorder.framework */; };
9A5E75E5204CC39700119939 /* ShortcutRecorder.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9A86E2BC1CE04F1600547EE7 /* ShortcutRecorder.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9A5E75E5204CC39700119939 /* ShortcutRecorder.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9A86E2BC1CE04F1600547EE7 /* ShortcutRecorder.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9A5E75E8204CC39700119939 /* PTHotKey.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A86E2BE1CE04F1600547EE7 /* PTHotKey.framework */; }; 9A5E75E8204CC39700119939 /* PTHotKey.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A86E2BE1CE04F1600547EE7 /* PTHotKey.framework */; };
@ -362,13 +361,13 @@
35C36F9F2259ED6D002FA5C6 /* RemindersHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemindersHandler.swift; sourceTree = "<group>"; }; 35C36F9F2259ED6D002FA5C6 /* RemindersHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemindersHandler.swift; sourceTree = "<group>"; };
35C36FA32259EEC2002FA5C6 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = SOURCE_ROOT; }; 35C36FA32259EEC2002FA5C6 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = SOURCE_ROOT; };
35DFBCEE26A8468900D6648B /* ConfigExport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigExport.swift; sourceTree = "<group>"; }; 35DFBCEE26A8468900D6648B /* ConfigExport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigExport.swift; sourceTree = "<group>"; };
35DFBCF026A8479000D6648B /* Keys.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Keys.plist; path = ../Internal/Keys.plist; sourceTree = "<group>"; };
35E65124268EDD2E00E3E1E3 /* Toasty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toasty.swift; sourceTree = "<group>"; }; 35E65124268EDD2E00E3E1E3 /* Toasty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toasty.swift; sourceTree = "<group>"; };
9A0385BA269E3434003B5E72 /* StandardMenubarHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardMenubarHandlerTests.swift; sourceTree = "<group>"; }; 9A0385BA269E3434003B5E72 /* StandardMenubarHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardMenubarHandlerTests.swift; sourceTree = "<group>"; };
9A0385BF269E8891003B5E72 /* PermissionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionsTests.swift; sourceTree = "<group>"; }; 9A0385BF269E8891003B5E72 /* PermissionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionsTests.swift; sourceTree = "<group>"; };
9A13BAD71CA87F08007C6CBE /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/Panel.xib; sourceTree = "<group>"; }; 9A13BAD71CA87F08007C6CBE /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/Panel.xib; sourceTree = "<group>"; };
9A13BAE11CA882FA007C6CBE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 9A13BAE11CA882FA007C6CBE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
9A13BAEB1CA88A76007C6CBE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; }; 9A13BAEB1CA88A76007C6CBE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
9A159CEA27B00E3300570529 /* Keys.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Keys.plist; path = Internal/Keys.plist; sourceTree = "<group>"; };
9A20A04A1C4DEED200FB45AB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 9A20A04A1C4DEED200FB45AB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
9A20A06F1C4E804D00FB45AB /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; 9A20A06F1C4E804D00FB45AB /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
9A24A1871ED902CC0095201E /* EventKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EventKit.framework; path = System/Library/Frameworks/EventKit.framework; sourceTree = SDKROOT; }; 9A24A1871ED902CC0095201E /* EventKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EventKit.framework; path = System/Library/Frameworks/EventKit.framework; sourceTree = SDKROOT; };
@ -386,8 +385,6 @@
9A4DC4E82337F5D600F03FA4 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 9A4DC4E82337F5D600F03FA4 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = "<group>"; };
9A4DC4E92337F5D600F03FA4 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; }; 9A4DC4E92337F5D600F03FA4 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
9A56DB7D1C1CFB73004CE6AF /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MainMenu.xib; path = Clocker/MainMenu.xib; sourceTree = "<group>"; }; 9A56DB7D1C1CFB73004CE6AF /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MainMenu.xib; path = Clocker/MainMenu.xib; sourceTree = "<group>"; };
9A5951BB1C1D0A8D009C17AA /* CommonStrings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CommonStrings.m; path = Clocker/Utilities/CommonStrings.m; sourceTree = "<group>"; };
9A5951BC1C1D0A8D009C17AA /* CommonStrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommonStrings.h; path = Clocker/Utilities/CommonStrings.h; sourceTree = "<group>"; };
9A5B1A8D1BECDFB700A77C68 /* Clocker.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = Clocker.entitlements; path = Clocker/Clocker.entitlements; sourceTree = "<group>"; }; 9A5B1A8D1BECDFB700A77C68 /* Clocker.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = Clocker.entitlements; path = Clocker/Clocker.entitlements; sourceTree = "<group>"; };
9A5E6B9F1CAF71C1006E7C5C /* libicucore.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libicucore.tbd; path = usr/lib/libicucore.tbd; sourceTree = SDKROOT; }; 9A5E6B9F1CAF71C1006E7C5C /* libicucore.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libicucore.tbd; path = usr/lib/libicucore.tbd; sourceTree = SDKROOT; };
9A6D93361CF3E82F005A8690 /* CoreImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; }; 9A6D93361CF3E82F005A8690 /* CoreImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; };
@ -727,8 +724,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
9A3169C01D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist */, 9A3169C01D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist */,
9A5951BB1C1D0A8D009C17AA /* CommonStrings.m */,
9A5951BC1C1D0A8D009C17AA /* CommonStrings.h */,
9A13BAE21CA882FA007C6CBE /* InfoPlist.strings */, 9A13BAE21CA882FA007C6CBE /* InfoPlist.strings */,
9A13BAEC1CA88A76007C6CBE /* Localizable.strings */, 9A13BAEC1CA88A76007C6CBE /* Localizable.strings */,
C2CCCD8120619C4C00F2DFC2 /* LocationController.swift */, C2CCCD8120619C4C00F2DFC2 /* LocationController.swift */,
@ -914,7 +909,7 @@
DD4F7BF913C30F9F00825C6E = { DD4F7BF913C30F9F00825C6E = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
35DFBCF026A8479000D6648B /* Keys.plist */, 9A159CEA27B00E3300570529 /* Keys.plist */,
35B2FEE4259A2C25005DA84D /* CoreModelKit */, 35B2FEE4259A2C25005DA84D /* CoreModelKit */,
35B2FED4259A2244005DA84D /* CoreLoggerKit */, 35B2FED4259A2244005DA84D /* CoreLoggerKit */,
35B2FEB1259A1649005DA84D /* StartupKit */, 35B2FEB1259A1649005DA84D /* StartupKit */,
@ -1221,6 +1216,7 @@
35C36F972259EBB1002FA5C6 /* AppFeedbackWindow.xib in Resources */, 35C36F972259EBB1002FA5C6 /* AppFeedbackWindow.xib in Resources */,
9A13BAE01CA882FA007C6CBE /* InfoPlist.strings in Resources */, 9A13BAE01CA882FA007C6CBE /* InfoPlist.strings in Resources */,
35C36F912259EAF4002FA5C6 /* Preferences.storyboard in Resources */, 35C36F912259EAF4002FA5C6 /* Preferences.storyboard in Resources */,
9A159CEB27B00E3300570529 /* Keys.plist in Resources */,
9AB89E031CE97A4900EC8EB1 /* Media.xcassets in Resources */, 9AB89E031CE97A4900EC8EB1 /* Media.xcassets in Resources */,
9A13BAD61CA87F08007C6CBE /* Panel.xib in Resources */, 9A13BAD61CA87F08007C6CBE /* Panel.xib in Resources */,
35C36F6B2259E0E1002FA5C6 /* FloatingWindow.xib in Resources */, 35C36F6B2259E0E1002FA5C6 /* FloatingWindow.xib in Resources */,
@ -1228,7 +1224,6 @@
35C36F17225961DA002FA5C6 /* DateTools.bundle in Resources */, 35C36F17225961DA002FA5C6 /* DateTools.bundle in Resources */,
35C36EF322595F14002FA5C6 /* WelcomeView.xib in Resources */, 35C36EF322595F14002FA5C6 /* WelcomeView.xib in Resources */,
3548C45A26BECF1B00AFB533 /* UpcomingEventViewItem.xib in Resources */, 3548C45A26BECF1B00AFB533 /* UpcomingEventViewItem.xib in Resources */,
35DFBCF126A8479000D6648B /* Keys.plist in Resources */,
35C36EF822595F14002FA5C6 /* Onboarding.storyboard in Resources */, 35C36EF822595F14002FA5C6 /* Onboarding.storyboard in Resources */,
35C36F612259DE67002FA5C6 /* NotesPopover.xib in Resources */, 35C36F612259DE67002FA5C6 /* NotesPopover.xib in Resources */,
9A3169C11D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist in Resources */, 9A3169C11D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist in Resources */,
@ -1316,7 +1311,6 @@
35C36F452259D892002FA5C6 /* Strings.swift in Sources */, 35C36F452259D892002FA5C6 /* Strings.swift in Sources */,
35C36EF722595F14002FA5C6 /* FinalOnboardingViewController.swift in Sources */, 35C36EF722595F14002FA5C6 /* FinalOnboardingViewController.swift in Sources */,
35C36FA12259ED6D002FA5C6 /* EventCenter.swift in Sources */, 35C36FA12259ED6D002FA5C6 /* EventCenter.swift in Sources */,
9A5951BD1C1D0A8D009C17AA /* CommonStrings.m in Sources */,
357391872507277500D30819 /* TimeMarkerViewItem.swift in Sources */, 357391872507277500D30819 /* TimeMarkerViewItem.swift in Sources */,
35C36F782259E1D0002FA5C6 /* Foundation + Additions.swift in Sources */, 35C36F782259E1D0002FA5C6 /* Foundation + Additions.swift in Sources */,
35C36F16225961DA002FA5C6 /* Date+Inits.swift in Sources */, 35C36F16225961DA002FA5C6 /* Date+Inits.swift in Sources */,
@ -1578,7 +1572,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 = 98; CURRENT_PROJECT_VERSION = 103;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@ -1611,7 +1605,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 21.08.01; MARKETING_VERSION = 22.03;
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;
@ -2157,7 +2151,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 = 98; CURRENT_PROJECT_VERSION = 103;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
@ -2191,7 +2185,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 21.08.01; MARKETING_VERSION = 22.03;
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";
@ -2239,7 +2233,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 = 98; CURRENT_PROJECT_VERSION = 103;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@ -2272,7 +2266,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 21.08.01; MARKETING_VERSION = 22.03;
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";

34
Clocker/Clocker/Utilities/CommonStrings.h

@ -1,34 +0,0 @@
// Copyright © 2015 Abhishek Banthia
#import <Foundation/Foundation.h>
@interface CommonStrings : NSObject
extern NSString *const CLEmptyString;
extern NSString *const CLDefaultPreferenceKey;
extern NSString *const CLTimezoneName;
extern NSString *const CLCustomLabel;
extern NSString *const CL24hourFormatSelectedKey;
extern NSString *const CLDragSessionKey;
extern NSString *const CLTimezoneID;
extern NSString *const CLPlaceIdentifier;
extern NSString *const CLRelativeDateKey;
extern NSString *const CLThemeKey;
extern NSString *const CLShowDayInMenu;
extern NSString *const CLShowDateInMenu;
extern NSString *const CLShowPlaceInMenu;
extern NSString *const CLDisplayFutureSliderKey;
extern NSString *const CLStartAtLogin;
extern NSString *const CLShowAppInForeground;
extern NSString *const CLSunriseSunsetTime;
extern NSString *const CLLocationSearchURL;
extern NSString *const CLShowSecondsInMenubar;
extern NSString *const CLUserFontSizePreference;
extern NSString *const CLShowUpcomingEventView;
extern NSString *const CLShowAllDayEventsInUpcomingView;
extern NSString *const CLShowMeetingInMenubar;
extern NSString *const CLTruncateTextLength;
extern NSString *const CLFutureSliderRange;
extern NSString *const CLSelectedCalendars;
@end

33
Clocker/Clocker/Utilities/CommonStrings.m

@ -1,33 +0,0 @@
// Copyright © 2015 Abhishek Banthia
#import "CommonStrings.h"
@implementation CommonStrings
NSString *const CLEmptyString = @"";
NSString *const CLDefaultPreferenceKey = @"defaultPreferences";
NSString *const CLTimezoneName = @"formattedAddress";
NSString *const CLPlaceIdentifier = @"place_id";
NSString *const CLTimezoneID = @"timezoneID";
NSString *const CLCustomLabel = @"customLabel";
NSString *const CL24hourFormatSelectedKey = @"is24HourFormatSelected";
NSString *const CLDragSessionKey = @"public.text";
NSString *const CLRelativeDateKey = @"relativeDate";
NSString *const CLThemeKey = @"defaultTheme";
NSString *const CLDisplayFutureSliderKey = @"displayFutureSlider";
NSString *const CLShowDayInMenu = @"showDay";
NSString *const CLShowDateInMenu = @"showDate";
NSString *const CLShowPlaceInMenu = @"showPlaceName";
NSString *const CLStartAtLogin = @"startAtLogin";
NSString *const CLShowAppInForeground = @"displayAppAsForegroundApp";
NSString *const CLSunriseSunsetTime = @"showSunriseSetTime";
NSString *const CLShowSecondsInMenubar = @"showSeconds";
NSString *const CLUserFontSizePreference = @"userFontSize";
NSString *const CLShowUpcomingEventView = @"ShowUpcomingEventView";
NSString *const CLFutureSliderRange = @"sliderDayRange";
NSString *const CLShowAllDayEventsInUpcomingView = @"showAllDayEventsInUpcomingView";
NSString *const CLShowMeetingInMenubar = @"showMeetingInfoInMenubar";
NSString *const CLTruncateTextLength = @"truncateTextLength";
NSString *const CLSelectedCalendars = @"SelectedCalendars";
@end

1
Clocker/ClockerUITests/ClockerUITests.m

@ -1,7 +1,6 @@
// Copyright © 2015 Abhishek Banthia // Copyright © 2015 Abhishek Banthia
#import <XCTest/XCTest.h> #import <XCTest/XCTest.h>
#import "CommonStrings.h"
@interface ClockerUITests : XCTestCase @interface ClockerUITests : XCTestCase

130
Clocker/ClockerUnitTests/ClockerUnitTests.swift

@ -94,27 +94,54 @@ class ClockerUnitTests: XCTestCase {
func testAddingATimezoneToDefaults() { func testAddingATimezoneToDefaults() {
let timezoneData = TimezoneData(with: california) let timezoneData = TimezoneData(with: california)
let currentFavourites = DataStore.shared().timezones()
let defaults = UserDefaults.standard
let currentFavourites = (defaults.object(forKey: CLDefaultPreferenceKey) as? [Data]) ?? []
let oldCount = currentFavourites.count let oldCount = currentFavourites.count
let operationsObject = TimezoneDataOperations(with: timezoneData) let operationsObject = TimezoneDataOperations(with: timezoneData)
operationsObject.saveObject() operationsObject.saveObject()
let newDefaults = UserDefaults.standard.object(forKey: CLDefaultPreferenceKey) as? [Data] let newDefaults = DataStore.shared().timezones()
XCTAssert(newDefaults != nil) XCTAssert(newDefaults.isEmpty == false)
XCTAssert(newDefaults?.count == oldCount + 1) XCTAssert(newDefaults.count == oldCount + 1)
}
func testDecoding() {
let timezone1 = TimezoneData.customObject(from: nil)
XCTAssertNotNil(timezone1)
let data = Data()
let timezone2 = TimezoneData.customObject(from: data)
XCTAssertNil(timezone2)
}
func testDescription() {
let timezoneData = TimezoneData(with: california)
XCTAssertFalse(timezoneData.description.isEmpty)
XCTAssertFalse(timezoneData.debugDescription.isEmpty)
}
func testHashing() {
let timezoneData = TimezoneData(with: california)
XCTAssert(timezoneData.hash != -1)
timezoneData.placeID = nil
timezoneData.timezoneID = nil
XCTAssert(timezoneData.hash == -1)
}
func testBadInputDictionaryForInitialization() {
let badInput: [String: Any] = ["customLabel": "",
"latitude": "41.2565369",
"longitude": "-95.9345034"]
let badTimezoneData = TimezoneData(with: badInput)
XCTAssertEqual(badTimezoneData.placeID, "Error")
XCTAssertEqual(badTimezoneData.timezoneID, "Error")
XCTAssertEqual(badTimezoneData.formattedAddress, "Error")
} }
func testDeletingATimezone() { func testDeletingATimezone() {
let defaults = UserDefaults.standard var currentFavourites = DataStore.shared().timezones()
guard var currentFavourites = defaults.object(forKey: CLDefaultPreferenceKey) as? [Data] else {
XCTFail("Default preferences aren't in the correct format")
return
}
// Check if timezone with test identifier is present. // Check if timezone with test identifier is present.
let filteredCount = currentFavourites.filter { let filteredCount = currentFavourites.filter {
let timezone = TimezoneData.customObject(from: $0) let timezone = TimezoneData.customObject(from: $0)
@ -128,14 +155,14 @@ class ClockerUnitTests: XCTestCase {
operationsObject.saveObject() operationsObject.saveObject()
} }
let oldCount = (defaults.object(forKey: CLDefaultPreferenceKey) as? [Data])?.count ?? 0 let oldCount = DataStore.shared().timezones().count
currentFavourites = currentFavourites.filter { currentFavourites = currentFavourites.filter {
let timezone = TimezoneData.customObject(from: $0) let timezone = TimezoneData.customObject(from: $0)
return timezone?.placeID != "TestIdentifier" return timezone?.placeID != "TestIdentifier"
} }
defaults.set(currentFavourites, forKey: CLDefaultPreferenceKey) DataStore.shared().setTimezones(currentFavourites)
XCTAssertTrue(currentFavourites.count == oldCount - 1) XCTAssertTrue(currentFavourites.count == oldCount - 1)
} }
@ -143,10 +170,10 @@ class ClockerUnitTests: XCTestCase {
// The below test might fail outside California or if DST is active! // The below test might fail outside California or if DST is active!
// CI is calibrated to be on LA timezone! // CI is calibrated to be on LA timezone!
func testTimeDifference() { func testTimeDifference() {
XCTAssertTrue(operations.timeDifference() == ", 10h 30m ahead", "Difference was unexpectedly: \(operations.timeDifference())") XCTAssertTrue(operations.timeDifference() == ", 9h 30m ahead", "Difference was unexpectedly: \(operations.timeDifference())")
XCTAssertTrue(californiaOperations.timeDifference() == ", 3h behind", "Difference was unexpectedly: \(californiaOperations.timeDifference())") XCTAssertTrue(californiaOperations.timeDifference() == ", 3h behind", "Difference was unexpectedly: \(californiaOperations.timeDifference())")
XCTAssertTrue(floridaOperations.timeDifference() == "", "Difference was unexpectedly: \(floridaOperations.timeDifference())") XCTAssertTrue(floridaOperations.timeDifference() == "", "Difference was unexpectedly: \(floridaOperations.timeDifference())")
XCTAssertTrue(aucklandOperations.timeDifference() == ", 18h ahead", "Difference was unexpectedly: \(aucklandOperations.timeDifference())") XCTAssertTrue(aucklandOperations.timeDifference() == ", 17h ahead", "Difference was unexpectedly: \(aucklandOperations.timeDifference())")
XCTAssertTrue(omahaOperations.timeDifference() == ", an hour behind", "Difference was unexpectedly: \(omahaOperations.timeDifference())") XCTAssertTrue(omahaOperations.timeDifference() == ", an hour behind", "Difference was unexpectedly: \(omahaOperations.timeDifference())")
} }
@ -207,6 +234,10 @@ class ClockerUnitTests: XCTestCase {
dataObject.setShouldOverrideGlobalTimeFormat(11) // 12-hour with preceding zero and seconds dataObject.setShouldOverrideGlobalTimeFormat(11) // 12-hour with preceding zero and seconds
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm:ss") XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm:ss")
// Wrong input
dataObject.setShouldOverrideGlobalTimeFormat(0) // 12-hour with preceding zero and seconds
XCTAssertTrue(dataObject.timezoneFormat(88) == "h:mm a")
} }
func testTimezoneFormatWithDefaultSetAs24HourFormat() { func testTimezoneFormatWithDefaultSetAs24HourFormat() {
@ -214,7 +245,8 @@ class ClockerUnitTests: XCTestCase {
UserDefaults.standard.set(NSNumber(value: 1), forKey: CLSelectedTimeZoneFormatKey) // Set to 24-Hour Format UserDefaults.standard.set(NSNumber(value: 1), forKey: CLSelectedTimeZoneFormatKey) // Set to 24-Hour Format
dataObject.setShouldOverrideGlobalTimeFormat(0) dataObject.setShouldOverrideGlobalTimeFormat(0)
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "HH:mm") XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "HH:mm",
"Unexpected format returned: \(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()))")
dataObject.setShouldOverrideGlobalTimeFormat(1) // 12-Hour Format dataObject.setShouldOverrideGlobalTimeFormat(1) // 12-Hour Format
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "h:mm a") XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "h:mm a")
@ -242,17 +274,73 @@ class ClockerUnitTests: XCTestCase {
dataObject.setShouldOverrideGlobalTimeFormat(11) // 12-hour with preceding zero and seconds dataObject.setShouldOverrideGlobalTimeFormat(11) // 12-hour with preceding zero and seconds
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm:ss") XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm:ss")
dataObject.setShouldOverrideGlobalTimeFormat(12) // 12-hour with preceding zero and seconds
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "epoch")
}
func testSecondsDisplayForOverridenTimezone() {
let dataObject = TimezoneData(with: california)
UserDefaults.standard.set(NSNumber(value: 1), forKey: CLSelectedTimeZoneFormatKey) // Set to 24-Hour Format
// Test default behaviour
let timezoneWithSecondsKeys = [4,5,8,11]
for timezoneKey in timezoneWithSecondsKeys {
dataObject.setShouldOverrideGlobalTimeFormat(timezoneKey)
XCTAssertTrue(dataObject.shouldShowSeconds(DataStore.shared().timezoneFormat()))
}
let timezoneWithoutSecondsKeys = [1,2,7,10]
for timezoneKey in timezoneWithoutSecondsKeys {
dataObject.setShouldOverrideGlobalTimeFormat(timezoneKey)
XCTAssertFalse(dataObject.shouldShowSeconds(DataStore.shared().timezoneFormat()))
}
// Test wrong override timezone key
let wrongTimezoneKey = 88
dataObject.setShouldOverrideGlobalTimeFormat(wrongTimezoneKey)
XCTAssertFalse(dataObject.shouldShowSeconds(DataStore.shared().timezoneFormat()))
// Test wrong global preference key
dataObject.setShouldOverrideGlobalTimeFormat(0)
XCTAssertFalse(dataObject.shouldShowSeconds(88))
}
func testTimezoneRetrieval() {
let dataObject = TimezoneData(with: mumbai)
let autoupdatingTimezone = TimeZone.autoupdatingCurrent.identifier
XCTAssertEqual(dataObject.timezone(), "Asia/Calcutta")
// Unlikely
dataObject.timezoneID = nil
XCTAssertEqual(dataObject.timezone(), autoupdatingTimezone)
dataObject.isSystemTimezone = true
XCTAssertEqual(dataObject.timezone(), autoupdatingTimezone)
} }
func testFormattedLabel() { func testFormattedLabel() {
let dataObject = TimezoneData(with: mumbai) let dataObject = TimezoneData(with: mumbai)
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Ghar", "Incorrect custom label returned by model.") XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Ghar", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())")
dataObject.customLabel = nil dataObject.setLabel("")
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Mumbai", "Incorrect custom label returned by model.") XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Mumbai", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())")
dataObject.formattedAddress = nil dataObject.formattedAddress = nil
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Asia", "Incorrect custom label returned by model.") XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Asia", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())")
dataObject.setLabel("Jogeshwari")
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Jogeshwari", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())")
// Unlikely scenario
dataObject.setLabel("")
dataObject.timezoneID = "GMT"
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "GMT", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())")
// Another unlikely scenario
dataObject.setLabel("")
dataObject.timezoneID = nil
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Error", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())")
} }
func testEquality() { func testEquality() {

6
Clocker/ClockerUnitTests/StandardMenubarHandlerTests.swift

@ -16,7 +16,7 @@ class StandardMenubarHandlerTests: XCTestCase {
func testValidStandardMenubarHandler_returnMenubarTitle() { func testValidStandardMenubarHandler_returnMenubarTitle() {
// Wipe all timezones from UserDefaults // Wipe all timezones from UserDefaults
UserDefaults.standard.setValue(nil, forKey: CLDefaultPreferenceKey) DataStore.shared().setTimezones(nil)
// Save a menubar selected timezone // Save a menubar selected timezone
let dataObject = TimezoneData(with: mumbai) let dataObject = TimezoneData(with: mumbai)
@ -43,7 +43,7 @@ class StandardMenubarHandlerTests: XCTestCase {
func testUnfavouritedTimezone_returnEmptyMenubarTimezoneCount() { func testUnfavouritedTimezone_returnEmptyMenubarTimezoneCount() {
// Wipe all timezones from UserDefaults // Wipe all timezones from UserDefaults
UserDefaults.standard.setValue(nil, forKey: CLDefaultPreferenceKey) DataStore.shared().setTimezones(nil)
// Save a menubar selected timezone // Save a menubar selected timezone
let dataObject = TimezoneData(with: mumbai) let dataObject = TimezoneData(with: mumbai)
@ -57,7 +57,7 @@ class StandardMenubarHandlerTests: XCTestCase {
func testUnfavouritedTimezone_returnNilMenubarString() { func testUnfavouritedTimezone_returnNilMenubarString() {
// Wipe all timezones from UserDefaults // Wipe all timezones from UserDefaults
UserDefaults.standard.setValue(nil, forKey: CLDefaultPreferenceKey) DataStore.shared().setTimezones(nil)
let menubarHandler = MenubarHandler() let menubarHandler = MenubarHandler()
let emptyMenubarString = menubarHandler.titleForMenubar() let emptyMenubarString = menubarHandler.titleForMenubar()
// Returns early because DataStore.menubarTimezones is nil // Returns early because DataStore.menubarTimezones is nil

38
Clocker/CoreModelKit/Sources/CoreModelKit/TimezoneData.swift

@ -198,7 +198,6 @@ public class TimezoneData: NSObject, NSCoding {
} else if shouldOverride == 4 { } else if shouldOverride == 4 {
overrideFormat = .twelveHourWithSeconds overrideFormat = .twelveHourWithSeconds
} else if shouldOverride == 5 { } else if shouldOverride == 5 {
print("Setting override format to five")
overrideFormat = .twentyHourWithSeconds overrideFormat = .twentyHourWithSeconds
} else if shouldOverride == 7 { } else if shouldOverride == 7 {
overrideFormat = .twelveHourPrecedingZero overrideFormat = .twelveHourPrecedingZero
@ -211,7 +210,7 @@ public class TimezoneData: NSObject, NSCoding {
} else if shouldOverride == 12 { } else if shouldOverride == 12 {
overrideFormat = .epochTime overrideFormat = .epochTime
} else { } else {
assertionFailure("Chosen a wrong timezone format") Logger.info("Chosen a wrong timezone format: \(shouldOverride)")
} }
} }
@ -226,16 +225,6 @@ public class TimezoneData: NSObject, NSCoding {
return timezone return timezone
} }
if let name = formattedAddress, let placeIdentifier = placeID, let timezoneIdentifier = timezoneID {
let errorDictionary = [
"Formatted Address": name,
"Place Identifier": placeIdentifier,
"TimezoneID": timezoneIdentifier,
]
Logger.log(object: errorDictionary, for: "Error fetching timezone() in TimezoneData")
}
return TimeZone.autoupdatingCurrent.identifier return TimeZone.autoupdatingCurrent.identifier
} }
@ -273,7 +262,9 @@ public class TimezoneData: NSObject, NSCoding {
return formatInString.contains("ss") return formatInString.contains("ss")
} }
let formatInString = TimezoneData.values[NSNumber(integerLiteral: overrideFormat.rawValue)] ?? DateFormat.twelveHour // We subtract 1 because the timezone format in the dropdown contains 1 extra row for "Respecting global preferences"
let key = NSNumber(integerLiteral: overrideFormat.rawValue - 1)
let formatInString = TimezoneData.values[key] ?? DateFormat.twelveHour
return formatInString.contains("ss") return formatInString.contains("ss")
} }
@ -285,17 +276,6 @@ public class TimezoneData: NSObject, NSCoding {
return placeIdentifier.hashValue ^ timezone.hashValue return placeIdentifier.hashValue ^ timezone.hashValue
} }
static func == (lhs: TimezoneData, rhs: TimezoneData) -> Bool {
return lhs.placeID == rhs.placeID
}
public override 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 { public override func isEqual(_ object: Any?) -> Bool {
guard let compared = object as? TimezoneData else { guard let compared = object as? TimezoneData else {
return false return false
@ -317,17 +297,17 @@ public extension TimezoneData {
private func objectDescription() -> String { private func objectDescription() -> String {
let customString = """ let customString = """
TimezoneID: \(timezoneID ?? "Error") TimezoneID: \(String(describing: timezoneID))
Formatted Address: \(formattedAddress ?? "Error") Formatted Address: \(formattedAddress ?? "Error")
Custom Label: \(customLabel ?? "Error") Custom Label: \(customLabel ?? "Error")
Latitude: \(latitude ?? -0.0) Latitude: \(latitude ?? -0.0)
Longitude: \(longitude ?? -0.0) Longitude: \(longitude ?? -0.0)
Place Identifier: \(placeID ?? "Error") Place Identifier: \(String(describing: placeID))
Is Favourite: \(isFavourite) Is Favourite: \(isFavourite)
Sunrise Time: \(sunriseTime?.debugDescription ?? "N/A") Sunrise Time: \(String(describing: sunriseTime))
Sunset Time: \(sunsetTime?.debugDescription ?? "N/A") Sunset Time: \(String(describing: sunsetTime))
Selection Type: \(selectionType.rawValue) Selection Type: \(selectionType.rawValue)
Note: \(note ?? "Error") Note: \(String(describing: note))
Is System Timezone: \(isSystemTimezone) Is System Timezone: \(isSystemTimezone)
Override: \(overrideFormat) Override: \(overrideFormat)
""" """

6
Clocker/CoreModelKit/Tests/CoreModelKitTests/TimezoneDataEqualityTests.swift

@ -14,7 +14,8 @@ class TimezoneDataEqualityTests: XCTestCase {
timezone2.timezoneID = "Africa/Banjul" timezone2.timezoneID = "Africa/Banjul"
timezone2.formattedAddress = "SameLabel" timezone2.formattedAddress = "SameLabel"
XCTAssertNotEqual(timezone1, timezone2) XCTAssertFalse(timezone1 == timezone2) // Test ==
XCTAssertNotEqual(timezone1, timezone2) // Test isEqual
} }
func testEqualityWhenTimezonesLabelsDiffer() { func testEqualityWhenTimezonesLabelsDiffer() {
@ -26,6 +27,7 @@ class TimezoneDataEqualityTests: XCTestCase {
timezone2.timezoneID = TimeZone.autoupdatingCurrent.identifier timezone2.timezoneID = TimeZone.autoupdatingCurrent.identifier
timezone2.formattedAddress = "DifferentLabel" timezone2.formattedAddress = "DifferentLabel"
XCTAssertFalse(timezone1 == timezone2)
XCTAssertNotEqual(timezone1, timezone2) XCTAssertNotEqual(timezone1, timezone2)
} }
@ -40,6 +42,7 @@ class TimezoneDataEqualityTests: XCTestCase {
timezone2.timezoneID = TimeZone.autoupdatingCurrent.identifier timezone2.timezoneID = TimeZone.autoupdatingCurrent.identifier
timezone2.formattedAddress = "DifferentLabel" timezone2.formattedAddress = "DifferentLabel"
XCTAssertTrue(timezone1 == timezone2)
XCTAssertEqual(timezone1, timezone2) XCTAssertEqual(timezone1, timezone2)
} }
@ -54,6 +57,7 @@ class TimezoneDataEqualityTests: XCTestCase {
timezone2.timezoneID = TimeZone.autoupdatingCurrent.identifier timezone2.timezoneID = TimeZone.autoupdatingCurrent.identifier
timezone2.formattedAddress = "DifferentLabel" timezone2.formattedAddress = "DifferentLabel"
XCTAssertFalse(timezone1 == timezone2)
XCTAssertNotEqual(timezone1, timezone2) XCTAssertNotEqual(timezone1, timezone2)
} }
} }

8
Clocker/Overall App/AppDefaults.swift

@ -20,8 +20,9 @@ class AppDefaults {
private class func initializeDefaults() { private class func initializeDefaults() {
let userDefaults = UserDefaults.standard let userDefaults = UserDefaults.standard
let dataStore = DataStore.shared()
let timezones = userDefaults.object(forKey: CLDefaultPreferenceKey) let timezones = dataStore.timezones()
let selectedCalendars = userDefaults.object(forKey: CLSelectedCalendars) let selectedCalendars = userDefaults.object(forKey: CLSelectedCalendars)
// Now delete the old preferences // Now delete the old preferences
@ -30,7 +31,7 @@ class AppDefaults {
// Register the usual suspects // Register the usual suspects
userDefaults.register(defaults: defaultsDictionary()) userDefaults.register(defaults: defaultsDictionary())
userDefaults.set(timezones, forKey: CLDefaultPreferenceKey) dataStore.setTimezones(timezones)
userDefaults.set(selectedCalendars, forKey: CLSelectedCalendars) userDefaults.set(selectedCalendars, forKey: CLSelectedCalendars)
// Set the theme default as Light! // Set the theme default as Light!
@ -39,7 +40,7 @@ class AppDefaults {
// If we already have timezones to display in menubar, do nothing. // If we already have timezones to display in menubar, do nothing.
// Else, we switch the menubar mode default to compact mode for new users // Else, we switch the menubar mode default to compact mode for new users
if userDefaults.bool(forKey: CLDefaultMenubarMode) == false { if userDefaults.bool(forKey: CLDefaultMenubarMode) == false {
if let menubarFavourites = userDefaults.object(forKey: CLDefaultPreferenceKey) as? [Data], menubarFavourites.isEmpty == false { if let menubarFavourites = dataStore.menubarTimezones(), menubarFavourites.isEmpty == false {
userDefaults.set(1, forKey: CLMenubarCompactMode) userDefaults.set(1, forKey: CLMenubarCompactMode)
} else { } else {
userDefaults.set(0, forKey: CLMenubarCompactMode) userDefaults.set(0, forKey: CLMenubarCompactMode)
@ -137,6 +138,7 @@ extension UserDefaults {
func wipeIfNeccesary() { func wipeIfNeccesary() {
if let bundleID = Bundle.main.bundleIdentifier, object(forKey: "PreferencesHaveBeenWiped") == nil { if let bundleID = Bundle.main.bundleIdentifier, object(forKey: "PreferencesHaveBeenWiped") == nil {
Logger.info("Wiping all user defaults")
removePersistentDomain(forName: bundleID) removePersistentDomain(forName: bundleID)
set(true, forKey: "PreferencesHaveBeenWiped") set(true, forKey: "PreferencesHaveBeenWiped")
} }

23
Clocker/Overall App/DataStore.swift

@ -45,12 +45,24 @@ class DataStore: NSObject {
} }
func timezones() -> [Data] { func timezones() -> [Data] {
if let cloudPreferences = NSUbiquitousKeyValueStore().object(forKey: CLDefaultPreferenceKey) as? [Data] {
Logger.info("Returning preferences from NSUbiquitousKeyValueStore")
return cloudPreferences
}
guard let preferences = userDefaults.object(forKey: CLDefaultPreferenceKey) as? [Data] else { guard let preferences = userDefaults.object(forKey: CLDefaultPreferenceKey) as? [Data] else {
return [] return []
} }
return preferences return preferences
} }
func setTimezones(_ timezones: [Data]?) {
userDefaults.set(timezones, forKey: CLDefaultPreferenceKey)
// iCloud sync
NSUbiquitousKeyValueStore().set(timezones, forKey: CLDefaultPreferenceKey)
NSUbiquitousKeyValueStore().synchronize()
}
func menubarTimezones() -> [Data]? { func menubarTimezones() -> [Data]? {
return timezones().filter { return timezones().filter {
@ -75,10 +87,6 @@ class DataStore: NSObject {
return shouldDisplayDateInMenubar return shouldDisplayDateInMenubar
} }
func setTimezones(_ timezones: [Data]) {
userDefaults.set(timezones, forKey: CLDefaultPreferenceKey)
}
func retrieve(key: String) -> Any? { func retrieve(key: String) -> Any? {
return userDefaults.object(forKey: key) return userDefaults.object(forKey: key)
} }
@ -86,10 +94,9 @@ class DataStore: NSObject {
func addTimezone(_ timezone: TimezoneData) { func addTimezone(_ timezone: TimezoneData) {
let encodedTimezone = NSKeyedArchiver.archivedData(withRootObject: timezone) let encodedTimezone = NSKeyedArchiver.archivedData(withRootObject: timezone)
var defaults: [Data] = (userDefaults.object(forKey: CLDefaultPreferenceKey) as? [Data]) ?? [] var defaults: [Data] = timezones()
defaults.append(encodedTimezone) defaults.append(encodedTimezone)
setTimezones(defaults)
userDefaults.set(defaults, forKey: CLDefaultPreferenceKey)
} }
func removeLastTimezone() { func removeLastTimezone() {
@ -103,7 +110,7 @@ class DataStore: NSObject {
Logger.log(object: [:], for: "Undo Action Executed during Onboarding") Logger.log(object: [:], for: "Undo Action Executed during Onboarding")
userDefaults.set(currentLineup, forKey: CLDefaultPreferenceKey) setTimezones(currentLineup)
} }
func timezoneFormat() -> NSNumber { func timezoneFormat() -> NSNumber {

49
Clocker/Panel/ParentPanelController.swift

@ -153,36 +153,53 @@ class ParentPanelController: NSWindowController {
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()
// Setup table
mainTableView.backgroundColor = NSColor.clear mainTableView.backgroundColor = NSColor.clear
mainTableView.selectionHighlightStyle = .none mainTableView.selectionHighlightStyle = .none
mainTableView.enclosingScrollView?.hasVerticalScroller = false mainTableView.enclosingScrollView?.hasVerticalScroller = false
if #available(OSX 11.0, *) {
mainTableView.style = .fullWidth
}
// Setup images
let sharedThemer = Themer.shared() let sharedThemer = Themer.shared()
shutdownButton.image = sharedThemer.shutdownImage() shutdownButton.image = sharedThemer.shutdownImage()
preferencesButton.image = sharedThemer.preferenceImage() preferencesButton.image = sharedThemer.preferenceImage()
pinButton.image = sharedThemer.pinImage() pinButton.image = sharedThemer.pinImage()
sharingButton.image = sharedThemer.sharingImage() sharingButton.image = sharedThemer.sharingImage()
if let upcomingView = upcomingEventContainerView { // Setup KVO observers for user default changes
upcomingView.setAccessibility("UpcomingEventView")
}
setupObservers() setupObservers()
updateReviewViewFontColor() updateReviewViewFontColor()
// Setup layers
futureSliderView.wantsLayer = true futureSliderView.wantsLayer = true
reviewView.wantsLayer = true reviewView.wantsLayer = true
// Setup notifications
NotificationCenter.default.addObserver(self, NotificationCenter.default.addObserver(self,
selector: #selector(themeChanged), selector: #selector(themeChanged),
name: Notification.Name.themeDidChange, name: Notification.Name.themeDidChange,
object: nil) object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(systemTimezoneDidChange),
name: NSNotification.Name.NSSystemTimeZoneDidChange,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(ubiquitousStoreDidChange),
name: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
object: nil)
// Setup upcoming events view
upcomingEventContainerView.setAccessibility("UpcomingEventView")
determineUpcomingViewVisibility() determineUpcomingViewVisibility()
setupUpcomingEventViewCollectionViewIfNeccesary()
// Setup colors based on the curren theme
themeChanged() themeChanged()
// UI adjustments based on user preferences
if DataStore.shared().timezones().isEmpty || DataStore.shared().shouldDisplay(.futureSlider) == false { if DataStore.shared().timezones().isEmpty || DataStore.shared().shouldDisplay(.futureSlider) == false {
futureSliderView.isHidden = true futureSliderView.isHidden = true
if modernContainerView != nil { if modernContainerView != nil {
@ -203,22 +220,10 @@ class ParentPanelController: NSWindowController {
} }
} }
// More UI adjustments
sharingButton.sendAction(on: .leftMouseDown) sharingButton.sendAction(on: .leftMouseDown)
adjustFutureSliderBasedOnPreferences() adjustFutureSliderBasedOnPreferences()
NotificationCenter.default.addObserver(self,
selector: #selector(timezoneGonnaChange),
name: NSNotification.Name.NSSystemTimeZoneDidChange,
object: nil)
if #available(OSX 11.0, *) {
mainTableView.style = .fullWidth
}
setupModernSliderIfNeccessary() setupModernSliderIfNeccessary()
setupUpcomingEventViewCollectionViewIfNeccesary()
if roundedDateView != nil { if roundedDateView != nil {
setupRoundedDateView() setupRoundedDateView()
} }
@ -231,7 +236,7 @@ class ParentPanelController: NSWindowController {
roundedDateView.layer?.backgroundColor = Themer.shared().textBackgroundColor().cgColor roundedDateView.layer?.backgroundColor = Themer.shared().textBackgroundColor().cgColor
} }
@objc func timezoneGonnaChange() { @objc func systemTimezoneDidChange() {
OperationQueue.main.addOperation { OperationQueue.main.addOperation {
/* /*
let locationController = LocationController.sharedController() let locationController = LocationController.sharedController()
@ -241,6 +246,14 @@ class ParentPanelController: NSWindowController {
coordinates: nil) coordinates: nil)
} }
} }
// Backing defaults changed
@objc func ubiquitousStoreDidChange() {
OperationQueue.main.addOperation {
self.mainTableView.reloadData()
self.setScrollViewConstraint()
}
}
private func updateHomeObject(with customLabel: String, coordinates: CLLocationCoordinate2D?) { private func updateHomeObject(with customLabel: String, coordinates: CLLocationCoordinate2D?) {
let timezones = DataStore.shared().timezones() let timezones = DataStore.shared().timezones()

2
Clocker/Preferences/Appearance/AppearanceViewController.swift

@ -189,7 +189,7 @@ class AppearanceViewController: ParentViewController {
if let selectedFormat = sender.selectedItem?.title, if let selectedFormat = sender.selectedItem?.title,
selectedFormat.contains("ss") { selectedFormat.contains("ss") {
print("Seconds are contained") Logger.info("Selected format contains timezone format")
guard let panelController = PanelController.panel() else { return } guard let panelController = PanelController.panel() else { return }
panelController.pauseTimer() panelController.pauseTimer()
} }

8
Clocker/Preferences/Menu Bar/StatusContainerView.swift

@ -177,7 +177,13 @@ class StatusContainerView: NSView {
if newWidth != frame.size.width, newWidth > frame.size.width + 2.0 { if newWidth != frame.size.width, newWidth > frame.size.width + 2.0 {
Logger.info("Correcting our width to \(newWidth) and the previous width was \(frame.size.width)") Logger.info("Correcting our width to \(newWidth) and the previous width was \(frame.size.width)")
frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: newWidth, height: frame.size.height) // NSView move animation
NSAnimationContext.runAnimationGroup({ context in
context.duration = 0.2
let newFrame = CGRect(x: frame.origin.x, y: frame.origin.y, width: newWidth, height: frame.size.height)
// The view will animate to the new origin
self.animator().frame = newFrame
}) {}
} }
} }
} }

2
Clocker/Preferences/Menu Bar/StatusItemHandler.swift

@ -150,7 +150,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().timezones()
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) {

Loading…
Cancel
Save