Browse Source

Animated Onboarding Changes.

v1.2.4
Abhishek Banthia 9 years ago
parent
commit
384c0705f3
  1. 12
      Clocker.xcodeproj/project.pbxproj
  2. BIN
      Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate
  3. 20
      Clocker/CLAnimatedImages.h
  4. 241
      Clocker/CLAnimatedImages.m
  5. 16
      Clocker/CLArrowIndicators.h
  6. 66
      Clocker/CLArrowIndicators.m
  7. 15
      Clocker/CLScaleUpButton.h
  8. 45
      Clocker/CLScaleUpButton.m
  9. 71
      Clocker/Onboarding/CLIntroView.xib
  10. 31
      Clocker/Onboarding/CLIntroViewController.m
  11. 16
      Clocker/Onboarding/CLOnboardingWindowController.m
  12. 38
      Clocker/Onboarding/en.lproj/CLOnboardingWindow.xib
  13. 25
      Clocker/PanelController.m
  14. 5
      Clocker/Preferences/CLPreferencesViewController.h
  15. 64
      Clocker/Preferences/CLPreferencesViewController.m
  16. 39
      Clocker/Preferences/en.lproj/CLPreferencesView.xib
  17. 51
      Clocker/QCMethod.h
  18. 346
      Clocker/QCMethod.m
  19. 3
      Clocker/Rate App/iRate.m
  20. 21
      Media.xcassets/HongKong.imageset/Contents.json
  21. BIN
      Media.xcassets/HongKong.imageset/HongKong.jpg
  22. 21
      Media.xcassets/LA.imageset/Contents.json
  23. BIN
      Media.xcassets/LA.imageset/LA.jpg
  24. 21
      Media.xcassets/NYC.imageset/Contents.json
  25. BIN
      Media.xcassets/NYC.imageset/NYC.jpg
  26. 21
      Media.xcassets/Paris.imageset/Contents.json
  27. BIN
      Media.xcassets/Paris.imageset/Paris.jpg
  28. 21
      Media.xcassets/SF.imageset/Contents.json
  29. BIN
      Media.xcassets/SF.imageset/SF.jpg
  30. 21
      Media.xcassets/Singapore.imageset/Contents.json
  31. BIN
      Media.xcassets/Singapore.imageset/Singapore.jpg
  32. 21
      Media.xcassets/Tokyo.imageset/Contents.json
  33. BIN
      Media.xcassets/Tokyo.imageset/Tokyo.jpg
  34. 21
      Media.xcassets/london.imageset/Contents.json
  35. BIN
      Media.xcassets/london.imageset/london.jpg
  36. 21
      Media.xcassets/sydney.imageset/Contents.json
  37. BIN
      Media.xcassets/sydney.imageset/sydney.jpg

12
Clocker.xcodeproj/project.pbxproj

@ -81,6 +81,8 @@
9ACE03EF1CB0ADE00039FC01 /* Firebase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ACE03EE1CB0ADE00039FC01 /* Firebase.framework */; };
9AD6DE571CE114DA007A8401 /* CLScaleUpButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD6DE561CE114DA007A8401 /* CLScaleUpButton.m */; };
9AD6DE651CE18EB4007A8401 /* CLArrowIndicators.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD6DE641CE18EB4007A8401 /* CLArrowIndicators.m */; };
9AE1FFE21CE28CF500827C80 /* CLAnimatedImages.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE1FFDF1CE28CF500827C80 /* CLAnimatedImages.m */; };
9AE1FFE31CE28CF500827C80 /* QCMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE1FFE11CE28CF500827C80 /* QCMethod.m */; };
9AF9A16B1C250AB300EE7C2A /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AF9A16A1C250AB300EE7C2A /* Reachability.m */; };
DD4F7C0913C30F9F00825C6E /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD4F7C0813C30F9F00825C6E /* Cocoa.framework */; };
/* End PBXBuildFile section */
@ -334,6 +336,10 @@
9AD6DE561CE114DA007A8401 /* CLScaleUpButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CLScaleUpButton.m; path = Clocker/CLScaleUpButton.m; sourceTree = "<group>"; };
9AD6DE631CE18EB4007A8401 /* CLArrowIndicators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CLArrowIndicators.h; path = Clocker/CLArrowIndicators.h; sourceTree = "<group>"; };
9AD6DE641CE18EB4007A8401 /* CLArrowIndicators.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CLArrowIndicators.m; path = Clocker/CLArrowIndicators.m; sourceTree = "<group>"; };
9AE1FFDE1CE28CF500827C80 /* CLAnimatedImages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CLAnimatedImages.h; path = Clocker/CLAnimatedImages.h; sourceTree = "<group>"; };
9AE1FFDF1CE28CF500827C80 /* CLAnimatedImages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CLAnimatedImages.m; path = Clocker/CLAnimatedImages.m; sourceTree = "<group>"; };
9AE1FFE01CE28CF500827C80 /* QCMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QCMethod.h; path = Clocker/QCMethod.h; sourceTree = "<group>"; };
9AE1FFE11CE28CF500827C80 /* QCMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = QCMethod.m; path = Clocker/QCMethod.m; sourceTree = "<group>"; };
9AF9A1691C250AB300EE7C2A /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Reachability.h; path = Clocker/Reachability/Reachability.h; sourceTree = "<group>"; };
9AF9A16A1C250AB300EE7C2A /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Reachability.m; path = Clocker/Reachability/Reachability.m; sourceTree = "<group>"; };
DD4F7C0413C30F9F00825C6E /* Clocker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Clocker.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -598,6 +604,10 @@
DD4F7BF913C30F9F00825C6E = {
isa = PBXGroup;
children = (
9AE1FFDE1CE28CF500827C80 /* CLAnimatedImages.h */,
9AE1FFDF1CE28CF500827C80 /* CLAnimatedImages.m */,
9AE1FFE01CE28CF500827C80 /* QCMethod.h */,
9AE1FFE11CE28CF500827C80 /* QCMethod.m */,
9A86E2B51CE04F1600547EE7 /* ShortcutRecorder.xcodeproj */,
9A5E6B9C1CAF7174006E7C5C /* Firebase */,
9A87DA4F1C358F8200A8CF3B /* Date Tools */,
@ -881,6 +891,7 @@
9A25F7471C1A5E17007D369B /* iRate.m in Sources */,
9A8605C01BEC14F600A810A4 /* Panel.m in Sources */,
9AD6DE651CE18EB4007A8401 /* CLArrowIndicators.m in Sources */,
9AE1FFE21CE28CF500827C80 /* CLAnimatedImages.m in Sources */,
9A8605BA1BEC14DC00A810A4 /* StatusItemView.m in Sources */,
9A87DAC91C358FA800A8CF3B /* DTTimePeriodCollection.m in Sources */,
9A3247391C263F4F00CF6B6E /* CLAppearanceViewController.m in Sources */,
@ -889,6 +900,7 @@
9A9E63861C2C673E009A299B /* CLAppFeedbackWindowController.m in Sources */,
9A8605BB1BEC14DC00A810A4 /* PanelController.m in Sources */,
9A8605B61BEC14BE00A810A4 /* MenubarController.m in Sources */,
9AE1FFE31CE28CF500827C80 /* QCMethod.m in Sources */,
9A42394F1CB0616400A8E51A /* CLFloatingWindowController.m in Sources */,
9A10C68F1CDAC8B500D474F1 /* CLPanelTextField.m in Sources */,
9A5951C01C1D0AA0009C17AA /* CLOneWindowController.m in Sources */,

BIN
Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate generated

Binary file not shown.

20
Clocker/CLAnimatedImages.h

@ -0,0 +1,20 @@
//
// CLAnimatedImages.h
//
// Code generated using QuartzCode 1.39.16 on 5/10/16.
// www.quartzcodeapp.com
//
#import <Cocoa/Cocoa.h>
IB_DESIGNABLE
@interface CLAnimatedImages : NSView
- (void)addUntitled1Animation;
- (void)addUntitled1AnimationCompletionBlock:(void (^)(BOOL finished))completionBlock;
- (void)removeAnimationsForAnimationId:(NSString *)identifier;
- (void)removeAllAnimations;
@end

241
Clocker/CLAnimatedImages.m

@ -0,0 +1,241 @@
//
// CLAnimatedImages.m
//
// Code generated using QuartzCode 1.39.16 on 5/10/16.
// www.quartzcodeapp.com
//
#import "CLAnimatedImages.h"
#import "QCMethod.h"
@interface CLAnimatedImages ()
@property (nonatomic, strong) NSMutableDictionary * layers;
@property (nonatomic, strong) NSMapTable * completionBlocks;
@property (nonatomic, assign) BOOL updateLayerValueForCompletedAnimation;
@end
@implementation CLAnimatedImages
#pragma mark - Life Cycle
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupProperties];
[self setupLayers];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self setupProperties];
[self setupLayers];
}
return self;
}
- (void)setupProperties{
self.completionBlocks = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaqueMemory valueOptions:NSPointerFunctionsStrongMemory];;
self.layers = [NSMutableDictionary dictionary];
}
- (void)setupLayers{
[self setWantsLayer:YES];
CALayer * effect = [CALayer layer];
effect.frame = CGRectMake(25.09, 4.93, 230.89, 203.84);
[self.layer addSublayer:effect];
self.layers[@"effect"] = effect;
//effect effect layer setup
{
CALayer * TopPlaces = [CALayer layer];
TopPlaces.frame = CGRectMake(0, -0, 66, 57.02);
[effect addSublayer:TopPlaces];
self.layers[@"TopPlaces"] = TopPlaces;
CALayer * TopPlaces2 = [CALayer layer];
TopPlaces2.frame = CGRectMake(82.46, -0, 65.97, 56.99);
[effect addSublayer:TopPlaces2];
self.layers[@"TopPlaces2"] = TopPlaces2;
CALayer * TopPlaces3 = [CALayer layer];
TopPlaces3.frame = CGRectMake(164.92, -0, 65.97, 56.99);
[effect addSublayer:TopPlaces3];
self.layers[@"TopPlaces3"] = TopPlaces3;
CALayer * TopPlaces4 = [CALayer layer];
TopPlaces4.frame = CGRectMake(0, 73.43, 65.97, 56.99);
[effect addSublayer:TopPlaces4];
self.layers[@"TopPlaces4"] = TopPlaces4;
CALayer * TopPlaces5 = [CALayer layer];
TopPlaces5.frame = CGRectMake(82.46, 73.43, 65.97, 56.99);
[effect addSublayer:TopPlaces5];
self.layers[@"TopPlaces5"] = TopPlaces5;
CALayer * TopPlaces6 = [CALayer layer];
TopPlaces6.frame = CGRectMake(164.92, 73.43, 65.97, 56.99);
[effect addSublayer:TopPlaces6];
self.layers[@"TopPlaces6"] = TopPlaces6;
CALayer * TopPlaces7 = [CALayer layer];
TopPlaces7.frame = CGRectMake(0, 146.86, 65.97, 56.99);
[effect addSublayer:TopPlaces7];
self.layers[@"TopPlaces7"] = TopPlaces7;
CALayer * TopPlaces8 = [CALayer layer];
TopPlaces8.frame = CGRectMake(82.46, 146.86, 65.97, 56.99);
[effect addSublayer:TopPlaces8];
self.layers[@"TopPlaces8"] = TopPlaces8;
CALayer * TopPlaces9 = [CALayer layer];
TopPlaces9.frame = CGRectMake(164.92, 146.86, 65.97, 56.99);
[effect addSublayer:TopPlaces9];
self.layers[@"TopPlaces9"] = TopPlaces9;
}
[self resetLayerPropertiesForLayerIdentifiers:nil];
}
- (void)resetLayerPropertiesForLayerIdentifiers:(NSArray *)layerIds{
[CATransaction begin];
[CATransaction setDisableActions:YES];
if(!layerIds || [layerIds containsObject:@"TopPlaces"]){
CALayer * TopPlaces = self.layers[@"TopPlaces"];
TopPlaces.masksToBounds = YES;
TopPlaces.contents = [NSImage imageNamed:@"Tokyo"];
TopPlaces.contentsGravity = kCAGravityResizeAspectFill;
}
if(!layerIds || [layerIds containsObject:@"TopPlaces2"]){
CALayer * TopPlaces2 = self.layers[@"TopPlaces2"];
TopPlaces2.masksToBounds = YES;
TopPlaces2.contents = [NSImage imageNamed:@"london"];
TopPlaces2.contentsGravity = kCAGravityResizeAspectFill;
}
if(!layerIds || [layerIds containsObject:@"TopPlaces3"]){
CALayer * TopPlaces3 = self.layers[@"TopPlaces3"];
TopPlaces3.masksToBounds = YES;
TopPlaces3.contents = [NSImage imageNamed:@"SF"];
TopPlaces3.contentsGravity = kCAGravityResizeAspectFill;
}
if(!layerIds || [layerIds containsObject:@"TopPlaces4"]){
CALayer * TopPlaces4 = self.layers[@"TopPlaces4"];
TopPlaces4.masksToBounds = YES;
TopPlaces4.contents = [NSImage imageNamed:@"LA"];
TopPlaces4.contentsGravity = kCAGravityResizeAspectFill;
}
if(!layerIds || [layerIds containsObject:@"TopPlaces5"]){
CALayer * TopPlaces5 = self.layers[@"TopPlaces5"];
TopPlaces5.masksToBounds = YES;
TopPlaces5.contents = [NSImage imageNamed:@"sydney"];
TopPlaces5.contentsGravity = kCAGravityResizeAspectFill;
}
if(!layerIds || [layerIds containsObject:@"TopPlaces6"]){
CALayer * TopPlaces6 = self.layers[@"TopPlaces6"];
TopPlaces6.masksToBounds = YES;
TopPlaces6.contents = [NSImage imageNamed:@"Singapore"];
TopPlaces6.contentsGravity = kCAGravityResizeAspectFill;
}
if(!layerIds || [layerIds containsObject:@"TopPlaces7"]){
CALayer * TopPlaces7 = self.layers[@"TopPlaces7"];
TopPlaces7.masksToBounds = YES;
TopPlaces7.contents = [NSImage imageNamed:@"NYC"];
TopPlaces7.contentsGravity = kCAGravityResizeAspectFill;
}
if(!layerIds || [layerIds containsObject:@"TopPlaces8"]){
CALayer * TopPlaces8 = self.layers[@"TopPlaces8"];
TopPlaces8.masksToBounds = YES;
TopPlaces8.contents = [NSImage imageNamed:@"HongKong"];
TopPlaces8.contentsGravity = kCAGravityResizeAspectFill;
}
if(!layerIds || [layerIds containsObject:@"TopPlaces9"]){
CALayer * TopPlaces9 = self.layers[@"TopPlaces9"];
TopPlaces9.masksToBounds = YES;
TopPlaces9.contents = [NSImage imageNamed:@"Paris"];
TopPlaces9.contentsGravity = kCAGravityResizeAspectFill;
}
[CATransaction commit];
}
#pragma mark - Animation Setup
- (void)addUntitled1Animation{
[self addUntitled1AnimationCompletionBlock:nil];
}
- (void)addUntitled1AnimationCompletionBlock:(void (^)(BOOL finished))completionBlock{
if (completionBlock){
CABasicAnimation * completionAnim = [CABasicAnimation animationWithKeyPath:@"completionAnim"];;
completionAnim.duration = 4.2;
completionAnim.delegate = self;
[completionAnim setValue:@"Untitled1" forKey:@"animId"];
[completionAnim setValue:@(NO) forKey:@"needEndAnim"];
[self.layer addAnimation:completionAnim forKey:@"Untitled1"];
[self.completionBlocks setObject:completionBlock forKey:[self.layer animationForKey:@"Untitled1"]];
}
NSString * fillMode = kCAFillModeForwards;
////Effect animation
CAKeyframeAnimation * effectTransformAnim = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
effectTransformAnim.values = @[[NSValue valueWithCATransform3D:CATransform3DIdentity],
[NSValue valueWithCATransform3D:CATransform3DConcat(CATransform3DMakeScale(1.5, 1.5, 1), CATransform3DMakeRotation(-3 * M_PI/180, -0, -0, 1))],
[NSValue valueWithCATransform3D:CATransform3DConcat(CATransform3DMakeScale(1.5, 1.5, 1), CATransform3DMakeRotation(3 * M_PI/180, 0, 0, 1))]];
effectTransformAnim.keyTimes = @[@0, @0.44, @1];
effectTransformAnim.duration = 0.5;
effectTransformAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
effectTransformAnim.autoreverses = YES;
[effectTransformAnim setValue:@0.4 forKeyPath:@"instanceDelay"];
[effectTransformAnim setValue:@0 forKeyPath:@"instanceOrder"];
CABasicAnimation * effectZPositionAnim = [CABasicAnimation animationWithKeyPath:@"zPosition"];
effectZPositionAnim.fromValue = @0;
effectZPositionAnim.toValue = @100;
effectZPositionAnim.duration = 0.5;
effectZPositionAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
effectZPositionAnim.autoreverses = YES;
[effectZPositionAnim setValue:@0.4 forKeyPath:@"instanceDelay"];
[effectZPositionAnim setValue:@0 forKeyPath:@"instanceOrder"];
CAAnimationGroup * effectUntitled1Anim = [QCMethod groupAnimations:@[effectTransformAnim, effectZPositionAnim] fillMode:kCAFillModeBoth forEffectLayer:YES sublayersCount:9];
[QCMethod addSublayersAnimation:effectUntitled1Anim forKey:@"effectUntitled1Anim" forLayer:(CALayer *)self.layers[@"effect"]];
}
#pragma mark - Animation Cleanup
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
void (^completionBlock)(BOOL) = [self.completionBlocks objectForKey:anim];;
if (completionBlock){
[self.completionBlocks removeObjectForKey:anim];
if ((flag && self.updateLayerValueForCompletedAnimation) || [[anim valueForKey:@"needEndAnim"] boolValue]){
[self updateLayerValuesForAnimationId:[anim valueForKey:@"animId"]];
[self removeAnimationsForAnimationId:[anim valueForKey:@"animId"]];
}
completionBlock(flag);
}
}
- (void)updateLayerValuesForAnimationId:(NSString *)identifier{
if([identifier isEqualToString:@"Untitled1"]){
[QCMethod updateValueFromPresentationLayerForAnimation:[self.layers[@"effect"] animationForKey:@"effectUntitled1Anim"] theLayer:self.layers[@"effect"]];
}
}
- (void)removeAnimationsForAnimationId:(NSString *)identifier{
if([identifier isEqualToString:@"Untitled1"]){
[self.layers[@"effect"] removeAnimationForKey:@"effectUntitled1Anim"];
}
}
- (void)removeAllAnimations{
[self.layers enumerateKeysAndObjectsUsingBlock:^(id key, CALayer *layer, BOOL *stop) {
[layer removeAllAnimations];
}];
}
@end

16
Clocker/CLArrowIndicators.h

@ -0,0 +1,16 @@
//
// CLArrowIndicators.h
// Clocker
//
// Created by Abhishek Banthia on 5/9/16.
//
//
#import <Cocoa/Cocoa.h>
@interface CLArrowIndicators : NSControl
@property (strong, nonatomic) NSColor *blackColor;
@property (assign, nonatomic) BOOL mouseDown;
@end

66
Clocker/CLArrowIndicators.m

@ -0,0 +1,66 @@
//
// CLArrowIndicators.m
// Clocker
//
// Created by Abhishek Banthia on 5/9/16.
//
//
#import "CLArrowIndicators.h"
typedef enum : NSUInteger {
Left,
Right
} Type;
@implementation CLArrowIndicators
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// let drawRightArrow = self.type == .Right
// let lineWidth: CGFloat = 4
//
// let bezierPath = NSBezierPath()
// bezierPath.moveToPoint(NSPoint(x: drawRightArrow ? NSMinX(self.bounds) : NSMaxX(self.bounds), y: NSMaxY(self.bounds)))
// bezierPath.lineToPoint(NSPoint(x: drawRightArrow ? NSMaxX(self.bounds)-lineWidth*0.5 : NSMinX(self.bounds)+lineWidth*0.5, y: NSMidY(self.bounds)))
// bezierPath.lineToPoint(NSPoint(x: drawRightArrow ? NSMinX(self.bounds) : NSMaxX(self.bounds), y: NSMinY(self.bounds)))
// bezierPath.lineWidth = lineWidth
// bezierPath.lineCapStyle = .RoundLineCapStyle
// bezierPath.lineJoinStyle = .RoundLineJoinStyle
// (self.mouseDown ? self.color : self.color.colorWithAlphaComponent(0.33)).setStroke()
// bezierPath.stroke()
Type drawRightArrow = Right;
CGFloat lineWidth = 4;
NSBezierPath *bezierPath = [[NSBezierPath alloc] init];
[bezierPath moveToPoint:NSMakePoint(drawRightArrow ? NSMinX(self.bounds) : NSMaxX(self.bounds), NSMaxY(self.bounds))];
[bezierPath lineToPoint:NSMakePoint(drawRightArrow ? NSMaxX(self.bounds) - lineWidth*0.5 : NSMinX(self.bounds) + lineWidth*0.5, NSMidY(self.bounds))];
[bezierPath lineToPoint:NSMakePoint(drawRightArrow ? NSMinX(self.bounds) : NSMaxX(self.bounds), NSMidY(self.bounds))];
bezierPath.lineWidth = lineWidth;
bezierPath.lineCapStyle = NSRoundLineCapStyle;
bezierPath.lineJoinStyle = NSRoundLineJoinStyle;
self.mouseDown ? self.blackColor : [[self.blackColor colorWithAlphaComponent:0.33] setStroke];
[bezierPath stroke];
// Drawing code here.
}
- (void)mouseDown:(NSEvent *)theEvent
{
[super mouseDown:theEvent];
self.mouseDown = YES;
}
- (void)mouseUp:(NSEvent *)theEvent
{
[super mouseUp:theEvent];
self.mouseDown = NO;
[NSApp sendAction:self.action to:self.target from:self];
}
@end

15
Clocker/CLScaleUpButton.h

@ -0,0 +1,15 @@
//
// CLScaleUpButton.h
// Clocker
//
// Created by Abhishek Banthia on 5/9/16.
//
//
#import <Cocoa/Cocoa.h>
@interface CLScaleUpButton : NSButton
@property (strong, nonatomic) NSTrackingArea *trackingArea;
@end

45
Clocker/CLScaleUpButton.m

@ -0,0 +1,45 @@
//
// CLScaleUpButton.m
// Clocker
//
// Created by Abhishek Banthia on 5/9/16.
//
//
#import "CLScaleUpButton.h"
#import <pop/POP.h>
@implementation CLScaleUpButton
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
-(void)mouseEntered:(NSEvent *)theEvent
{
[super mouseEntered:theEvent];
POPSpringAnimation *scale = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
scale.velocity = [NSValue valueWithCGPoint:CGPointMake(1, 1)];
scale.springBounciness = 20.f;
[self.layer pop_addAnimation:scale forKey:@"scale"];
}
-(void)updateTrackingAreas
{
if(self.trackingArea != nil) {
[self removeTrackingArea:self.trackingArea];
}
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
self.trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:self.trackingArea];
}
@end

71
Clocker/Onboarding/CLIntroView.xib

@ -1,43 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="CLIntroViewController">
<connections>
<outlet property="onboardingImageView" destination="qZ4-qB-r3O" id="5cu-wZ-y8M"/>
<outlet property="customView" destination="rjF-xt-RiU" id="U5q-Ud-5JD"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="485" height="520"/>
<rect key="frame" x="0.0" y="0.0" width="485" height="420"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<visualEffectView wantsLayer="YES" alphaValue="0.80000000000000004" blendingMode="behindWindow" state="followsWindowActiveState" translatesAutoresizingMaskIntoConstraints="NO" id="G8h-RB-gyd">
<rect key="frame" x="0.0" y="-10" width="485" height="530"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="qZ4-qB-r3O">
<rect key="frame" x="0.0" y="60" width="485" height="479"/>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1DU-NA-5N0">
<rect key="frame" x="14" y="193" width="81" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="479" id="QkO-Un-33O"/>
<constraint firstAttribute="width" constant="485" id="Ymc-PM-QEC"/>
<constraint firstAttribute="width" constant="69" id="EqC-1t-ZIv"/>
<constraint firstAttribute="height" constant="21" id="pwL-hr-muf"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="Onboarding" id="Rvj-vz-qz1"/>
</imageView>
</subviews>
<buttonCell key="cell" type="push" title="Left" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="lf3-xl-YrG">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="leftAction:" target="-2" id="wRC-2w-a5l"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="dJl-QF-kJE">
<rect key="frame" x="390" y="193" width="81" height="32"/>
<constraints>
<constraint firstItem="qZ4-qB-r3O" firstAttribute="top" secondItem="G8h-RB-gyd" secondAttribute="top" constant="-9" id="DK4-8b-YaJ"/>
<constraint firstItem="qZ4-qB-r3O" firstAttribute="leading" secondItem="G8h-RB-gyd" secondAttribute="leading" id="WFY-ka-uhT"/>
<constraint firstAttribute="trailing" secondItem="qZ4-qB-r3O" secondAttribute="trailing" id="jid-yl-vki"/>
<constraint firstAttribute="height" constant="21" id="NOu-jQ-oVL"/>
<constraint firstAttribute="width" constant="69" id="xF1-9q-RgM"/>
</constraints>
<shadow key="shadow">
<color key="color" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</shadow>
</visualEffectView>
<button focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="sgW-1g-MOH">
<buttonCell key="cell" type="push" title="Right" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="S2e-yL-pup">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="rightAction:" target="-2" id="n1w-Lo-4cT"/>
</connections>
</button>
<button focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="sgW-1g-MOH" customClass="CLScaleUpButton">
<rect key="frame" x="186" y="13" width="114" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="d55-vu-duj"/>
@ -59,19 +66,25 @@ DQ
<action selector="continueOnboarding:" target="-2" id="VxO-5e-FH6"/>
</connections>
</button>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="rjF-xt-RiU" customClass="CLAnimatedImages">
<rect key="frame" x="102" y="160" width="280" height="240"/>
<constraints>
<constraint firstAttribute="width" constant="280" id="Vyp-yW-I0s"/>
<constraint firstAttribute="height" constant="240" id="YxH-Fh-3L2"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="dJl-QF-kJE" secondAttribute="trailing" constant="20" id="2mU-bT-BSB"/>
<constraint firstItem="1DU-NA-5N0" firstAttribute="centerY" secondItem="Hz6-mo-xeY" secondAttribute="centerY" id="Bnu-eZ-Oo7"/>
<constraint firstItem="rjF-xt-RiU" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" id="Mqz-PA-JYI"/>
<constraint firstItem="sgW-1g-MOH" firstAttribute="centerX" secondItem="Hz6-mo-xeY" secondAttribute="centerX" id="OlA-UF-19Y"/>
<constraint firstAttribute="bottom" secondItem="G8h-RB-gyd" secondAttribute="bottom" constant="-10" id="Sme-p8-MK1"/>
<constraint firstItem="G8h-RB-gyd" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="Ugy-Fp-utH"/>
<constraint firstItem="dJl-QF-kJE" firstAttribute="centerY" secondItem="Hz6-mo-xeY" secondAttribute="centerY" id="Tua-SU-scv"/>
<constraint firstAttribute="bottom" secondItem="sgW-1g-MOH" secondAttribute="bottom" constant="20" id="Zuy-ve-Ywq"/>
<constraint firstItem="G8h-RB-gyd" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="bYK-JY-bx6"/>
<constraint firstAttribute="trailing" secondItem="G8h-RB-gyd" secondAttribute="trailing" id="tS5-KQ-4aS"/>
<constraint firstItem="1DU-NA-5N0" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" id="aOO-sG-v9l"/>
<constraint firstItem="rjF-xt-RiU" firstAttribute="centerX" secondItem="Hz6-mo-xeY" secondAttribute="centerX" id="dYe-2i-tiR"/>
</constraints>
<point key="canvasLocation" x="185.5" y="348"/>
<point key="canvasLocation" x="172.5" y="347"/>
</customView>
</objects>
<resources>
<image name="Onboarding" width="916" height="794"/>
</resources>
</document>

31
Clocker/Onboarding/CLIntroViewController.m

@ -9,10 +9,12 @@
#import "CLIntroViewController.h"
#import <QuartzCore/QuartzCore.h>
#import "ApplicationDelegate.h"
#import <pop/POP.h>
#import "CLAnimatedImages.h"
@interface CLIntroViewController ()
@property (weak) IBOutlet NSImageView *onboardingImageView;
@property (weak) IBOutlet CLAnimatedImages *customView;
@end
@ -30,10 +32,13 @@
[self.view setLayer:viewLayer];
self.view.window.styleMask = NSFullSizeContentViewWindowMask;
[self.customView addUntitled1Animation];
}
- (IBAction)continueOnboarding:(NSButton *)sender
{
if ([sender.title isEqualToString:@"Get Started"])
{
[self.view.window close];
@ -42,16 +47,28 @@
return;
}
self.onboardingImageView.image = [NSImage imageNamed:@"FinalOnboarding"];
[sender setTitle:@"Get Started"];
CALayer *layer = self.onboardingImageView.layer;
[layer pop_removeAllAnimations];
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionY];
anim.fromValue = @(300);
anim.toValue = @(100);
anim.springBounciness = 20.0f;
CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
transition.type = kCATransitionMoveIn;
[self.view setWantsLayer:YES];
[layer pop_addAnimation:anim forKey:@"size"];
[self.onboardingImageView.layer addAnimation:transition forKey:nil];
}
- (IBAction)leftAction:(id)sender
{
[self.customView addUntitled1Animation];
}
- (IBAction)rightAction:(id)sender
{
}

16
Clocker/Onboarding/CLOnboardingWindowController.m

@ -8,8 +8,11 @@
#import "CLOnboardingWindowController.h"
#import <QuartzCore/QuartzCore.h>
#import <pop/POP.h>
@interface CLOnboardingWindowController ()
@property (weak) IBOutlet NSTextField *titleLabel;
@property (weak) IBOutlet NSButton *continueButtonOutlet;
@property (strong, nonatomic) CLIntroViewController *introViewController;
@ -22,15 +25,18 @@ static CLOnboardingWindowController *sharedOnboardingWindow;
- (void)windowDidLoad {
[super windowDidLoad];
self.window.backgroundColor = [NSColor whiteColor];
self.window.titleVisibility = NSWindowTitleHidden;
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
POPSpringAnimation *shake = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionX];
shake.springBounciness = 35;
shake.velocity = @(1000);
[self.titleLabel.layer pop_addAnimation:shake forKey:@"shakePassword"];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
+ (instancetype)sharedWindow
{
@ -48,14 +54,10 @@ static CLOnboardingWindowController *sharedOnboardingWindow;
- (IBAction)continueButtonPressed:(id)sender
{
self.introViewController = [[CLIntroViewController alloc] initWithNibName:@"CLIntroView" bundle:nil];
[[self.window animator] setContentSize:self.introViewController.view.frame.size];
[[self.window animator] setContentView:self.introViewController.view];
CGFloat xPos = NSWidth([[self.window screen] frame])/2 - NSWidth([self.window frame])/2;
CGFloat yPos = NSHeight([[self.window screen] frame])/2 - NSHeight([self.window frame])/2;
[self.window setFrame:NSMakeRect(xPos, yPos, NSWidth([self.window frame]), NSHeight([self.window frame])) display:YES];
}

38
Clocker/Onboarding/en.lproj/CLOnboardingWindow.xib

@ -6,6 +6,8 @@
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="CLOnboardingWindowController">
<connections>
<outlet property="continueButtonOutlet" destination="MQa-AK-s2j" id="XDy-Vq-a5q"/>
<outlet property="titleLabel" destination="oiI-iN-JcW" id="9hX-7l-wpk"/>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
</connections>
</customObject>
@ -13,33 +15,35 @@
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<rect key="contentRect" x="196" y="240" width="275" height="233"/>
<rect key="contentRect" x="196" y="240" width="538" height="420"/>
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="777"/>
<value key="minSize" type="size" width="538" height="420"/>
<value key="maxSize" type="size" width="538" height="420"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="275" height="233"/>
<rect key="frame" x="0.0" y="0.0" width="538" height="420"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TaQ-Ln-Vip">
<rect key="frame" x="114" y="155" width="48" height="48"/>
<rect key="frame" x="169" y="190" width="200" height="200"/>
<constraints>
<constraint firstAttribute="width" constant="48" id="Ll6-ju-UBQ"/>
<constraint firstAttribute="height" constant="48" id="kpd-df-Kmk"/>
<constraint firstAttribute="width" constant="200" id="Ll6-ju-UBQ"/>
<constraint firstAttribute="height" constant="200" id="kpd-df-Kmk"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="ClockerIcon-256" id="2t2-AF-Gtf"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="ClockerIcon-512" id="2t2-AF-Gtf"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="oiI-iN-JcW">
<rect key="frame" x="18" y="120" width="239" height="30"/>
<rect key="frame" x="18" y="125" width="502" height="60"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="C7v-6N-7K9"/>
<constraint firstAttribute="height" constant="60" id="C7v-6N-7K9"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Clocker" id="r8V-tn-VkN">
<font key="font" size="20" name="SFUIDisplay-Bold"/>
<font key="font" size="35" name="SFUIDisplay-Bold"/>
<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="oyE-6j-Mni">
<rect key="frame" x="18" y="11" width="239" height="17"/>
<rect key="frame" x="18" y="11" width="502" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="Ttg-Xe-RUI"/>
</constraints>
@ -49,11 +53,11 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MQa-AK-s2j">
<rect key="frame" x="81" y="27" width="114" height="32"/>
<button focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MQa-AK-s2j" customClass="CLScaleUpButton">
<rect key="frame" x="212" y="27" width="114" height="36"/>
<constraints>
<constraint firstAttribute="width" constant="102" id="17K-x2-WJw"/>
<constraint firstAttribute="height" constant="21" id="uWT-Rz-CCE"/>
<constraint firstAttribute="height" constant="25" id="uWT-Rz-CCE"/>
</constraints>
<buttonCell key="cell" type="push" title="Continue" bezelStyle="rounded" alignment="center" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="TjC-Ot-oen">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -72,9 +76,9 @@ DQ
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wod-xv-dtj">
<rect key="frame" x="18" y="99" width="239" height="19"/>
<rect key="frame" x="18" y="99" width="502" height="24"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Your timezone manager!" id="hQe-Z5-uca">
<font key="font" size="13" name="SFUIDisplay-Light"/>
<font key="font" size="16" name="SFUIDisplay-Light"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
@ -101,10 +105,10 @@ DQ
<connections>
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
</connections>
<point key="canvasLocation" x="295.5" y="171.5"/>
<point key="canvasLocation" x="300" y="133"/>
</window>
</objects>
<resources>
<image name="ClockerIcon-256" width="256" height="256"/>
<image name="ClockerIcon-512" width="512" height="512"/>
</resources>
</document>

25
Clocker/PanelController.m

@ -283,6 +283,8 @@ static PanelController *sharedPanel = nil;
CLTimezoneData *dataObject = [CLTimezoneData getCustomObject:self.defaultPreferences[row]];
cell.sunriseSetTime.stringValue = [dataObject getFormattedSunriseOrSunsetTime];
NSTextView *customLabel = (NSTextView*)[cell.relativeDate.window
fieldEditor:YES
forObject:cell.relativeDate];
@ -296,6 +298,8 @@ static PanelController *sharedPanel = nil;
[cell.customName setDrawsBackground:YES];
[cell.customName setBackgroundColor:[NSColor blackColor]];
customLabel.insertionPointColor = [NSColor whiteColor];
cell.sunriseSetImage.image = dataObject.sunriseOrSunset ?
[NSImage imageNamed:@"White Sunrise"] : [NSImage imageNamed:@"White Sunset"];
}
else
{
@ -305,9 +309,12 @@ static PanelController *sharedPanel = nil;
[self.mainTableview setBackgroundColor:[NSColor whiteColor]];
self.window.alphaValue = 1;
customLabel.insertionPointColor = [NSColor blackColor];
cell.sunriseSetImage.image = dataObject.sunriseOrSunset ?
[NSImage imageNamed:@"Sunrise"] : [NSImage imageNamed:@"Sunset"];
}
cell.relativeDate.stringValue = [dataObject getDateForTimeZoneWithFutureSliderValue:self.futureSliderValue andDisplayType:CLPanelDisplay];
cell.relativeDate.stringValue = [dataObject
getDateForTimeZoneWithFutureSliderValue:self.futureSliderValue andDisplayType:CLPanelDisplay];
cell.time.stringValue = [dataObject getTimeForTimeZoneWithFutureSliderValue:self.futureSliderValue];
@ -316,14 +323,14 @@ static PanelController *sharedPanel = nil;
cell.customName.stringValue = [dataObject formatStringShouldContainCity:YES];
NSNumber *displayFutureSlider = [[NSUserDefaults standardUserDefaults] objectForKey:CLDisplayFutureSliderKey];
if ([displayFutureSlider isEqualToNumber:[NSNumber numberWithInteger:1]])
{
self.futureSlider.hidden = YES;
}
else
{
self.futureSlider.hidden = NO;
}
self.futureSlider.hidden = [displayFutureSlider isEqualToNumber:[NSNumber numberWithInteger:1]] ? YES : NO;
NSNumber *displaySunriseSunsetTime = [[NSUserDefaults standardUserDefaults] objectForKey:CLSunriseSunsetTime];
cell.sunriseSetTime.hidden = [displaySunriseSunsetTime isEqualToNumber:@(1)] ? YES : NO;
cell.sunriseSetImage.hidden = [displaySunriseSunsetTime isEqualToNumber:@(1)] ? YES : NO;
[cell setUpAutoLayoutWithCell:cell];

5
Clocker/Preferences/CLPreferencesViewController.h

@ -7,13 +7,16 @@
//
#import <Cocoa/Cocoa.h>
#import <ShortcutRecorder/ShortcutRecorder.h>
#import <PTHotKey/PTHotKeyCenter.h>
#import <PTHotKey/PTHotKey+ShortcutRecorder.h>
typedef enum : NSUInteger {
CLDefaultTheme,
CLBlackTheme
} CLTheme;
@interface CLPreferencesViewController : NSViewController
@interface CLPreferencesViewController : NSViewController<SRRecorderControlDelegate>

64
Clocker/Preferences/CLPreferencesViewController.m

@ -14,9 +14,10 @@
#import "CommonStrings.h"
#import "CLTimezoneData.h"
#import "CLAPI.h"
//#import <Answers/Answers.h>
#import "EDSunriseSet.h"
#import <ServiceManagement/ServiceManagement.h>
NSString *const CLSearchPredicateKey = @"SELF CONTAINS[cd]%@";
NSString *const CLPreferencesViewNibIdentifier = @"PreferencesWindow";
NSString *const CLPreferencesTimezoneNameIdentifier = @"formattedAddress";
@ -45,6 +46,7 @@ NSString *const CLTryAgainMessage = @"Try again, maybe?";
@property (nonatomic, copy) NSString *columnName;
@property (atomic, copy) NSArray *themes;
@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
@property (weak) IBOutlet SRRecorderControl *recorderControl;
@property (weak) IBOutlet NSTableView *timezoneTableView;
@property (strong) IBOutlet Panel *timezonePanel;
@ -88,8 +90,60 @@ NSString *const CLTryAgainMessage = @"Try again, maybe?";
self.columnName = @"Place(s)";
// Do view setup here.
NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
self.recorderControl.delegate = self;
[self.recorderControl bind:NSValueBinding
toObject:defaults
withKeyPath:@"values.globalPing"
options:nil];
[defaults addObserver:self forKeyPath:@"values.globalPing" options:NSKeyValueObservingOptionInitial context:NULL];
}
/*
- (void)initializeHotkeySequence
{
PTHotKeyCenter *hotKeyCenter = [PTHotKeyCenter sharedCenter];
PTHotKey *oldHotKey = [hotKeyCenter hotKeyWithIdentifier:aKeyPath];
[hotKeyCenter unregisterHotKey:oldHotKey];
PTHotKey *newHotKey = [PTHotKey hotKeyWithIdentifier:aKeyPath
keyCombo:newShortcut
target:self
action:@selector(ping:)];
[hotKeyCenter registerHotKey:newHotKey];
}*/
-(void)observeValueForKeyPath:(NSString *)aKeyPath ofObject:(id)anObject change:(NSDictionary<NSString *,id> *)aChange context:(void *)aContext
{
if ([aKeyPath isEqualToString:@"values.globalPing"])
{
PTHotKeyCenter *hotKeyCenter = [PTHotKeyCenter sharedCenter];
PTHotKey *oldHotKey = [hotKeyCenter hotKeyWithIdentifier:aKeyPath];
[hotKeyCenter unregisterHotKey:oldHotKey];
NSDictionary *newShortcut = [anObject valueForKeyPath:aKeyPath];
if (newShortcut && (NSNull *)newShortcut != [NSNull null])
{
PTHotKey *newHotKey = [PTHotKey hotKeyWithIdentifier:aKeyPath
keyCombo:newShortcut
target:self
action:@selector(ping:)];
[hotKeyCenter registerHotKey:newHotKey];
}
}
else
[super observeValueForKeyPath:aKeyPath ofObject:anObject change:aChange context:aContext];
}
-(IBAction)ping:(id)sender
{
ApplicationDelegate *delegate = (ApplicationDelegate *)[[NSApplication sharedApplication] delegate];
[delegate togglePanel:nil];
}
-(void)dealloc
{
@ -738,7 +792,8 @@ NSString *const CLTryAgainMessage = @"Try again, maybe?";
CLTimezoneData *dataObject = self.filteredArray[self.availableTimezoneTableView.selectedRow];
[dataObject sendAnalyticsData];
/*Strip till the first comma we encounter*/
NSString *filteredAddress = dataObject.formattedAddress;
@ -755,11 +810,12 @@ NSString *const CLTryAgainMessage = @"Try again, maybe?";
[newTimezone setObject:filteredAddress forKey:CLTimezoneName];
[newTimezone setObject:dataObject.place_id forKey:CLPlaceIdentifier];
[newTimezone setObject:latitude forKey:@"latitude"];
[newTimezone setObject:longitude forKey:@"longitude"];
[newTimezone setObject:dataObject.latitude forKey:@"latitude"];
[newTimezone setObject:dataObject.longitude forKey:@"longitude"];
[newTimezone setObject:CLEmptyString forKey:@"nextUpdate"];
[newTimezone setObject:CLEmptyString forKey:CLCustomLabel];
CLTimezoneData *timezoneObject = [[CLTimezoneData alloc] initWithDictionary:newTimezone];
NSArray *defaultPreference = [[NSUserDefaults standardUserDefaults] objectForKey:CLDefaultPreferenceKey];

39
Clocker/Preferences/en.lproj/CLPreferencesView.xib

@ -10,6 +10,7 @@
<outlet property="availableTimezoneTableView" destination="Q0t-hQ-orw" id="vQv-rd-Wkv"/>
<outlet property="messageLabel" destination="KFC-NV-5A3" id="NKB-JY-Udb"/>
<outlet property="placeholderLabel" destination="L5U-OI-Tkv" id="NhA-YA-x7S"/>
<outlet property="recorderControl" destination="DuQ-3m-l0n" id="lJH-Sc-bMi"/>
<outlet property="searchCriteria" destination="MiN-SF-nnU" id="Osf-q8-wwG"/>
<outlet property="searchField" destination="biT-6m-ElR" id="Di3-QU-LGY"/>
<outlet property="timezonePanel" destination="6FL-fp-Ke1" id="SDq-Q4-hMb"/>
@ -20,11 +21,11 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<view id="Uu9-io-frR">
<rect key="frame" x="0.0" y="0.0" width="439" height="335"/>
<rect key="frame" x="0.0" y="0.0" width="439" height="344"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button toolTip="Add a timezone" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="4yB-vZ-tNX">
<rect key="frame" x="11" y="19" width="21" height="22"/>
<rect key="frame" x="11" y="24" width="21" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="GNz-C9-Ay8"/>
<constraint firstAttribute="width" constant="21" id="OkY-Uq-PwX"/>
@ -38,7 +39,7 @@
</connections>
</button>
<button toolTip="Remove a timezone" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iOG-Ey-lmD">
<rect key="frame" x="32" y="19" width="21" height="22"/>
<rect key="frame" x="32" y="24" width="21" height="22"/>
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="gLH-wy-bCE">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -51,13 +52,13 @@ CA
</connections>
</button>
<scrollView focusRingType="none" borderType="none" autohidesScrollers="YES" horizontalLineScroll="22" horizontalPageScroll="10" verticalLineScroll="22" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zBR-OH-6QQ">
<rect key="frame" x="10" y="46" width="419" height="281"/>
<rect key="frame" x="10" y="66" width="419" height="270"/>
<clipView key="contentView" id="UZ2-JA-TZe">
<rect key="frame" x="0.0" y="0.0" width="419" height="281"/>
<rect key="frame" x="0.0" y="0.0" width="419" height="270"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnSelection="YES" autosaveColumns="NO" rowHeight="20" headerView="igm-uc-1wh" id="LbJ-dW-ITm">
<rect key="frame" x="0.0" y="0.0" width="419" height="258"/>
<rect key="frame" x="0.0" y="0.0" width="419" height="247"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -111,7 +112,7 @@ CA
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</clipView>
<constraints>
<constraint firstAttribute="height" constant="281" id="PZN-nD-VFx"/>
<constraint firstAttribute="height" constant="270" id="PZN-nD-VFx"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="QrG-bP-Ras">
<rect key="frame" x="0.0" y="266" width="419" height="15"/>
@ -127,9 +128,9 @@ CA
</tableHeaderView>
</scrollView>
<button translatesAutoresizingMaskIntoConstraints="NO" id="HMC-Ku-qrH">
<rect key="frame" x="59" y="21" width="265" height="18"/>
<rect key="frame" x="59" y="26" width="184" height="18"/>
<constraints>
<constraint firstAttribute="width" constant="261" id="5ET-GR-cI7"/>
<constraint firstAttribute="width" constant="180" id="5ET-GR-cI7"/>
<constraint firstAttribute="height" constant="14" id="Hfw-03-t8F"/>
</constraints>
<buttonCell key="cell" type="check" title="Start Clocker at Login" bezelStyle="regularSquare" imagePosition="left" inset="2" id="6ag-Bx-bSv">
@ -141,21 +142,33 @@ CA
<binding destination="1Gq-ZQ-IML" name="value" keyPath="values.startAtLogin" id="UjN-PC-pxC"/>
</connections>
</button>
<customView focusRingType="none" appearanceType="aqua" translatesAutoresizingMaskIntoConstraints="NO" id="DuQ-3m-l0n" customClass="SRRecorderControl">
<rect key="frame" x="249" y="22" width="180" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="180" id="aut-wW-20E"/>
<constraint firstAttribute="height" constant="25" id="es4-pH-3Rc"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="enabled" value="YES"/>
</userDefinedRuntimeAttributes>
</customView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="DuQ-3m-l0n" secondAttribute="trailing" constant="10" id="15u-tf-62J"/>
<constraint firstAttribute="bottom" secondItem="HMC-Ku-qrH" secondAttribute="bottom" constant="28" id="7tI-Ff-GHJ"/>
<constraint firstItem="iOG-Ey-lmD" firstAttribute="height" secondItem="4yB-vZ-tNX" secondAttribute="height" id="HKt-is-5y3"/>
<constraint firstItem="zBR-OH-6QQ" firstAttribute="top" secondItem="Uu9-io-frR" secondAttribute="top" constant="8" id="JKn-gF-8oI"/>
<constraint firstAttribute="bottom" secondItem="iOG-Ey-lmD" secondAttribute="bottom" constant="20" id="LkE-TY-4pP"/>
<constraint firstItem="HMC-Ku-qrH" firstAttribute="leading" secondItem="iOG-Ey-lmD" secondAttribute="trailing" constant="8" id="RAb-Xi-AY4"/>
<constraint firstAttribute="bottom" secondItem="HMC-Ku-qrH" secondAttribute="bottom" constant="23" id="j8p-GM-QPX"/>
<constraint firstAttribute="bottom" secondItem="4yB-vZ-tNX" secondAttribute="bottom" constant="25" id="Zyb-ya-88h"/>
<constraint firstAttribute="bottom" secondItem="iOG-Ey-lmD" secondAttribute="bottom" constant="25" id="cZh-fI-Lio"/>
<constraint firstAttribute="trailing" secondItem="zBR-OH-6QQ" secondAttribute="trailing" constant="10" id="p1P-Ev-oBI"/>
<constraint firstAttribute="bottom" secondItem="DuQ-3m-l0n" secondAttribute="bottom" constant="22" id="vzh-s2-a5z"/>
<constraint firstItem="iOG-Ey-lmD" firstAttribute="width" secondItem="4yB-vZ-tNX" secondAttribute="width" id="wLJ-lQ-GhP"/>
<constraint firstItem="iOG-Ey-lmD" firstAttribute="leading" secondItem="4yB-vZ-tNX" secondAttribute="trailing" id="xu0-0C-2pe"/>
<constraint firstItem="4yB-vZ-tNX" firstAttribute="leading" secondItem="Uu9-io-frR" secondAttribute="leading" constant="11" id="zgB-PO-97r"/>
<constraint firstItem="zBR-OH-6QQ" firstAttribute="leading" secondItem="Uu9-io-frR" secondAttribute="leading" constant="10" id="zoH-62-nam"/>
<constraint firstAttribute="bottom" secondItem="4yB-vZ-tNX" secondAttribute="bottom" constant="20" id="zvP-zK-Hxe"/>
</constraints>
<point key="canvasLocation" x="295.5" y="173.5"/>
<point key="canvasLocation" x="295.5" y="178"/>
</view>
<userDefaultsController representsSharedInstance="YES" id="1Gq-ZQ-IML"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hasShadow="NO" hidesOnDeactivate="YES" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="alertPanel" appearanceType="aqua" frameAutosaveName="" id="6FL-fp-Ke1" customClass="Panel">

51
Clocker/QCMethod.h

@ -0,0 +1,51 @@
//
// QCMethod.h
//
// Version 1.2
//
// www.quartzcodeapp.com
//
#import "TargetConditionals.h"
#import <QuartzCore/QuartzCore.h>
#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE)
#import <UIKit/UIKit.h>
#else
#import <Cocoa/Cocoa.h>
#endif
@interface QCMethod : NSObject
+ (CAAnimation*)reverseAnimation:(CAAnimation*)anim totalDuration:(CGFloat)totalDuration;
+ (CAAnimationGroup*)groupAnimations:(NSArray*)animations fillMode:(NSString*)fillMode forEffectLayer:(BOOL)forEffectLayer sublayersCount:(NSInteger)count;
+ (CAAnimationGroup*)groupAnimations:(NSArray*)animations fillMode:(NSString*)fillMode;
+ (CGFloat)maxDurationFromAnimations:(NSArray*)anims;
+ (CGFloat)maxDurationOfEffectAnimation:(CAAnimationGroup*)anim sublayersCount:(NSInteger)count;
+ (void)updateValueFromAnimationsForLayers:(NSArray*)layers;
+ (void)updateValueForAnimation:(CAAnimation*)anim theLayer:(CALayer *)layer;
+ (void)updateValueFromPresentationLayerForAnimation:(CAAnimation*)anim theLayer:(CALayer *)layer;
+ (void)addSublayersAnimation:(CAAnimation*)anim forKey:(NSString*)key forLayer:(CALayer*)layer;
+ (void)addSublayersAnimationNeedReverse:(CAAnimation*)anim forKey:(NSString*)key forLayer:(CALayer*)layer reverseAnimation:(BOOL)reverse totalDuration:(CGFloat)totalDuration;
#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE)
+ (UIBezierPath*)alignToBottomPath:(UIBezierPath*)path layer:(CALayer*)layer;
+ (UIBezierPath*)offsetPath:(UIBezierPath*)path by:(CGPoint)offset;
#else
+ (NSBezierPath*)offsetPath:(NSBezierPath*)path by:(CGPoint)offset;
#endif
@end
#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE)
#else
@interface NSBezierPath (Path)
- (CGPathRef)quartzPath;
@end
@interface NSImage (cgImage)
-(CGImageRef)cgImage;
@end
#endif

346
Clocker/QCMethod.m

@ -0,0 +1,346 @@
//
// QCMethod.m
//
// www.quartzcodeapp.com
//
#import "QCMethod.h"
@implementation QCMethod
+ (CAAnimation*)reverseAnimation:(CAAnimation*)anim totalDuration:(CGFloat)totalDuration{
CGFloat duration = anim.duration + (anim.autoreverses ? anim.duration : 0);
duration = anim.repeatCount > 1 ? duration * anim.repeatCount : duration;
CGFloat endTime = anim.beginTime + duration;
CGFloat reverseStartTime = totalDuration - endTime;
CAAnimation *newAnim;
//Reverse timing function
void (^reverseTimingFunction)(CAAnimation*) = ^(CAAnimation *theAnim){
CAMediaTimingFunction *timingFunction = theAnim.timingFunction;
if (timingFunction) {
float first[2];
float second[2];
[timingFunction getControlPointAtIndex:1 values:first];
[timingFunction getControlPointAtIndex:2 values:second];
theAnim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:1-second[0] :1-second[1] :1-first[0] :1-first[1]];
}
};
//Reverse animation values appropriately
if ([anim isKindOfClass:[CABasicAnimation class]]) {
CABasicAnimation *basicAnim = (CABasicAnimation*)anim;
if (!anim.autoreverses) {
id fromValue = basicAnim.toValue;
basicAnim.toValue = basicAnim.fromValue;
basicAnim.fromValue = fromValue;
reverseTimingFunction(basicAnim);
}
basicAnim.beginTime = reverseStartTime;
if (reverseStartTime > 0) {
CAAnimationGroup *groupAnim = [CAAnimationGroup animation];
groupAnim.animations = @[basicAnim];
groupAnim.duration = [self maxDurationFromAnimations:groupAnim.animations];
[groupAnim.animations setValue:kCAFillModeBoth forKeyPath:@"fillMode"];
newAnim = groupAnim;
}else newAnim = basicAnim;
}
else if ([anim isKindOfClass:[CAKeyframeAnimation class]]) {
CAKeyframeAnimation *keyAnim = (CAKeyframeAnimation*)anim;
if (!anim.autoreverses) {
NSArray *values = [[keyAnim.values reverseObjectEnumerator] allObjects];
keyAnim.values = values;
reverseTimingFunction(keyAnim);
}
keyAnim.beginTime = reverseStartTime;
if (reverseStartTime > 0) {
CAAnimationGroup *groupAnim = [CAAnimationGroup animation];
groupAnim.animations = @[keyAnim];
groupAnim.duration = [self maxDurationFromAnimations:groupAnim.animations];
[groupAnim.animations setValue:kCAFillModeBoth forKeyPath:@"fillMode"];
newAnim = groupAnim;
}else newAnim = keyAnim;
}
else if ([anim isKindOfClass:[CAAnimationGroup class]]) {
CAAnimationGroup *groupAnim = (CAAnimationGroup*)anim;
NSMutableArray *newSubAnims = [NSMutableArray arrayWithCapacity:groupAnim.animations.count];
for (CAAnimation *subAnim in groupAnim.animations) {
CAAnimation *newSubAnim = [self reverseAnimation:subAnim totalDuration:totalDuration];
[newSubAnims addObject:newSubAnim];
}
groupAnim.animations = newSubAnims;
[groupAnim.animations setValue:kCAFillModeBoth forKeyPath:@"fillMode"];
groupAnim.duration = [self maxDurationFromAnimations:newSubAnims];
newAnim = groupAnim;
}else newAnim = anim;
return newAnim;
}
+ (CAAnimationGroup*)groupAnimations:(NSArray*)animations fillMode:(NSString*)fillMode forEffectLayer:(BOOL)forEffectLayer sublayersCount:(NSInteger)count{
CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
groupAnimation.animations = animations;
if (fillMode) {
[groupAnimation.animations setValue:fillMode forKeyPath:@"fillMode"];
groupAnimation.fillMode = fillMode;
groupAnimation.removedOnCompletion = NO;
}
if (forEffectLayer) {
groupAnimation.duration = [QCMethod maxDurationOfEffectAnimation:groupAnimation sublayersCount:count];
}else{
groupAnimation.duration = [QCMethod maxDurationFromAnimations:animations];
}
return groupAnimation;
}
+ (CAAnimationGroup*)groupAnimations:(NSArray*)animations fillMode:(NSString*)fillMode{
return [self groupAnimations:animations fillMode:fillMode forEffectLayer:NO sublayersCount:0];
}
+ (CGFloat)maxDurationFromAnimations:(NSArray*)anims{
CGFloat maxDuration = 0;
for (CAAnimation *anim in anims) {
maxDuration = MAX(anim.beginTime + anim.duration * (CGFloat)(anim.repeatCount == 0 ? 1.0f : anim.repeatCount) * (anim.autoreverses ? 2.0f : 1.0f), maxDuration);
}
if (maxDuration == INFINITY) {
maxDuration = 1000.0f;
}
return maxDuration;
}
+ (CGFloat)maxDurationOfEffectAnimation:(CAAnimationGroup*)anim sublayersCount:(NSInteger)count{
CGFloat maxDuration = 0;
if ([anim isKindOfClass:[CAAnimationGroup class]]) {
for (CABasicAnimation *subAnim in anim.animations) {
CGFloat instanceDelay = [[subAnim valueForKey:@"instanceDelay"] floatValue];
CGFloat delay = instanceDelay * (CGFloat)(count - 1);
CGFloat repeatCountDuration = 0;
if (subAnim.repeatCount >1) {
repeatCountDuration = (subAnim.duration * (subAnim.repeatCount-1));
}
CGFloat duration = subAnim.beginTime + (subAnim.autoreverses ? subAnim.duration : 0) + (delay + subAnim.duration + repeatCountDuration);
maxDuration = MAX(duration, maxDuration);
}
}
if (maxDuration == INFINITY) {
maxDuration = 1000.0f;
}
return maxDuration;
}
+ (void)updateValueFromAnimationsForLayers:(NSArray*)layers{
[CATransaction begin];
[CATransaction setDisableActions:YES];
for (CALayer *layer in layers) {
for (NSString *animKey in layer.animationKeys) {
CAAnimation *anim = [layer animationForKey:animKey];
[self updateValueForAnimation:anim theLayer:layer];
}
}
[CATransaction commit];
}
+ (void)updateValueForAnimation:(CAAnimation*)anim theLayer:(CALayer *)layer{
if ([anim isKindOfClass:[CABasicAnimation class]]) {
CABasicAnimation *basicAnim = (CABasicAnimation*)anim;
if (!basicAnim.autoreverses) {
[layer setValue:basicAnim.toValue forKeyPath:basicAnim.keyPath];
}
}
else if ([anim isKindOfClass:[CAKeyframeAnimation class]]) {
CAKeyframeAnimation *keyAnim = (CAKeyframeAnimation*)anim;
if (!anim.autoreverses) {
[layer setValue:keyAnim.values.lastObject forKeyPath:keyAnim.keyPath];
}
}
else if ([anim isKindOfClass:[CAAnimationGroup class]]) {
CAAnimationGroup *groupAnim = (CAAnimationGroup*)anim;
for (CAAnimation *subAnim in groupAnim.animations) {
[self updateValueForAnimation:subAnim theLayer:layer];
}
}
}
+ (void)updateValueFromPresentationLayerForAnimation:(CAAnimation*)anim theLayer:(CALayer *)layer{
if ([anim isKindOfClass:[CABasicAnimation class]] || [anim isKindOfClass:[CAKeyframeAnimation class]]) {
CABasicAnimation *basicAnim = (CABasicAnimation*)anim;
[layer setValue:[layer.presentationLayer valueForKeyPath:basicAnim.keyPath] forKeyPath:basicAnim.keyPath];
}
else if ([anim isKindOfClass:[CAAnimationGroup class]]) {
CAAnimationGroup *groupAnim = (CAAnimationGroup*)anim;
for (CAAnimation *subAnim in groupAnim.animations) {
[self updateValueFromPresentationLayerForAnimation:subAnim theLayer:layer];
}
}
}
+ (void)addSublayersAnimation:(CAAnimation*)anim forKey:(NSString*)key forLayer:(CALayer*)layer{
[self addSublayersAnimationNeedReverse:anim forKey:key forLayer:layer reverseAnimation:NO totalDuration:0];
}
//!Add animation to each sublayer in effect layer
+ (void)addSublayersAnimationNeedReverse:(CAAnimation*)anim forKey:(NSString*)key forLayer:(CALayer*)layer reverseAnimation:(BOOL)reverse totalDuration:(CGFloat)totalDuration{
NSArray *sublayers = layer.sublayers;
NSInteger sublayersCount = sublayers.count;
void (^setBeginTime)(CAAnimation*, NSInteger) = ^(CAAnimation *subAnim, NSInteger sublayerIdx){
CGFloat instanceDelay = [[subAnim valueForKey:@"instanceDelay"] floatValue];
NSInteger orderType = [[subAnim valueForKey:@"instanceOrder"] integerValue];
switch (orderType) {
case 0: subAnim.beginTime += sublayerIdx * instanceDelay; break;
case 1: subAnim.beginTime += (sublayersCount - sublayerIdx - 1) * instanceDelay; break;
case 2: {
CGFloat middleIdx = sublayersCount/2.0f;
CGFloat begin = fabs((middleIdx - sublayerIdx)) * instanceDelay ;
subAnim.beginTime += begin; break;
}
case 3: {
CGFloat middleIdx = sublayersCount/2.0f;
CGFloat begin = (middleIdx - fabs((middleIdx - sublayerIdx))) * instanceDelay ;
subAnim.beginTime += begin; break;
}
case 4: {
//Add yours here
}
default:
break;
}
};
[sublayers enumerateObjectsWithOptions:0 usingBlock:^(CALayer *sublayer, NSUInteger idx, BOOL *stop) {
if ([anim isKindOfClass:[CAAnimationGroup class]]) {
CAAnimationGroup *groupAnim = (CAAnimationGroup*)anim.copy;
NSMutableArray *newSubAnimations = [NSMutableArray arrayWithCapacity:groupAnim.animations.count];
for (CABasicAnimation *subAnim in groupAnim.animations) {
[newSubAnimations addObject:subAnim.copy];
}
groupAnim.animations = newSubAnimations;
NSArray *animations = [(CAAnimationGroup*)groupAnim animations];
for (CABasicAnimation *sub in animations) {
setBeginTime(sub, idx);
//Reverse animation if needed
if (reverse) [self reverseAnimation:sub totalDuration:totalDuration];
}
[sublayer addAnimation:groupAnim forKey:key];
}
else{
CABasicAnimation *copiedAnim = anim.copy;
setBeginTime(copiedAnim, idx);
[sublayer addAnimation:copiedAnim forKey:key];
}
}];
}
#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE)
+ (UIBezierPath*)alignToBottomPath:(UIBezierPath*)path layer:(CALayer*)layer{
CGFloat diff = CGRectGetMaxY(layer.bounds) - CGRectGetMaxY(path.bounds);
CGAffineTransform affineTransform = CGAffineTransformTranslate(CGAffineTransformIdentity, 0, diff);
[path applyTransform:affineTransform];
return path;
}
+ (UIBezierPath*)offsetPath:(UIBezierPath*)path by:(CGPoint)offset{
CGAffineTransform affineTransform = CGAffineTransformTranslate(CGAffineTransformIdentity, offset.x, offset.y);
[path applyTransform:affineTransform];
return path;
}
#else
+ (NSBezierPath*)offsetPath:(NSBezierPath*)path by:(CGPoint)offset{
NSAffineTransform* xfm = [NSAffineTransform transform];
[xfm translateXBy:offset.x yBy:offset.y];
[path transformUsingAffineTransform:xfm];
return path;
}
#endif
@end
#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE)
#else
@implementation NSBezierPath (Path)
- (CGPathRef)quartzPath{
NSInteger i, numElements;
CGPathRef immutablePath = NULL;
numElements = [self elementCount];
if (numElements > 0)
{
CGMutablePathRef path = CGPathCreateMutable();
NSPoint points[3];
BOOL didClosePath = YES;
for (i = 0; i < numElements; i++)
{
switch ([self elementAtIndex:i associatedPoints:points])
{
case NSMoveToBezierPathElement:
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
break;
case NSLineToBezierPathElement:
CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
didClosePath = NO;
break;
case NSCurveToBezierPathElement:
CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
didClosePath = NO;
break;
case NSClosePathBezierPathElement:
CGPathCloseSubpath(path);
didClosePath = YES;
break;
}
}
if (!didClosePath){
//CGPathCloseSubpath(path);
}
immutablePath = CGPathCreateCopy(path);
CGPathRelease(path);
}
return immutablePath;
}
@end
@implementation NSImage (cgImage)
-(CGImageRef)cgImage{
NSData* data = [self TIFFRepresentation];
CGImageRef imageRef = NULL;
CGImageSourceRef sourceRef;
sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
if(sourceRef) {
imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, NULL);
CFRelease(sourceRef);
}
return imageRef;
}
@end
#endif

3
Clocker/Rate App/iRate.m

@ -943,8 +943,7 @@ static NSString *const iRateMacAppStoreURLFormat = @"macappstore://itunes.apple.
{
if ([window.windowController isMemberOfClass:[PanelController class]])
{
PanelController *panelRef = (PanelController *)[[[NSApplication sharedApplication]
mainWindow] windowController];
PanelController *panelRef = (PanelController *)[window windowController];
panelRef.showReviewCell = YES;
[panelRef updateDefaultPreferences];
}

21
Media.xcassets/HongKong.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "HongKong.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/HongKong.imageset/HongKong.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

21
Media.xcassets/LA.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LA.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/LA.imageset/LA.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

21
Media.xcassets/NYC.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "NYC.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/NYC.imageset/NYC.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

21
Media.xcassets/Paris.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Paris.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/Paris.imageset/Paris.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

21
Media.xcassets/SF.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "SF.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/SF.imageset/SF.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

21
Media.xcassets/Singapore.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Singapore.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/Singapore.imageset/Singapore.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

21
Media.xcassets/Tokyo.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Tokyo.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/Tokyo.imageset/Tokyo.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

21
Media.xcassets/london.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "london.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/london.imageset/london.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

21
Media.xcassets/sydney.imageset/Contents.json vendored

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "sydney.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
Media.xcassets/sydney.imageset/sydney.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Loading…
Cancel
Save