Browse Source

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

pull/101/head
Abhishek 4 years ago
parent
commit
165fac0418
  1. BIN
      Clocker.app.zip
  2. 4
      Clocker/AppDelegate.swift
  3. 91
      Clocker/Clocker.xcodeproj/project.pbxproj
  4. 16
      Clocker/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  5. 159
      Clocker/Clocker/en.lproj/Panel.xib
  6. 170
      Clocker/Onboarding/OnboardingSearchController.swift
  7. 5
      Clocker/Overall App/DataStore.swift
  8. 24
      Clocker/Overall App/Foundation + Additions.swift
  9. 4
      Clocker/Overall App/Themer.swift
  10. 2
      Clocker/Panel/Data Layer/TimezoneDataOperations.swift
  11. 22
      Clocker/Panel/PanelController.swift
  12. 95
      Clocker/Panel/ParentPanelController+ModernSlider.swift
  13. 69
      Clocker/Panel/ParentPanelController.swift
  14. 11
      Clocker/Panel/Rate Controller/ReviewController.swift
  15. 36
      Clocker/Panel/UI/FloatingWindow.xib
  16. 38
      Clocker/Panel/UI/HourMarkerViewItem.swift
  17. 27
      Clocker/Panel/UI/HourMarkerViewItem.xib
  18. 37
      Clocker/Preferences/General/PreferencesViewController.swift
  19. 41
      Clocker/Preferences/General/SearchDataSource.swift
  20. 66
      Clocker/Preferences/Preferences.storyboard
  21. 16
      Readme.md

BIN
Clocker.app.zip

Binary file not shown.

4
Clocker/AppDelegate.swift

@ -58,7 +58,7 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
showOnboardingFlowIfEligible()
// Ratings Controller initialization
RateController.applicationDidLaunch(UserDefaults.standard)
ReviewController.applicationDidLaunch(UserDefaults.standard)
#if RELEASE
Fabric.with([Crashlytics.self])
@ -140,7 +140,7 @@ open class AppDelegate: NSObject, NSApplicationDelegate {
statusBarHandler = StatusItemHandler()
if ProcessInfo.processInfo.arguments.contains(CLUITestingLaunchArgument) {
RateController.setPreviewMode(true)
ReviewController.setPreviewMode(true)
}
UserDefaults.standard.register(defaults: ["NSApplicationCrashOnExceptions": true])

91
Clocker/Clocker.xcodeproj/project.pbxproj

@ -13,6 +13,7 @@
3508CCAA259A0027000E3530 /* StatusContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3508CCA9259A0027000E3530 /* StatusContainerView.swift */; };
357391872507277500D30819 /* HourMarkerViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 357391852507277500D30819 /* HourMarkerViewItem.swift */; };
357391882507277500D30819 /* HourMarkerViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = 357391862507277500D30819 /* HourMarkerViewItem.xib */; };
3579765E2680208C009DDA6E /* ParentPanelController+ModernSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3579765D2680208C009DDA6E /* ParentPanelController+ModernSlider.swift */; };
3595FAD0227F88BC0044A12A /* UserDefaults + KVOExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3595FACF227F88BC0044A12A /* UserDefaults + KVOExtensions.swift */; };
35B2FEC0259A186F005DA84D /* StartupKit in Frameworks */ = {isa = PBXBuildFile; productRef = 35B2FEBF259A186F005DA84D /* StartupKit */; };
35B2FEDD259A2291005DA84D /* CoreLoggerKit in Frameworks */ = {isa = PBXBuildFile; productRef = 35B2FEDC259A2291005DA84D /* CoreLoggerKit */; };
@ -66,7 +67,7 @@
35C36F612259DE67002FA5C6 /* NotesPopover.xib in Resources */ = {isa = PBXBuildFile; fileRef = 35C36F5F2259DE67002FA5C6 /* NotesPopover.xib */; };
35C36F622259DE67002FA5C6 /* NotesPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F602259DE67002FA5C6 /* NotesPopover.swift */; };
35C36F662259DF4C002FA5C6 /* ReviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F642259DF4C002FA5C6 /* ReviewView.swift */; };
35C36F672259DF4C002FA5C6 /* RateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F652259DF4C002FA5C6 /* RateController.swift */; };
35C36F672259DF4C002FA5C6 /* ReviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F652259DF4C002FA5C6 /* ReviewController.swift */; };
35C36F692259DF55002FA5C6 /* TextViewWithPlaceholder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F682259DF55002FA5C6 /* TextViewWithPlaceholder.swift */; };
35C36F6B2259E0E1002FA5C6 /* FloatingWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 35C36F6A2259E0E1002FA5C6 /* FloatingWindow.xib */; };
35C36F6F2259E185002FA5C6 /* CustomSliderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35C36F6C2259E185002FA5C6 /* CustomSliderCell.swift */; };
@ -90,9 +91,6 @@
9A20A04B1C4DEED200FB45AB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A20A04A1C4DEED200FB45AB /* IOKit.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 */; };
9A3231C725C605DA00D1078F /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A3231C625C605DA00D1078F /* Keys.plist */; };
9A3231C825C605DA00D1078F /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A3231C625C605DA00D1078F /* Keys.plist */; };
9A3231C925C605DA00D1078F /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A3231C625C605DA00D1078F /* Keys.plist */; };
9A4379271BEC223900F4E27F /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4379231BEC223900F4E27F /* Fabric.framework */; };
9A43792A1BEC230A00F4E27F /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4379291BEC230A00F4E27F /* libc++.tbd */; };
9A56DB801C1CFB73004CE6AF /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9A56DB7D1C1CFB73004CE6AF /* MainMenu.xib */; };
@ -233,7 +231,9 @@
3569A44E25441F320087E254 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
357391852507277500D30819 /* HourMarkerViewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HourMarkerViewItem.swift; sourceTree = "<group>"; };
357391862507277500D30819 /* HourMarkerViewItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HourMarkerViewItem.xib; sourceTree = "<group>"; };
3579765D2680208C009DDA6E /* ParentPanelController+ModernSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParentPanelController+ModernSlider.swift"; sourceTree = "<group>"; };
3595FACF227F88BC0044A12A /* UserDefaults + KVOExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults + KVOExtensions.swift"; sourceTree = "<group>"; };
35992D07267EA61E00020078 /* Keys.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Keys.plist; path = ../Internal/Keys.plist; sourceTree = "<group>"; };
35A6A4B925C5DEF300356073 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
35B2FEB1259A1649005DA84D /* StartupKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = StartupKit; sourceTree = "<group>"; };
35B2FED4259A2244005DA84D /* CoreLoggerKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = CoreLoggerKit; sourceTree = "<group>"; };
@ -287,7 +287,7 @@
35C36F5F2259DE67002FA5C6 /* NotesPopover.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NotesPopover.xib; sourceTree = "<group>"; };
35C36F602259DE67002FA5C6 /* NotesPopover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotesPopover.swift; sourceTree = "<group>"; };
35C36F642259DF4C002FA5C6 /* ReviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReviewView.swift; sourceTree = "<group>"; };
35C36F652259DF4C002FA5C6 /* RateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RateController.swift; sourceTree = "<group>"; };
35C36F652259DF4C002FA5C6 /* ReviewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReviewController.swift; sourceTree = "<group>"; };
35C36F682259DF55002FA5C6 /* TextViewWithPlaceholder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextViewWithPlaceholder.swift; sourceTree = "<group>"; };
35C36F6A2259E0E1002FA5C6 /* FloatingWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FloatingWindow.xib; sourceTree = "<group>"; };
35C36F6C2259E185002FA5C6 /* CustomSliderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomSliderCell.swift; sourceTree = "<group>"; };
@ -311,7 +311,6 @@
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; };
9A3169C01D2CC5AA0079FDF8 /* com.abhishek.ClockerHelper.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.abhishek.ClockerHelper.plist; path = Clocker/com.abhishek.ClockerHelper.plist; sourceTree = "<group>"; };
9A3231C625C605DA00D1078F /* Keys.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Keys.plist; path = Internal/Keys.plist; sourceTree = "<group>"; };
9A4379231BEC223900F4E27F /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
9A4379291BEC230A00F4E27F /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
9A43792B1BEC231100F4E27F /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
@ -539,6 +538,7 @@
35C36F282259D6FA002FA5C6 /* PanelController.swift */,
35C36F272259D6FA002FA5C6 /* ParentPanelController.swift */,
35C36F722259E1AA002FA5C6 /* FloatingWindowController.swift */,
3579765D2680208C009DDA6E /* ParentPanelController+ModernSlider.swift */,
);
path = Panel;
sourceTree = "<group>";
@ -612,7 +612,7 @@
35C36F632259DE9D002FA5C6 /* Rate Controller */ = {
isa = PBXGroup;
children = (
35C36F652259DF4C002FA5C6 /* RateController.swift */,
35C36F652259DF4C002FA5C6 /* ReviewController.swift */,
35C36F642259DF4C002FA5C6 /* ReviewView.swift */,
);
path = "Rate Controller";
@ -822,7 +822,7 @@
DD4F7BF913C30F9F00825C6E = {
isa = PBXGroup;
children = (
9A3231C625C605DA00D1078F /* Keys.plist */,
35992D07267EA61E00020078 /* Keys.plist */,
35B2FEE4259A2C25005DA84D /* CoreModelKit */,
35B2FED4259A2244005DA84D /* CoreLoggerKit */,
35B2FEB1259A1649005DA84D /* StartupKit */,
@ -1100,7 +1100,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9A3231C925C605DA00D1078F /* Keys.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1108,7 +1107,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9A3231C825C605DA00D1078F /* Keys.plist in Resources */,
9A8B256A232EFAD300204CAD /* Localizable.strings in Resources */,
9AA522C023415BDD00C9E005 /* InfoPlist.strings in Resources */,
);
@ -1118,7 +1116,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9A3231C725C605DA00D1078F /* Keys.plist in Resources */,
9A13BAEA1CA88A76007C6CBE /* Localizable.strings in Resources */,
357391882507277500D30819 /* HourMarkerViewItem.xib in Resources */,
9AB6F15E2259D08300A44663 /* iVersion.bundle in Resources */,
@ -1213,7 +1210,7 @@
35C36EF622595F14002FA5C6 /* OnboardingController.swift in Sources */,
9AB6F1622259D1B000A44663 /* PreferencesDataSource.swift in Sources */,
3508CC9A259A0001000E3530 /* StatusItemView.swift in Sources */,
35C36F672259DF4C002FA5C6 /* RateController.swift in Sources */,
35C36F672259DF4C002FA5C6 /* ReviewController.swift in Sources */,
35C36F472259D892002FA5C6 /* Reach.swift in Sources */,
35C36EF222595F14002FA5C6 /* OnboardingWelcomeViewController.swift in Sources */,
35C36F732259E1AA002FA5C6 /* FloatingWindowController.swift in Sources */,
@ -1285,6 +1282,7 @@
35C36F15225961DA002FA5C6 /* TimeChunk.swift in Sources */,
35C36F482259D892002FA5C6 /* NetworkManager.swift in Sources */,
9A8605AE1BEC148400A810A4 /* main.m in Sources */,
3579765E2680208C009DDA6E /* ParentPanelController+ModernSlider.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1453,14 +1451,23 @@
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = "Accent Color";
CLANG_ANALYZER_GCD_PERFORMANCE = YES;
CLANG_ANALYZER_LOCALIZABILITY_EMPTY_CONTEXT = YES;
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = NO;
CLANG_WARN_OBJC_INTERFACE_IVARS = NO;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO;
CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_INTERFACE_IVARS = YES;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CODE_SIGN_ENTITLEMENTS = Clocker/Clocker.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
@ -1483,7 +1490,10 @@
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
@ -1496,12 +1506,13 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
MARKETING_VERSION = 21.02.03;
MARKETING_VERSION = 21.07.01;
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.abhishek.Clocker;
PRODUCT_NAME = Clocker;
PROVISIONING_PROFILE = "71701bee-fee7-4927-b6e9-20d9a78ef29c";
PROVISIONING_PROFILE_SPECIFIER = "";
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = macosx;
SWIFT_OBJC_BRIDGING_HEADER = "Clocker-Bridging-Header.h";
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
@ -1988,14 +1999,23 @@
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = "Accent Color";
CLANG_ANALYZER_GCD_PERFORMANCE = YES;
CLANG_ANALYZER_LOCALIZABILITY_EMPTY_CONTEXT = YES;
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = NO;
CLANG_WARN_OBJC_INTERFACE_IVARS = NO;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO;
CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_INTERFACE_IVARS = YES;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CODE_SIGN_ENTITLEMENTS = Clocker/Clocker.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
@ -2019,7 +2039,10 @@
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
@ -2032,7 +2055,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
MARKETING_VERSION = 21.02.03;
MARKETING_VERSION = 21.07.01;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = "";
"OTHER_SWIFT_FLAGS[arch=*]" = "-D DEBUG";
@ -2040,6 +2063,7 @@
PRODUCT_NAME = Clocker;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = macosx;
SWIFT_OBJC_BRIDGING_HEADER = "Clocker-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -2057,14 +2081,23 @@
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = "Accent Color";
CLANG_ANALYZER_GCD_PERFORMANCE = YES;
CLANG_ANALYZER_LOCALIZABILITY_EMPTY_CONTEXT = YES;
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = NO;
CLANG_WARN_OBJC_INTERFACE_IVARS = NO;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO;
CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_INTERFACE_IVARS = YES;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CODE_SIGN_ENTITLEMENTS = Clocker/Clocker.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
@ -2087,7 +2120,10 @@
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
@ -2100,13 +2136,14 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
MARKETING_VERSION = 21.02.03;
MARKETING_VERSION = 21.07.01;
OTHER_LDFLAGS = "";
"OTHER_SWIFT_FLAGS[arch=*]" = "-D RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = com.abhishek.Clocker;
PRODUCT_NAME = Clocker;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = macosx;
SWIFT_OBJC_BRIDGING_HEADER = "Clocker-Bridging-Header.h";
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;

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

@ -15,5 +15,21 @@
stopOnStyle = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "6C78F195-3037-4EDA-8650-D12235EAA1E9"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Preferences/General/PreferencesViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "47"
endingLineNumber = "47"
landmarkName = "geocodingKey"
landmarkType = "24">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

159
Clocker/Clocker/en.lproj/Panel.xib

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17506" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17506"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -16,7 +17,9 @@
<outlet property="leftButton" destination="WVY-D9-AAX" id="M2W-xG-chN"/>
<outlet property="leftField" destination="8Qj-Y9-Okf" id="q3N-ht-jCd"/>
<outlet property="mainTableView" destination="dFw-ts-8OZ" id="2kY-dd-rDV"/>
<outlet property="modernContainerView" destination="8W7-rS-Uob" id="qgZ-SS-ayy"/>
<outlet property="modernSlider" destination="lxA-64-3QU" id="kS5-ub-7gV"/>
<outlet property="modernSliderLabel" destination="pi8-wk-eXa" id="yLU-nz-IBx"/>
<outlet property="nextEventLabel" destination="rld-Ag-KL1" id="GTY-j3-A1g"/>
<outlet property="pinButton" destination="YXE-4J-5cn" id="k6V-HK-7XG"/>
<outlet property="preferencesButton" destination="Ctq-BV-GPN" id="cdL-5h-qmx"/>
@ -40,22 +43,22 @@
<windowCollectionBehavior key="collectionBehavior" moveToActiveSpace="YES" ignoresCycle="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="1000" y="379" width="350" height="460"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
<view key="contentView" focusRingType="none" id="6" customClass="BackgroundPanelView" customModule="Clocker" customModuleProvider="target">
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
<view key="contentView" focusRingType="none" misplaced="YES" id="6" customClass="BackgroundPanelView" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="350" height="460"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView focusRingType="none" distribution="fill" orientation="vertical" alignment="leading" spacing="0.0" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OZA-6o-SbE">
<rect key="frame" x="0.0" y="0.0" width="350" height="460"/>
<rect key="frame" x="0.0" y="0.0" width="350" height="315"/>
<subviews>
<scrollView focusRingType="none" borderType="none" autohidesScrollers="YES" horizontalLineScroll="96" horizontalPageScroll="1" verticalLineScroll="96" verticalPageScroll="1" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" scrollerKnobStyle="light" translatesAutoresizingMaskIntoConstraints="NO" id="4Gd-Nv-fXr">
<rect key="frame" x="-29" y="195" width="379" height="265"/>
<rect key="frame" x="-20" y="50" width="370" height="265"/>
<clipView key="contentView" focusRingType="none" drawsBackground="NO" copiesOnScroll="NO" id="4MZ-Di-yNR">
<rect key="frame" x="0.0" y="0.0" width="379" height="265"/>
<rect key="frame" x="0.0" y="0.0" width="370" height="265"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowHeight="95" viewBased="YES" id="dFw-ts-8OZ" customClass="PanelTableView" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="379" height="265"/>
<rect key="frame" x="0.0" y="0.0" width="370" height="265"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="1"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -74,22 +77,22 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="timeZoneCell" id="qbN-ba-fho" customClass="TimezoneCellView" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="1" y="0.0" width="338" height="111"/>
<rect key="frame" x="11" y="0.0" width="347" height="111"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" verticalCompressionResistancePriority="749" tag="102" preferredMaxLayoutWidth="72" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QUd-7D-q14">
<rect key="frame" x="28" y="50" width="180" height="22"/>
<rect key="frame" x="28" y="50" width="189" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" identifier="relative-day-height" id="JkG-8f-zhJ"/>
</constraints>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" state="on" usesSingleLineMode="YES" id="74U-rv-5xj">
<font key="font" size="13" name="Avenir-Heavy"/>
<font key="font" size="13" name="Avenir-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" tag="101" preferredMaxLayoutWidth="110" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vnv-J2-7r1">
<rect key="frame" x="206" y="67" width="114" height="35"/>
<rect key="frame" x="215" y="67" width="114" height="35"/>
<constraints>
<constraint firstAttribute="height" constant="35" identifier="height" id="Bwf-I6-2Pc"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="110" id="cQV-gJ-zMz"/>
@ -101,7 +104,7 @@
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" preferredMaxLayoutWidth="50" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uOg-ij-alO">
<rect key="frame" x="236" y="49" width="84" height="20"/>
<rect key="frame" x="245" y="49" width="84" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="89H-r0-Dnh"/>
<constraint firstAttribute="width" constant="80" identifier="width" id="8KH-Ks-d4T"/>
@ -113,7 +116,7 @@
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6At-J8-gzZ">
<rect key="frame" x="28" y="0.0" width="310" height="22"/>
<rect key="frame" x="28" y="0.0" width="319" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" id="eYP-TP-f1a"/>
</constraints>
@ -124,7 +127,7 @@
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="sML-fJ-nbv">
<rect key="frame" x="216" y="49" width="20" height="20"/>
<rect key="frame" x="225" y="49" width="20" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="2NE-mf-cN5"/>
<constraint firstAttribute="width" constant="20" id="EXa-Tf-sR6"/>
@ -132,9 +135,9 @@
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageAlignment="right" imageScaling="proportionallyDown" id="cfP-C4-ENJ"/>
</imageView>
<textField verticalHuggingPriority="751" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="751" tag="100" preferredMaxLayoutWidth="150" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="etF-33-bCB">
<rect key="frame" x="28" y="79" width="172" height="20"/>
<rect key="frame" x="28" y="79" width="181" height="20"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" placeholderString="Timezone Name" id="rnh-AP-ooc">
<font key="font" size="15" name="Avenir-Light"/>
<font key="font" size="15" name="Avenir-Medium"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
@ -210,11 +213,11 @@
</connections>
</tableCellView>
<tableCellView identifier="addCell" id="rb3-TW-xSb" customClass="AddTableViewCell" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="1" y="112" width="338" height="100"/>
<rect key="frame" x="11" y="112" width="347" height="100"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="AzA-5G-LR7">
<rect key="frame" x="129" y="10" width="80" height="80"/>
<rect key="frame" x="134" y="10" width="80" height="80"/>
<constraints>
<constraint firstAttribute="height" constant="80" id="bRv-Of-5l3"/>
<constraint firstAttribute="width" constant="80" id="cRC-Fx-WLR"/>
@ -259,7 +262,7 @@
</scroller>
</scrollView>
<customView identifier="Review Cell" focusRingType="none" translatesAutoresizingMaskIntoConstraints="NO" id="TDn-Kk-KkV">
<rect key="frame" x="0.0" y="145" width="350" height="50"/>
<rect key="frame" x="0.0" y="0.0" width="350" height="50"/>
<subviews>
<stackView focusRingType="none" distribution="fill" orientation="horizontal" alignment="centerY" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uys-ww-duA">
<rect key="frame" x="25" y="25" width="300" height="20"/>
@ -289,7 +292,7 @@
<rect key="frame" x="75" y="2" width="200" height="21"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="WVY-D9-AAX">
<rect key="frame" x="-6" y="-7" width="108" height="32"/>
<rect key="frame" x="-7" y="-7" width="110" height="33"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="4zI-xY-iLf"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="96" id="weK-At-NNy"/>
@ -303,7 +306,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="w3d-CG-aBO">
<rect key="frame" x="98" y="-7" width="108" height="32"/>
<rect key="frame" x="97" y="-6" width="110" height="32"/>
<buttonCell key="cell" type="push" title="Yes!" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="VE1-Cu-JUr">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" size="13" name="Avenir-Light"/>
@ -332,8 +335,8 @@
</constraints>
<accessibility description="ReviewCell" identifier="ReviewCell"/>
</customView>
<customView wantsLayer="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Akn-cR-W4G" customClass="ReviewView" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="0.0" y="70" width="350" height="75"/>
<customView wantsLayer="YES" focusRingType="none" translatesAutoresizingMaskIntoConstraints="NO" id="Akn-cR-W4G" customClass="ReviewView" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="0.0" y="-75" width="350" height="75"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Etf-aa-udM" customClass="ClockerTextBackgroundView" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="10" y="10" width="330" height="55"/>
@ -410,10 +413,10 @@
<accessibility identifier="UpcomingEventView"/>
</customView>
<customView wantsLayer="YES" focusRingType="none" translatesAutoresizingMaskIntoConstraints="NO" id="C7R-Dq-MFr" userLabel="Slider View">
<rect key="frame" x="0.0" y="40" width="350" height="30"/>
<rect key="frame" x="0.0" y="110" width="350" height="30"/>
<subviews>
<slider verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Vf2-uI-yf3">
<rect key="frame" x="7" y="6" width="201" height="19"/>
<rect key="frame" x="7" y="2" width="201" height="23"/>
<constraints>
<constraint firstAttribute="height" constant="15" id="cS7-i2-mHU"/>
</constraints>
@ -458,6 +461,63 @@
<constraint firstAttribute="trailing" secondItem="I2Z-NZ-795" secondAttribute="trailing" constant="5" id="ju8-FH-nE8"/>
</constraints>
</customView>
<customView wantsLayer="YES" focusRingType="none" id="8W7-rS-Uob" userLabel="Modern Slider">
<rect key="frame" x="0.0" y="40" width="350" height="70"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<scrollView wantsLayer="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="htc-pO-AqH">
<rect key="frame" x="5" y="30" width="340" height="40"/>
<clipView key="contentView" id="N1e-zE-F86">
<rect key="frame" x="0.0" y="0.0" width="340" height="40"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView id="lxA-64-3QU">
<rect key="frame" x="0.0" y="0.0" width="340" height="40"/>
<autoresizingMask key="autoresizingMask" heightSizable="YES"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" id="mgM-vQ-fB7">
<size key="itemSize" width="50" height="50"/>
</collectionViewFlowLayout>
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<connections>
<outlet property="dataSource" destination="-2" id="Exd-5i-4cB"/>
<outlet property="delegate" destination="-2" id="r49-5r-Rx5"/>
</connections>
</collectionView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="8II-oP-xbd">
<rect key="frame" x="0.0" y="34" width="340" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="f9b-8n-Bt1">
<rect key="frame" x="-100" y="-100" width="16" height="50"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pi8-wk-eXa">
<rect key="frame" x="123" y="3" width="104" height="22"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="100" id="eLd-zO-yiI"/>
</constraints>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Label Goes Here" id="ii9-w0-WDX">
<font key="font" size="10" name="Avenir-LightOblique"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="Accent Color"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="70" id="5HT-Ps-YH3"/>
<constraint firstAttribute="bottom" secondItem="pi8-wk-eXa" secondAttribute="bottom" constant="3" id="6E6-8S-PZv"/>
<constraint firstItem="htc-pO-AqH" firstAttribute="top" secondItem="8W7-rS-Uob" secondAttribute="top" id="Ag8-2G-tVA"/>
<constraint firstItem="htc-pO-AqH" firstAttribute="leading" secondItem="8W7-rS-Uob" secondAttribute="leading" constant="5" id="QmJ-Dd-WLb"/>
<constraint firstItem="pi8-wk-eXa" firstAttribute="top" secondItem="htc-pO-AqH" secondAttribute="bottom" constant="5" id="UIT-XA-SEL"/>
<constraint firstAttribute="bottom" secondItem="htc-pO-AqH" secondAttribute="bottom" constant="30" id="YCJ-zB-dvc"/>
<constraint firstAttribute="trailing" secondItem="htc-pO-AqH" secondAttribute="trailing" constant="5" id="esR-My-uoD"/>
<constraint firstItem="pi8-wk-eXa" firstAttribute="centerX" secondItem="8W7-rS-Uob" secondAttribute="centerX" id="f3f-ax-wFo"/>
</constraints>
<accessibility identifier="Modern Slider"/>
</customView>
<customView wantsLayer="YES" focusRingType="none" translatesAutoresizingMaskIntoConstraints="NO" id="B8X-sx-cjT">
<rect key="frame" x="0.0" y="0.0" width="350" height="40"/>
<subviews>
@ -536,48 +596,6 @@
<constraint firstItem="Ctq-BV-GPN" firstAttribute="leading" secondItem="B8X-sx-cjT" secondAttribute="leading" constant="8" id="ydm-oF-sVc"/>
</constraints>
</customView>
<customView hidden="YES" wantsLayer="YES" focusRingType="none" id="8W7-rS-Uob" userLabel="Slider View">
<rect key="frame" x="0.0" y="205" width="365" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<scrollView wantsLayer="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="htc-pO-AqH">
<rect key="frame" x="0.0" y="0.0" width="365" height="50"/>
<clipView key="contentView" id="N1e-zE-F86">
<rect key="frame" x="0.0" y="0.0" width="365" height="50"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView id="lxA-64-3QU">
<rect key="frame" x="0.0" y="0.0" width="365" height="158"/>
<autoresizingMask key="autoresizingMask" heightSizable="YES"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" id="mgM-vQ-fB7">
<size key="itemSize" width="50" height="50"/>
</collectionViewFlowLayout>
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<connections>
<outlet property="dataSource" destination="-2" id="Exd-5i-4cB"/>
<outlet property="delegate" destination="-2" id="r49-5r-Rx5"/>
</connections>
</collectionView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="8II-oP-xbd">
<rect key="frame" x="1" y="33" width="363" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="f9b-8n-Bt1">
<rect key="frame" x="349" y="0.0" width="16" height="50"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
<constraints>
<constraint firstItem="htc-pO-AqH" firstAttribute="leading" secondItem="8W7-rS-Uob" secondAttribute="leading" id="0QY-hT-XLg"/>
<constraint firstAttribute="height" constant="50" id="5HT-Ps-YH3"/>
<constraint firstItem="htc-pO-AqH" firstAttribute="top" secondItem="8W7-rS-Uob" secondAttribute="top" id="Ag8-2G-tVA"/>
<constraint firstAttribute="bottom" secondItem="htc-pO-AqH" secondAttribute="bottom" id="YCJ-zB-dvc"/>
<constraint firstAttribute="trailing" secondItem="htc-pO-AqH" secondAttribute="trailing" id="d7f-wV-lqc"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="B8X-sx-cjT" firstAttribute="leading" secondItem="OZA-6o-SbE" secondAttribute="leading" id="AUz-54-0mE"/>
@ -617,7 +635,7 @@
<connections>
<outlet property="delegate" destination="-2" id="8"/>
</connections>
<point key="canvasLocation" x="172" y="466"/>
<point key="canvasLocation" x="172" y="465.5"/>
</window>
<userDefaultsController representsSharedInstance="YES" id="O3B-kK-4vm"/>
</objects>
@ -630,5 +648,8 @@
<image name="PowerIcon" width="350" height="350"/>
<image name="Remove" width="700" height="700"/>
<image name="SharingDarkIcon" width="19" height="22"/>
<namedColor name="Accent Color">
<color red="0.092000000178813934" green="0.0" blue="0.99900001287460327" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>

170
Clocker/Onboarding/OnboardingSearchController.swift

@ -21,8 +21,7 @@ class OnboardingSearchController: NSViewController {
@IBOutlet private var accessoryLabel: NSTextField!
@IBOutlet var undoButton: NSButton!
private var results: [TimezoneData] = []
private var searchDataSource: SearchDataSource!
private var searchResultsDataSource: SearchDataSource!
private var dataTask: URLSessionDataTask? = .none
private var themeDidChangeNotification: NSObjectProtocol?
@ -40,8 +39,9 @@ class OnboardingSearchController: NSViewController {
super.viewDidLoad()
view.wantsLayer = true
searchResultsDataSource = SearchDataSource(with: searchBar, location: .onboarding)
searchDataSource = SearchDataSource(with: searchBar)
resultsTableView.isHidden = true
resultsTableView.delegate = self
resultsTableView.setAccessibility("ResultsTableView")
resultsTableView.dataSource = self
@ -79,23 +79,68 @@ class OnboardingSearchController: NSViewController {
@objc func doubleClickAction(_: NSTableView?) {
[accessoryLabel].forEach { $0?.isHidden = false }
if resultsTableView.selectedRow >= 0, resultsTableView.selectedRow < results.count {
let selectedTimezone = results[resultsTableView.selectedRow]
if resultsTableView.selectedRow >= 0, resultsTableView.selectedRow < searchResultsDataSource.resultsCount() {
let selectedType = searchResultsDataSource.placeForRow(resultsTableView.selectedRow)
switch selectedType {
case .city:
let filteredGoogleResult = searchResultsDataSource.retrieveFilteredResultFromGoogleAPI(resultsTableView.selectedRow)
addTimezoneToDefaults(filteredGoogleResult!)
return
case .timezone:
cleanupAfterInstallingTimezone()
return
}
}
}
private func cleanupAfterInstallingTimezone() {
let data = TimezoneData()
data.setLabel(CLEmptyString)
let currentSelection = searchResultsDataSource.retrieveSelectedTimezone(resultsTableView.selectedRow)
let metaInfo = metadata(for: currentSelection)
data.timezoneID = metaInfo.0.name
data.formattedAddress = metaInfo.1.formattedName
data.selectionType = .timezone
data.isSystemTimezone = metaInfo.0.name == NSTimeZone.system.identifier
let operationObject = TimezoneDataOperations(with: data)
operationObject.saveObject()
searchResultsDataSource.cleanupFilterArray()
searchResultsDataSource.timezoneFilteredArray = []
searchResultsDataSource.calculateChangesets()
searchBar.stringValue = CLEmptyString
accessoryLabel.stringValue = "Added \(metaInfo.1.formattedName)."
undoButton.isHidden = false
setupLabelHidingTimer()
addTimezoneToDefaults(selectedTimezone)
resultsTableView.reloadData()
resultsTableView.isHidden = true
}
private func metadata(for selection: TimezoneMetadata) -> (NSTimeZone, TimezoneMetadata) {
if selection.formattedName == "Anywhere on Earth" {
return (NSTimeZone(name: "GMT-1200")!, selection)
} else if selection.formattedName == "UTC" {
return (NSTimeZone(name: "GMT")!, selection)
} else {
return (selection.timezone, selection)
}
}
private func addTimezoneToDefaults(_ timezone: TimezoneData) {
func setupLabelHidingTimer() {
Timer.scheduledTimer(withTimeInterval: 5,
repeats: false) { _ in
OperationQueue.main.addOperation {
self.accessoryLabel.stringValue = CLEmptyString
}
private func setupLabelHidingTimer() {
Timer.scheduledTimer(withTimeInterval: 5,
repeats: false) { _ in
OperationQueue.main.addOperation {
self.setInfoLabel(CLEmptyString)
}
}
}
private func addTimezoneToDefaults(_ timezone: TimezoneData) {
if resultsTableView.selectedRow == -1 {
setInfoLabel(PreferencesConstants.noTimezoneSelectedErrorMessage)
setupLabelHidingTimer()
@ -142,22 +187,10 @@ class OnboardingSearchController: NSViewController {
return false
}
// Extracting this out for tests
private func decodeTimezone(from data: Data) -> Timezone? {
let jsonDecoder = JSONDecoder()
do {
let decodedObject = try jsonDecoder.decode(Timezone.self, from: data)
return decodedObject
} catch {
Logger.info("decodedObject error: \n\(error)")
return nil
}
}
private func fetchTimezone(for latitude: Double, and longitude: Double, _ dataObject: TimezoneData) {
if NetworkManager.isConnected() == false || ProcessInfo.processInfo.arguments.contains("mockTimezoneDown") {
setInfoLabel(PreferencesConstants.noInternetConnectivityError)
results = []
searchResultsDataSource.cleanupFilterArray()
resultsTableView.reloadData()
return
}
@ -177,8 +210,8 @@ class OnboardingSearchController: NSViewController {
return
}
if error == nil, let json = response, let response = self.decodeTimezone(from: json) {
if self.resultsTableView.selectedRow >= 0, self.resultsTableView.selectedRow < self.results.count {
if error == nil, let json = response, let response = json.decodeTimezone() {
if self.resultsTableView.selectedRow >= 0, self.resultsTableView.selectedRow < self.searchResultsDataSource.resultsCount() {
var filteredAddress = "Error"
if let address = dataObject.formattedAddress {
@ -261,11 +294,6 @@ class OnboardingSearchController: NSViewController {
accessoryLabel.isHidden = false
if NetworkManager.isConnected() == false {
setInfoLabel(PreferencesConstants.noInternetConnectivityError)
return
}
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(OnboardingSearchController.actualSearch), with: nil, afterDelay: 0.2)
}
@ -279,6 +307,7 @@ class OnboardingSearchController: NSViewController {
@objc func actualSearch() {
func setupForError() {
searchResultsDataSource.calculateChangesets()
resultsTableView.isHidden = true
}
@ -311,11 +340,18 @@ class OnboardingSearchController: NSViewController {
return
}
self.results = []
self.searchResultsDataSource.cleanupFilterArray()
self.searchResultsDataSource.timezoneFilteredArray = []
if let errorPresent = error {
self.presentErrorMessage(errorPresent.localizedDescription)
setupForError()
self.findLocalSearchResultsForTimezones()
if self.searchResultsDataSource.timezoneFilteredArray.count == 0 {
self.presentErrorMessage(errorPresent.localizedDescription)
setupForError()
return
}
self.prepareUIForPresentingResults()
return
}
@ -325,7 +361,7 @@ class OnboardingSearchController: NSViewController {
return
}
let searchResults = self.decode(from: data)
let searchResults = data.decode()
if searchResults?.status == "ZERO_RESULTS" {
self.setInfoLabel("No results! 😔 Try entering the exact name.")
@ -334,10 +370,8 @@ class OnboardingSearchController: NSViewController {
}
self.appendResultsToFilteredArray(searchResults!.results)
self.setInfoLabel(CLEmptyString)
self.resultsTableView.reloadData()
self.findLocalSearchResultsForTimezones()
self.prepareUIForPresentingResults()
}
})
}
@ -350,12 +384,25 @@ class OnboardingSearchController: NSViewController {
}
}
private func findLocalSearchResultsForTimezones() {
let lowercasedSearchString = searchBar.stringValue.lowercased()
searchResultsDataSource.searchTimezones(lowercasedSearchString)
}
private func prepareUIForPresentingResults() {
setInfoLabel(CLEmptyString)
if searchResultsDataSource.calculateChangesets() {
resultsTableView.isHidden = false
resultsTableView.reloadData()
}
}
private func appendResultsToFilteredArray(_ results: [SearchResult.Result]) {
results.forEach {
let location = $0.geometry.location
let finalTimezones: [TimezoneData] = results.map { (result) -> TimezoneData in
let location = result.geometry.location
let latitude = location.lat
let longitude = location.lng
let formattedAddress = $0.formattedAddress
let formattedAddress = result.formattedAddress
let totalPackage = [
"latitude": latitude,
@ -363,27 +410,17 @@ class OnboardingSearchController: NSViewController {
CLTimezoneName: formattedAddress,
CLCustomLabel: formattedAddress,
CLTimezoneID: CLEmptyString,
CLPlaceIdentifier: $0.placeId,
CLPlaceIdentifier: result.placeId,
] as [String: Any]
self.results.append(TimezoneData(with: totalPackage))
return TimezoneData(with: totalPackage)
}
}
// Extracting this out for tests
private func decode(from data: Data) -> SearchResult? {
let jsonDecoder = JSONDecoder()
do {
let decodedObject = try jsonDecoder.decode(SearchResult.self, from: data)
return decodedObject
} catch {
Logger.info("decodedObject error: \n\(error)")
return nil
}
searchResultsDataSource.setFilteredArrayValue(finalTimezones)
}
private func resetSearchView() {
results = []
searchResultsDataSource.cleanupFilterArray()
resultsTableView.reloadData()
searchBar.stringValue = CLEmptyString
searchBar.placeholderString = "Press Enter to Search"
@ -397,13 +434,18 @@ class OnboardingSearchController: NSViewController {
extension OnboardingSearchController: NSTableViewDataSource {
func numberOfRows(in _: NSTableView) -> Int {
return results.count
return searchResultsDataSource.resultsCount()
}
func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? {
if let result = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "resultCellView"), owner: self) as? ResultTableViewCell, row >= 0, row < results.count {
let currentTimezone = results[row]
result.result.stringValue = " \(currentTimezone.formattedAddress ?? "Place Name")"
if let result = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "resultCellView"), owner: self) as? ResultTableViewCell, row >= 0, row < searchResultsDataSource.resultsCount() {
let currentSelection = searchResultsDataSource.retrieveResult(row)
if let timezone = currentSelection as? TimezoneMetadata {
result.result.stringValue = " \(timezone.formattedName)"
} else if let location = currentSelection as? TimezoneData {
result.result.stringValue = " \(location.formattedAddress ?? "Place Name")"
}
result.result.textColor = Themer.shared().mainTextColor()
return result
}
@ -414,7 +456,7 @@ extension OnboardingSearchController: NSTableViewDataSource {
extension OnboardingSearchController: NSTableViewDelegate {
func tableView(_: NSTableView, heightOfRow row: Int) -> CGFloat {
if row == 0, results.isEmpty {
if row == 0, searchResultsDataSource.resultsCount() == 0 {
return 30
}
@ -422,7 +464,7 @@ extension OnboardingSearchController: NSTableViewDelegate {
}
func tableView(_: NSTableView, shouldSelectRow row: Int) -> Bool {
return results.isEmpty ? row != 0 : true
return searchResultsDataSource.resultsCount() == 0 ? row != 0 : true
}
func tableView(_: NSTableView, rowViewForRow _: Int) -> NSTableRowView? {

5
Clocker/Overall App/DataStore.swift

@ -125,7 +125,10 @@ class DataStore: NSObject {
func shouldDisplay(_ type: ViewType) -> Bool {
switch type {
case .futureSlider:
return shouldDisplayHelper(CLDisplayFutureSliderKey)
guard let value = retrieve(key: CLDisplayFutureSliderKey) as? NSNumber else {
return false
}
return value != 2 // Modern is 0, Legacy is 1 and Hide is 2.
case .upcomingEventView:
guard let value = retrieve(key: CLShowUpcomingEventView) as? NSString else {
return false

24
Clocker/Overall App/Foundation + Additions.swift

@ -1,6 +1,7 @@
// Copyright © 2015 Abhishek Banthia
import Cocoa
import CoreModelKit
extension NSNotification.Name {
static let themeDidChange = NSNotification.Name("ThemeDidChangeNotification")
@ -32,3 +33,26 @@ extension NSImage.Name {
static let sortToggleAlternateIcon = NSImage.Name("Additional Preferences Highlighted Dynamic")
static let menubarIcon = NSImage.Name("LightModeIcon")
}
extension Data {
// Extracting this out for tests
public func decode() -> SearchResult? {
let jsonDecoder = JSONDecoder()
do {
let decodedObject = try jsonDecoder.decode(SearchResult.self, from: self)
return decodedObject
} catch {
return nil
}
}
public func decodeTimezone() -> Timezone? {
let jsonDecoder = JSONDecoder()
do {
let decodedObject = try jsonDecoder.decode(Timezone.self, from: self)
return decodedObject
} catch {
return nil
}
}
}

4
Clocker/Overall App/Themer.swift

@ -187,8 +187,8 @@ extension Themer {
return
themeIndex == .light
? NSImage(named: NSImage.Name("Settings"))!
: NSImage(named: NSImage.Name("Settings-White"))!
? NSImage(named: NSImage.Name("Settings"))!
: NSImage(named: NSImage.Name("Settings-White"))!
}
func pinImage() -> NSImage {

2
Clocker/Panel/Data Layer/TimezoneDataOperations.swift

@ -404,7 +404,7 @@ extension TimezoneDataOperations {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US")
dateFormatter.timeZone = TimeZone(identifier: dataObject.timezone())
dateFormatter.dateFormat = DataStore.shared().shouldDisplay(ViewType.twelveHour) ? "hh:mm a" : "HH:mm"
dateFormatter.dateFormat = dataObject.timezoneFormat(DataStore.shared().timezoneFormat())
return dateFormatter.string(from: correct)
}

22
Clocker/Panel/PanelController.swift

@ -79,19 +79,29 @@ class PanelController: ParentPanelController {
updateDefaultPreferences()
if DataStore.shared().timezones().isEmpty {
if DataStore.shared().timezones().isEmpty || DataStore.shared().shouldDisplay(.futureSlider) == false {
futureSliderView.isHidden = true
} else if futureSliderView.isHidden == DataStore.shared().shouldDisplay(.futureSlider) {
futureSliderView.isHidden = false
modernContainerView.isHidden = true
} else if let value = DataStore.shared().retrieve(key: CLDisplayFutureSliderKey) as? NSNumber {
if value.intValue == 1 {
futureSliderView.isHidden = false
modernContainerView.isHidden = true
} else if value.intValue == 0 {
futureSliderView.isHidden = true
modernContainerView.isHidden = false
}
}
// Reset future slider value to zero
futureSlider.integerValue = 0
sliderDatePicker.dateValue = Date()
modernSliderLabel.stringValue = modernSliderDataSource[modernSliderDataSource.count / 2]
let indexPaths: Set<IndexPath> = Set([IndexPath(item: modernSliderDataSource.count / 2, section: 0)])
modernSlider.scrollToItems(at: indexPaths, scrollPosition: .centeredHorizontally)
setTimezoneDatasourceSlider(sliderValue: 0)
reviewView.isHidden = !RateController.canPrompt()
reviewView.isHidden = !ReviewController.canPrompt()
reviewView.layer?.backgroundColor = NSColor.clear.cgColor
@ -367,7 +377,7 @@ class PanelController: ParentPanelController {
// We only want to move the slider if the slider is visible.
// If the parent view is hidden, then that doesn't automatically mean that all the childViews are also hidden
// Hence, check if the parent view is totally hidden or not..
if futureSliderView.isHidden == false {
if futureSliderView.isHidden == false, modernSlider.isHidden {
futureSlider.doubleValue += Double(event.scrollingDeltaX)
sliderMoved(futureSlider!)
}

95
Clocker/Panel/ParentPanelController+ModernSlider.swift

@ -0,0 +1,95 @@
// Copyright © 2015 Abhishek Banthia
import CoreLoggerKit
import Foundation
extension ParentPanelController: NSCollectionViewDataSource, NSCollectionViewDelegate {
func collectionView(_: NSCollectionView, numberOfItemsInSection _: Int) -> Int {
return modernSliderDataSource.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let item = collectionView.makeItem(withIdentifier: HourMarkerViewItem.reuseIdentifier, for: indexPath) as! HourMarkerViewItem
let dataSoureValue = modernSliderDataSource[indexPath.item]
item.setup(with: indexPath.item, value: dataSoureValue)
return item
}
}
extension ParentPanelController {
@objc func collectionViewDidScroll(_ notification: NSNotification) {
let contentView = notification.object as! NSClipView
let changedOrigin = contentView.documentVisibleRect.origin
let newPoint = NSPoint(x: changedOrigin.x + contentView.frame.width / 2, y: changedOrigin.y)
let indexPath = modernSlider.indexPathForItem(at: newPoint)
if let correctIndexPath = indexPath?.item, let item = modernSlider.item(at: correctIndexPath) as? HourMarkerViewItem {
modernSliderLabel.stringValue = item.timeRepresentation
// setTimezoneDatasourceSlider(sliderValue: item.indexTag * 15)
item.setupLineColor()
mainTableView.reloadData()
if let previousItem = modernSlider.item(at: correctIndexPath - 1) as? HourMarkerViewItem {
previousItem.resetLineColor()
}
if let nextItem = modernSlider.item(at: correctIndexPath + 1) as? HourMarkerViewItem {
nextItem.resetLineColor()
}
}
}
private func minuteFromCalendar() -> (Date, Int) {
let currentDate = Date()
var minute = Calendar.current.component(.minute, from: currentDate)
if minute < 15 {
minute = 15
} else if minute < 30 {
minute = 30
} else if minute < 45 {
minute = 45
} else {
minute = 0
}
return (currentDate, minute)
}
public func forward15Minutes() -> [String] {
let defaultParameters = minuteFromCalendar()
let hourQuarterDate = Calendar.current.nextDate(after: defaultParameters.0, matching: DateComponents(minute: defaultParameters.1), matchingPolicy: .strict, repeatedTimePolicy: .first, direction: .forward)!
var backwards = hourQuarterDate
var forwards = hourQuarterDate
var hourQuarters = [String]()
for _ in 1 ... 96 {
backwards = Calendar.current.date(byAdding: .minute, value: -15, to: backwards)!
hourQuarters.append(timezoneFormattedStringRepresentation(backwards))
}
hourQuarters.append(timezoneFormattedStringRepresentation(forwards))
for _ in 1 ... 96 {
forwards = Calendar.current.date(byAdding: .minute, value: 15, to: forwards)!
hourQuarters.append(timezoneFormattedStringRepresentation(forwards))
}
return hourQuarters
}
public func backward15Minutes() -> [String] {
let defaultParameters = minuteFromCalendar()
var hourQuarterDate = Calendar.current.nextDate(after: defaultParameters.0, matching: DateComponents(minute: defaultParameters.1), matchingPolicy: .strict, repeatedTimePolicy: .first, direction: .forward)!
var hourQuarters = [String]()
for _ in 1 ... 96 {
hourQuarterDate = Calendar.current.date(byAdding: .minute, value: -15, to: hourQuarterDate)!
hourQuarters.append(timezoneFormattedStringRepresentation(hourQuarterDate))
}
return hourQuarters
}
private func timezoneFormattedStringRepresentation(_ date: Date) -> String {
let dateFormatter = DateFormatterManager.dateFormatterWithFormat(with: .none,
format: "MMM d HH:mm",
timezoneIdentifier: TimeZone.current.identifier,
locale: Locale.autoupdatingCurrent)
return dateFormatter.string(from: date)
}
}

69
Clocker/Panel/ParentPanelController.swift

@ -86,7 +86,10 @@ class ParentPanelController: NSWindowController {
@IBOutlet var roundedDateView: NSView!
// Modern Slider
public var modernSliderDataSource: [String] = []
@IBOutlet var modernSlider: NSCollectionView!
@IBOutlet var modernSliderLabel: NSTextField!
@IBOutlet var modernContainerView: NSView!
var defaultPreferences: [Data] {
return DataStore.shared().timezones()
@ -107,7 +110,16 @@ class ParentPanelController: NSWindowController {
private func setupObservers() {
futureSliderObserver = UserDefaults.standard.observe(\.displayFutureSlider, options: [.new]) { _, change in
if let changedValue = change.newValue {
self.futureSliderView.isHidden = changedValue == 1
if changedValue == 0 {
self.futureSliderView.isHidden = true
self.modernContainerView.isHidden = false
} else if changedValue == 1 {
self.futureSliderView.isHidden = false
self.modernContainerView.isHidden = true
} else {
self.futureSliderView.isHidden = true
self.modernContainerView.isHidden = true
}
}
}
@ -159,7 +171,18 @@ class ParentPanelController: NSWindowController {
themeChanged()
futureSliderView.isHidden = !DataStore.shared().shouldDisplay(.futureSlider)
if DataStore.shared().timezones().isEmpty || DataStore.shared().shouldDisplay(.futureSlider) == false {
futureSliderView.isHidden = true
modernContainerView.isHidden = true
} else if let value = DataStore.shared().retrieve(key: CLDisplayFutureSliderKey) as? NSNumber {
if value.intValue == 1 {
futureSliderView.isHidden = false
modernContainerView.isHidden = true
} else if value.intValue == 0 {
futureSliderView.isHidden = true
modernContainerView.isHidden = false
}
}
sharingButton.sendAction(on: .leftMouseDown)
@ -175,8 +198,22 @@ class ParentPanelController: NSWindowController {
}
if modernSlider != nil {
// var backwards = backward15Minutes()
// backwards.reverse()
// let forwards = forward15Minutes()
modernSliderDataSource = forward15Minutes()
print(modernSliderDataSource)
modernSlider.enclosingScrollView?.scrollerInsets = NSEdgeInsets(top: 0, left: 0, bottom: 100, right: 0)
modernSlider.delegate = self
modernSlider.postsBoundsChangedNotifications = true
NotificationCenter.default.addObserver(self,
selector: #selector(collectionViewDidScroll(_:)),
name: NSView.boundsDidChangeNotification,
object: modernSlider.superview)
modernSliderLabel.stringValue = modernSliderDataSource[modernSliderDataSource.count / 2]
let indexPaths: Set<IndexPath> = Set([IndexPath(item: modernSliderDataSource.count / 2, section: 0)])
modernSlider.scrollToItems(at: indexPaths, scrollPosition: .centeredHorizontally)
}
if roundedDateView != nil {
@ -559,7 +596,9 @@ class ParentPanelController: NSWindowController {
if let futureSliderCell = futureSlider.cell as? CustomSliderCell, futureSliderCell.tracking == true {
return
}
if modernSliderLabel.isHidden == false {
return
}
let dataOperation = TimezoneDataOperations(with: model)
cellView.time.stringValue = dataOperation.time(with: futureSliderValue)
cellView.sunriseSetTime.stringValue = dataOperation.formattedSunriseTime(with: futureSliderValue)
@ -842,7 +881,7 @@ class ParentPanelController: NSWindowController {
} else {
updateReviewView()
RateController.prompted()
ReviewController.prompted()
if let countryCode = Locale.autoupdatingCurrent.regionCode {
Logger.log(object: ["CurrentCountry": countryCode], for: "Remind Later for Feedback")
@ -857,7 +896,7 @@ class ParentPanelController: NSWindowController {
leftTitle: PanelConstants.noThanksTitle,
rightTitle: "Yes")
} else if sender.title == PanelConstants.yesWithQuestionMark {
RateController.prompted()
ReviewController.prompted()
updateReviewView()
feedbackWindow = AppFeedbackWindowController.shared()
@ -865,7 +904,7 @@ class ParentPanelController: NSWindowController {
NSApp.activate(ignoringOtherApps: true)
} else {
updateReviewView()
RateController.prompt()
ReviewController.prompt()
if let countryCode = Locale.autoupdatingCurrent.regionCode {
Logger.log(object: ["CurrentCountry": countryCode], for: "Remind Later for Feedback")
@ -876,7 +915,7 @@ class ParentPanelController: NSWindowController {
private func updateReviewView() {
reviewView.isHidden = true
showReviewCell = false
leftField.stringValue = NSLocalizedString("Enjoy using Clocker",
leftField.stringValue = NSLocalizedString("Enjoy using Clocker?",
comment: "Title asking users if they like the app")
let paragraphStyle = NSMutableParagraphStyle()
@ -1031,19 +1070,3 @@ extension ParentPanelController: NSSharingServicePickerDelegate {
return self as? NSSharingServiceDelegate
}
}
extension ParentPanelController: NSCollectionViewDataSource, NSCollectionViewDelegate {
func collectionView(_: NSCollectionView, numberOfItemsInSection _: Int) -> Int {
return 24
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let item = collectionView.makeItem(withIdentifier: HourMarkerViewItem.reuseIdentifier, for: indexPath) as! HourMarkerViewItem
item.setup(with: indexPath.item)
return item
}
func collectionView(_: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {
Logger.info("Did Select Item at \(indexPaths.description)")
}
}

11
Clocker/Panel/Rate Controller/RateController.swift → Clocker/Panel/Rate Controller/ReviewController.swift

@ -1,8 +1,9 @@
// Copyright © 2015 Abhishek Banthia
import Cocoa
import StoreKit
final class RateController {
final class ReviewController {
private static var storage = UserDefaults.standard
private static let version: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "N/A"
private static var debugging = false
@ -62,7 +63,13 @@ final class RateController {
guard let ratingsURL = URL(string: AboutUsConstants.AppStoreLink) else {
return
}
NSWorkspace.shared.open(ratingsURL)
if #available(OSX 10.14, *) {
SKStoreReviewController.requestReview()
} else {
NSWorkspace.shared.open(ratingsURL)
}
prompted()
}
}

36
Clocker/Panel/UI/FloatingWindow.xib

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17154" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17154"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -37,7 +37,7 @@
<windowCollectionBehavior key="collectionBehavior" moveToActiveSpace="YES" ignoresCycle="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="1000" y="379" width="350" height="460"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1025"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
<value key="minSize" type="size" width="150" height="50"/>
<value key="maxSize" type="size" width="350" height="800"/>
<view key="contentView" misplaced="YES" id="qEx-SC-5Qd">
@ -48,13 +48,13 @@
<rect key="frame" x="0.0" y="0.0" width="379" height="460"/>
<subviews>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="81" horizontalPageScroll="10" verticalLineScroll="81" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="khu-OS-PzP">
<rect key="frame" x="0.0" y="195" width="379" height="265"/>
<rect key="frame" x="9" y="195" width="370" height="265"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="2rS-3B-A3C">
<rect key="frame" x="0.0" y="0.0" width="379" height="265"/>
<rect key="frame" x="0.0" y="0.0" width="370" height="265"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowHeight="80" viewBased="YES" id="3js-Fl-DdU" customClass="PanelTableView" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="379" height="265"/>
<rect key="frame" x="0.0" y="0.0" width="370" height="265"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="1"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -73,13 +73,13 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="timeZoneCell" id="UES-Eo-BEf" customClass="TimezoneCellView" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="1" y="0.0" width="338" height="80"/>
<rect key="frame" x="11" y="0.0" width="347" height="80"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="751" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="751" tag="100" preferredMaxLayoutWidth="150" translatesAutoresizingMaskIntoConstraints="NO" id="Nov-Lq-MHq">
<rect key="frame" x="33" y="50" width="169" height="20"/>
<rect key="frame" x="33" y="50" width="178" height="20"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" placeholderString="Timezone Name" id="NN9-pF-Axo">
<font key="font" size="15" name="Avenir-Light"/>
<font key="font" size="15" name="Avenir-Medium"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</textFieldCell>
@ -91,13 +91,13 @@
<constraint firstAttribute="height" constant="20" id="zbG-5a-kZz"/>
</constraints>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" state="on" usesSingleLineMode="YES" id="MAt-8Z-HKJ">
<font key="font" size="13" name="Avenir-Heavy"/>
<font key="font" size="13" name="Avenir-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="751" tag="101" preferredMaxLayoutWidth="110" translatesAutoresizingMaskIntoConstraints="NO" id="vG5-PS-a35">
<rect key="frame" x="206" y="43" width="114" height="30"/>
<rect key="frame" x="215" y="43" width="114" height="30"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="110" id="DyD-zQ-QUy"/>
</constraints>
@ -108,7 +108,7 @@
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NYh-Nx-Z7X">
<rect key="frame" x="33" y="2" width="287" height="22"/>
<rect key="frame" x="33" y="2" width="296" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" id="S78-bF-ZaL"/>
</constraints>
@ -119,7 +119,7 @@
</textFieldCell>
</textField>
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="fsY-Co-wno">
<rect key="frame" x="270" y="27" width="50" height="17"/>
<rect key="frame" x="279" y="27" width="50" height="17"/>
<constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="59" id="UUh-5p-Mx2"/>
<constraint firstAttribute="height" constant="17" id="qB5-wj-dAu"/>
@ -131,7 +131,7 @@
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="WfK-L4-OKG">
<rect key="frame" x="250" y="26" width="20" height="20"/>
<rect key="frame" x="259" y="26" width="20" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="gDq-Uj-NYZ"/>
<constraint firstAttribute="height" constant="20" id="rIi-uA-qtx"/>
@ -208,11 +208,11 @@
</connections>
</tableCellView>
<tableCellView identifier="addCell" id="ort-42-Yhe" customClass="AddTableViewCell" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="1" y="81" width="338" height="100"/>
<rect key="frame" x="11" y="81" width="347" height="100"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1o3-e8-MQn">
<rect key="frame" x="129" y="10" width="80" height="80"/>
<rect key="frame" x="134" y="10" width="80" height="80"/>
<constraints>
<constraint firstAttribute="width" constant="80" id="Quz-2f-tUq"/>
<constraint firstAttribute="height" constant="80" id="bJL-T6-r6z"/>
@ -401,7 +401,7 @@
<rect key="frame" x="0.0" y="40" width="350" height="30"/>
<subviews>
<datePicker focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ngk-LZ-J2y">
<rect key="frame" x="203" y="14" width="137" height="23"/>
<rect key="frame" x="203" y="0.0" width="137" height="23"/>
<datePickerCell key="cell" focusRingType="none" alignment="left" drawsBackground="NO" datePickerStyle="textField" id="fj6-ZG-8ff">
<font key="font" size="13" name="Avenir-Roman"/>
<date key="date" timeIntervalSinceReferenceDate="-595929600">
@ -416,7 +416,7 @@
</connections>
</datePicker>
<slider verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XQc-HF-TrM">
<rect key="frame" x="7" y="6" width="196" height="19"/>
<rect key="frame" x="7" y="2" width="196" height="23"/>
<constraints>
<constraint firstAttribute="height" constant="15" id="UT0-Yf-jfk"/>
</constraints>

38
Clocker/Panel/UI/HourMarkerViewItem.swift

@ -4,20 +4,29 @@ import Cocoa
class HourMarkerViewItem: NSCollectionViewItem {
static let reuseIdentifier = NSUserInterfaceItemIdentifier("HourMarkerViewItem")
public var timeRepresentation: String = "-1"
@IBOutlet var hourLabel: NSTextField!
func setup(with index: Int, value: String) {
timeRepresentation = value
func setup(with hour: Int) {
var dateComponents = DateComponents()
dateComponents.hour = hour
for constraint in view.constraints where constraint.identifier == "constrainFromTop" {
if index % 4 == 0 {
constraint.constant = 0
} else {
constraint.constant = 20
}
}
}
if let newDate = Calendar.autoupdatingCurrent.date(byAdding: dateComponents, to: Date().nextHour) {
let dateFormatter = DateFormatterManager.dateFormatterWithFormat(with: .none,
format: "HH:mm",
timezoneIdentifier: TimeZone.current.identifier,
locale: Locale.autoupdatingCurrent)
func setupLineColor() {
for subview in view.subviews where subview is NSBox {
subview.layer?.backgroundColor = NSColor.black.cgColor
}
}
hourLabel.stringValue = dateFormatter.string(from: newDate)
func resetLineColor() {
for subview in view.subviews where subview is NSBox {
subview.layer?.backgroundColor = nil
}
}
@ -25,12 +34,3 @@ class HourMarkerViewItem: NSCollectionViewItem {
return false
}
}
extension Date {
public var nextHour: Date {
let calendar = Calendar.current
let minutes = calendar.component(.minute, from: self)
let components = DateComponents(hour: 1, minute: -minutes)
return calendar.date(byAdding: components, to: self) ?? self
}
}

27
Clocker/Panel/UI/HourMarkerViewItem.xib

@ -1,13 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17156" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17156"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="HourMarkerViewItem" customModule="Clocker" customModuleProvider="target">
<connections>
<outlet property="constraintFromTop" destination="s8k-hS-sHN" id="aWd-YA-FDM"/>
<outlet property="verticalLine" destination="1AP-TS-SAk" id="kxC-uc-q7X"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
</connections>
</customObject>
@ -17,33 +19,22 @@
<rect key="frame" x="0.0" y="0.0" width="181" height="103"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<box horizontalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="1AP-TS-SAk">
<rect key="frame" x="86" y="23" width="9" height="80"/>
<box focusRingType="none" horizontalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="1AP-TS-SAk">
<rect key="frame" x="88" y="0.0" width="5" height="103"/>
<constraints>
<constraint firstAttribute="width" constant="5" id="DvW-Pd-tOA"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="1" id="DvW-Pd-tOA"/>
</constraints>
</box>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="loc-Ga-aDA">
<rect key="frame" x="76" y="0.0" width="30" height="18"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="8:00" id="x1W-QM-ton">
<font key="font" size="13" name="Avenir-Book"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="1AP-TS-SAk" firstAttribute="centerX" secondItem="Hz6-mo-xeY" secondAttribute="centerX" id="Ki4-9N-cRe"/>
<constraint firstAttribute="bottom" secondItem="loc-Ga-aDA" secondAttribute="bottom" id="cf2-W7-MIg"/>
<constraint firstItem="loc-Ga-aDA" firstAttribute="centerX" secondItem="Hz6-mo-xeY" secondAttribute="centerX" id="jdj-qX-jCt"/>
<constraint firstItem="1AP-TS-SAk" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="s8k-hS-sHN"/>
<constraint firstItem="loc-Ga-aDA" firstAttribute="top" secondItem="1AP-TS-SAk" secondAttribute="bottom" constant="5" id="sDM-Xa-ZS4"/>
<constraint firstAttribute="bottom" secondItem="1AP-TS-SAk" secondAttribute="bottom" id="VbR-OQ-DUr"/>
<constraint firstItem="1AP-TS-SAk" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" identifier="constrainFromTop" id="s8k-hS-sHN"/>
</constraints>
<point key="canvasLocation" x="-17.5" y="283"/>
</customView>
<customObject id="p0M-E4-898" customClass="HourMarkerViewItem" customModule="Clocker" customModuleProvider="target">
<connections>
<outlet property="hourLabel" destination="loc-Ga-aDA" id="ZFf-u1-jVN"/>
<outlet property="view" destination="Hz6-mo-xeY" id="9S0-wg-csq"/>
</connections>
</customObject>

37
Clocker/Preferences/General/PreferencesViewController.swift

@ -438,7 +438,7 @@ extension PreferencesViewController {
return
}
let searchResults = self.decode(from: data)
let searchResults = data.decode()
if searchResults?.status == "ZERO_RESULTS" {
self.findLocalSearchResultsForTimezones()
@ -460,8 +460,6 @@ extension PreferencesViewController {
private func findLocalSearchResultsForTimezones() {
let lowercasedSearchString = searchField.stringValue.lowercased()
searchResultsDataSource.searchTimezones(lowercasedSearchString)
Logger.info(searchResultsDataSource.timezoneFilteredArray.debugDescription)
}
private func generateSearchURL() -> String {
@ -520,30 +518,6 @@ extension PreferencesViewController {
}
}
// Extracting this out for tests
private func decode(from data: Data) -> SearchResult? {
let jsonDecoder = JSONDecoder()
do {
let decodedObject = try jsonDecoder.decode(SearchResult.self, from: data)
return decodedObject
} catch {
Logger.info("decodedObject error: \n\(error)")
return nil
}
}
// Extracting this out for tests
private func decodeTimezone(from data: Data) -> Timezone? {
let jsonDecoder = JSONDecoder()
do {
let decodedObject = try jsonDecoder.decode(Timezone.self, from: data)
return decodedObject
} catch {
Logger.info("decodedObject error: \n\(error)")
return nil
}
}
private func resetSearchView() {
if dataTask?.state == .running {
dataTask?.cancel()
@ -576,7 +550,7 @@ extension PreferencesViewController {
return
}
if error == nil, let json = response, let timezone = strongSelf.decodeTimezone(from: json) {
if error == nil, let json = response, let timezone = json.decodeTimezone() {
if strongSelf.availableTimezoneTableView.selectedRow >= 0 {
strongSelf.installTimezone(timezone)
}
@ -597,7 +571,7 @@ extension PreferencesViewController {
}
private func installTimezone(_ timezone: Timezone) {
guard let dataObject = searchResultsDataSource.retrieveFilteredResult(availableTimezoneTableView.selectedRow) else {
guard let dataObject = searchResultsDataSource.retrieveFilteredResultFromGoogleAPI(availableTimezoneTableView.selectedRow) else {
assertionFailure("Data was unexpectedly nil")
return
}
@ -742,7 +716,7 @@ extension PreferencesViewController {
}
private func cleanupAfterInstallingCity() {
guard let dataObject = searchResultsDataSource.retrieveFilteredResult(availableTimezoneTableView.selectedRow) else {
guard let dataObject = searchResultsDataSource.retrieveFilteredResultFromGoogleAPI(availableTimezoneTableView.selectedRow) else {
assertionFailure("Data was unexpectedly nil")
return
}
@ -763,8 +737,7 @@ extension PreferencesViewController {
let data = TimezoneData()
data.setLabel(CLEmptyString)
let currentSelection = searchResultsDataSource.retrieveSelectedTimezone(searchField.stringValue,
availableTimezoneTableView.selectedRow)
let currentSelection = searchResultsDataSource.retrieveSelectedTimezone(availableTimezoneTableView.selectedRow)
let metaInfo = metadata(for: currentSelection)
data.timezoneID = metaInfo.0.name

41
Clocker/Preferences/General/SearchDataSource.swift

@ -8,6 +8,11 @@ enum RowType {
case timezone
}
enum SearchLocation {
case onboarding
case preferences
}
struct TimezoneMetadata {
let timezone: NSTimeZone
let tags: Set<String>
@ -18,6 +23,7 @@ struct TimezoneMetadata {
class SearchDataSource: NSObject {
private var searchField: NSSearchField!
private var finalArray: [RowType] = []
private var location: SearchLocation = .preferences
private var dataTask: URLSessionDataTask? = .none
private var timezoneMetadataDictionary: [String: [String]] =
["GMT+5:30": ["india", "indian", "kolkata", "calcutta", "mumbai", "delhi", "hyderabad", "noida"],
@ -27,13 +33,14 @@ class SearchDataSource: NSObject {
"EST": ["florida", "new york"],
"EDT": ["florida", "new york"]]
private var filteredArray: [TimezoneData] = []
private var timezoneArray: [TimezoneMetadata] = []
var timezoneFilteredArray: [TimezoneMetadata] = []
private var filteredArray: [TimezoneData] = [] // Filtered results from the Google API
private var timezoneArray: [TimezoneMetadata] = [] // All timezones
var timezoneFilteredArray: [TimezoneMetadata] = [] // Filtered timezones list based on search input
init(with searchField: NSSearchField) {
init(with searchField: NSSearchField, location: SearchLocation = .preferences) {
super.init()
self.searchField = searchField
self.location = location
setupTimezoneDatasource()
calculateChangesets()
}
@ -50,10 +57,28 @@ class SearchDataSource: NSObject {
return finalArray[row]
}
func retrieveFilteredResult(_ index: Int) -> TimezoneData? {
// Returns result from finalArray based on the type i.e. city or timezone
func retrieveResult(_ row: Int) -> Any? {
let currentRowType = finalArray[row]
switch currentRowType {
case .timezone:
let datasource = searchField.stringValue.isEmpty ? timezoneArray : timezoneFilteredArray
return datasource[row % datasource.count]
case .city:
let timezoneData = filteredArray[row % filteredArray.count]
return timezoneData
}
}
func retrieveFilteredResultFromGoogleAPI(_ index: Int) -> TimezoneData? {
return filteredArray[index % filteredArray.count]
}
func resultsCount() -> Int {
return finalArray.count
}
private func setupTimezoneDatasource() {
timezoneArray = []
@ -103,7 +128,7 @@ class SearchDataSource: NSObject {
}
}
if searchField.stringValue.isEmpty {
if searchField.stringValue.isEmpty, location == .preferences {
addTimezonesIfNeeded(timezoneArray)
} else {
filteredArray.forEach { _ in
@ -132,8 +157,8 @@ class SearchDataSource: NSObject {
}
}
func retrieveSelectedTimezone(_ searchString: String, _ selectedIndex: Int) -> TimezoneMetadata {
return searchString.isEmpty == false ? timezoneFilteredArray[selectedIndex % timezoneFilteredArray.count] :
func retrieveSelectedTimezone(_ selectedIndex: Int) -> TimezoneMetadata {
return searchField.stringValue.isEmpty == false ? timezoneFilteredArray[selectedIndex % timezoneFilteredArray.count] :
timezoneArray[selectedIndex]
}
}

66
Clocker/Preferences/Preferences.storyboard

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17506" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="RHq-9Z-auA">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="RHq-9Z-auA">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17506"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -909,11 +909,11 @@
</slider>
<scrollView borderType="line" autohidesScrollers="YES" horizontalLineScroll="113" horizontalPageScroll="10" verticalLineScroll="113" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ytg-0u-Mtu">
<rect key="frame" x="122" y="81" width="400" height="100"/>
<clipView key="contentView" ambiguous="YES" id="gnX-f5-31D">
<clipView key="contentView" id="gnX-f5-31D">
<rect key="frame" x="1" y="1" width="398" height="98"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="111" rowSizeStyle="automatic" viewBased="YES" id="KbJ-p4-i6E">
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="111" rowSizeStyle="automatic" viewBased="YES" id="KbJ-p4-i6E">
<rect key="frame" x="0.0" y="0.0" width="398" height="113"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
@ -1168,7 +1168,7 @@
</tabViewItem>
<tabViewItem label="Misc" identifier="" id="ztQ-ui-wYI">
<view key="view" id="mF4-bp-EID">
<rect key="frame" x="10" y="33" width="623" height="432"/>
<rect key="frame" x="10" y="33" width="643" height="432"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" preferredMaxLayoutWidth="175" translatesAutoresizingMaskIntoConstraints="NO" id="fTA-lS-4wJ">
@ -1183,7 +1183,7 @@
</textFieldCell>
</textField>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Axn-Tb-Cdx">
<rect key="frame" x="242" y="361" width="83" height="24"/>
<rect key="frame" x="242" y="361" width="85" height="24"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="04s-TY-ltB">
<font key="font" size="12" name="Avenir-Light"/>
<segments>
@ -1205,7 +1205,7 @@
</textFieldCell>
</textField>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KeW-e2-uQE">
<rect key="frame" x="242" y="285" width="83" height="24"/>
<rect key="frame" x="242" y="285" width="85" height="24"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="n7R-Fj-KSe">
<font key="font" size="12" name="Avenir-Light"/>
<segments>
@ -1219,7 +1219,7 @@
</connections>
</segmentedControl>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="AxB-VD-lXm">
<rect key="frame" x="242" y="323" width="83" height="24"/>
<rect key="frame" x="242" y="323" width="85" height="24"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="0UT-Io-qfp">
<font key="font" size="12" name="Avenir-Light"/>
<segments>
@ -1252,7 +1252,7 @@
</textFieldCell>
</textField>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Mai-SZ-AEi">
<rect key="frame" x="242" y="247" width="146" height="24"/>
<rect key="frame" x="242" y="247" width="128" height="24"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="tbg-LS-tZH">
<font key="font" size="12" name="Avenir-Light"/>
<segments>
@ -1266,7 +1266,7 @@
</connections>
</segmentedControl>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Q3M-Kz-XV3">
<rect key="frame" x="256" y="403" width="112" height="22"/>
<rect key="frame" x="266" y="403" width="112" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" id="eJS-Lu-Avz"/>
<constraint firstAttribute="width" constant="108" id="y01-ys-4L6"/>
@ -1278,16 +1278,16 @@
</textFieldCell>
</textField>
<box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="XeT-rJ-1io">
<rect key="frame" x="-3" y="226" width="629" height="5"/>
<rect key="frame" x="-3" y="225" width="649" height="5"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="SdH-Fo-qYn"/>
</constraints>
</box>
<visualEffectView hidden="YES" focusRingType="none" blendingMode="withinWindow" material="light" state="followsWindowActiveState" translatesAutoresizingMaskIntoConstraints="NO" id="Wj2-aw-ZDm">
<rect key="frame" x="0.0" y="228" width="623" height="204"/>
<rect key="frame" x="0.0" y="227" width="643" height="205"/>
<subviews>
<textField hidden="YES" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="dtb-8u-6gN">
<rect key="frame" x="60" y="82" width="504" height="40"/>
<rect key="frame" x="70" y="83" width="504" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="7tY-09-nYM"/>
<constraint firstAttribute="width" constant="500" id="Taz-W1-qVP"/>
@ -1305,7 +1305,7 @@
</constraints>
</visualEffectView>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="DjV-qq-hr9">
<rect key="frame" x="242" y="144" width="230" height="24"/>
<rect key="frame" x="242" y="144" width="212" height="24"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="kvB-5f-IK4">
<font key="font" size="12" name="Avenir-Light"/>
<segments>
@ -1319,7 +1319,7 @@
</connections>
</segmentedControl>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" preferredMaxLayoutWidth="120" translatesAutoresizingMaskIntoConstraints="NO" id="GaR-Qm-7u4">
<rect key="frame" x="17" y="110" width="204" height="18"/>
<rect key="frame" x="17" y="109" width="204" height="18"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="lod-PT-AI5"/>
</constraints>
@ -1330,7 +1330,7 @@
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" preferredMaxLayoutWidth="120" translatesAutoresizingMaskIntoConstraints="NO" id="HNj-dh-8gr">
<rect key="frame" x="67" y="148" width="154" height="18"/>
<rect key="frame" x="67" y="147" width="154" height="18"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="150" id="7zy-Fe-aNw"/>
</constraints>
@ -1341,12 +1341,16 @@
</textFieldCell>
</textField>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pk6-co-N73">
<rect key="frame" x="242" y="68" width="79" height="24"/>
<rect key="frame" x="242" y="68" width="190" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="186" id="GFp-Fx-5i3"/>
</constraints>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="jUA-fY-nhn">
<font key="font" size="12" name="Avenir-Light"/>
<segments>
<segment label="Yes" width="36"/>
<segment label="No" width="36" selected="YES" tag="1"/>
<segment label="Modern" width="71"/>
<segment label="Legacy" width="71" selected="YES" tag="1"/>
<segment label="Hide"/>
</segments>
</segmentedCell>
<accessibility identifier="FutureSlider"/>
@ -1356,7 +1360,7 @@
</connections>
</segmentedControl>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8Nx-Xq-XDU">
<rect key="frame" x="240" y="105" width="223" height="25"/>
<rect key="frame" x="235" y="105" width="232" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="218" id="0qW-So-4cc"/>
</constraints>
@ -1370,18 +1374,18 @@
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" preferredMaxLayoutWidth="120" translatesAutoresizingMaskIntoConstraints="NO" id="8Jv-Cf-blJ">
<rect key="frame" x="17" y="72" width="204" height="18"/>
<rect key="frame" x="17" y="71" width="204" height="18"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="DXS-zG-LoB"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Show Future Slider" id="pfG-By-On0">
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Future Slider Display" id="pfG-By-On0">
<font key="font" size="13" name="Avenir-Light"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ffU-Ce-sfU">
<rect key="frame" x="256" y="186" width="112" height="22"/>
<rect key="frame" x="266" y="185" width="112" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="108" id="3Ch-Kc-bLG"/>
<constraint firstAttribute="height" constant="22" id="tHL-bd-6Pl"/>
@ -1487,7 +1491,7 @@
<windowStyleMask key="styleMask" closable="YES" miniaturizable="YES" nonactivatingPanel="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="120" y="64" width="345" height="320"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1025"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
<value key="minSize" type="size" width="345" height="320"/>
<value key="maxSize" type="size" width="345" height="320"/>
<view key="contentView" misplaced="YES" id="MAe-t5-3A2">
@ -1495,7 +1499,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<searchField toolTip="Search a timezone" wantsLayer="YES" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Dha-h9-Nd0" customClass="ClockerSearchField" customModule="Clocker" customModuleProvider="target">
<rect key="frame" x="8" y="133" width="320" height="23"/>
<rect key="frame" x="8" y="73" width="320" height="23"/>
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" focusRingType="none" placeholderString="Enter a city, state, country name" usesSingleLineMode="YES" maximumRecents="5" id="ikU-Tm-0WZ">
<font key="font" size="13" name="Avenir-Light"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -1552,13 +1556,13 @@ DQ
</connections>
</button>
<scrollView focusRingType="none" borderType="none" autohidesScrollers="YES" horizontalLineScroll="32" horizontalPageScroll="10" verticalLineScroll="32" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0wY-ff-FLW">
<rect key="frame" x="8" y="30" width="320" height="93"/>
<rect key="frame" x="8" y="30" width="320" height="33"/>
<clipView key="contentView" drawsBackground="NO" id="rGc-3M-cCq">
<rect key="frame" x="0.0" y="0.0" width="320" height="93"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="33"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" rowHeight="30" rowSizeStyle="automatic" viewBased="YES" id="xkl-2X-ZCb">
<rect key="frame" x="0.0" y="0.0" width="320" height="93"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="33"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -1648,14 +1652,14 @@ DQ
</scroller>
</scrollView>
<progressIndicator wantsLayer="YES" focusRingType="none" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="0A5-gp-lay">
<rect key="frame" x="160" y="96" width="16" height="16"/>
<rect key="frame" x="160" y="66" width="16" height="16"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="fgE-77-Vda"/>
<constraint firstAttribute="width" constant="16" id="pwe-em-e0a"/>
</constraints>
</progressIndicator>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xgb-wU-8RU">
<rect key="frame" x="18" y="66" width="300" height="22"/>
<rect key="frame" x="18" y="36" width="300" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" id="zqt-d8-yas"/>
</constraints>

16
Readme.md

@ -1,5 +1,4 @@
**Clocker**
---
# Clocker
[![Twitter: @clocker_support](https://img.shields.io/badge/contact-@clocker_support-blue.svg?style=flat)](https://twitter.com/clocker_support) [![Build Status](https://travis-ci.org/n0shake/Clocker.svg?branch=master)](https://travis-ci.org/n0shake/Clocker) [![Crowdin](https://badges.crowdin.net/clocker/localized.svg)](https://crowdin.com/project/clocker)
@ -7,12 +6,17 @@
If you'd like to donate, you can do so [here](https://www.paypal.me/AbhishekBanthia). You can find detailed reviews [here](https://www.podfeet.com/blog/2020/07/clocker/) and [slightly older here](https://lifehacker.com/clocker-crams-a-world-clock-into-your-menu-bar-1794709422). Need any help? Open an issue!
## Install
```shell
brew install --cask clocker
```
or
[![Download on the App Store](https://github.com/n0shake/Clocker/blob/v1.2.1/Clocker/Images/MacAppStore.png)](https://itunes.apple.com/us/app/clocker-menubar-world-clock/id1056643111?mt=12)
**Contributing**
---
# Contributing
**Clocker** is open for pull requests.
**License**
---
# License
Copyright (c) 2020 **Abhishek Banthia**. Released under the MIT License.

Loading…
Cancel
Save