diff --git a/Clocker.xcodeproj/project.pbxproj b/Clocker.xcodeproj/project.pbxproj index 1e709c7..57c7845 100755 --- a/Clocker.xcodeproj/project.pbxproj +++ b/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 = ""; }; 9AD6DE631CE18EB4007A8401 /* CLArrowIndicators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CLArrowIndicators.h; path = Clocker/CLArrowIndicators.h; sourceTree = ""; }; 9AD6DE641CE18EB4007A8401 /* CLArrowIndicators.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CLArrowIndicators.m; path = Clocker/CLArrowIndicators.m; sourceTree = ""; }; + 9AE1FFDE1CE28CF500827C80 /* CLAnimatedImages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CLAnimatedImages.h; path = Clocker/CLAnimatedImages.h; sourceTree = ""; }; + 9AE1FFDF1CE28CF500827C80 /* CLAnimatedImages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CLAnimatedImages.m; path = Clocker/CLAnimatedImages.m; sourceTree = ""; }; + 9AE1FFE01CE28CF500827C80 /* QCMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QCMethod.h; path = Clocker/QCMethod.h; sourceTree = ""; }; + 9AE1FFE11CE28CF500827C80 /* QCMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = QCMethod.m; path = Clocker/QCMethod.m; sourceTree = ""; }; 9AF9A1691C250AB300EE7C2A /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Reachability.h; path = Clocker/Reachability/Reachability.h; sourceTree = ""; }; 9AF9A16A1C250AB300EE7C2A /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Reachability.m; path = Clocker/Reachability/Reachability.m; sourceTree = ""; }; 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 */, diff --git a/Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate b/Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate index 34a6950..c84d6dd 100644 Binary files a/Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate and b/Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Clocker/CLAnimatedImages.h b/Clocker/CLAnimatedImages.h new file mode 100644 index 0000000..85fc414 --- /dev/null +++ b/Clocker/CLAnimatedImages.h @@ -0,0 +1,20 @@ +// +// CLAnimatedImages.h +// +// Code generated using QuartzCode 1.39.16 on 5/10/16. +// www.quartzcodeapp.com +// + +#import + +IB_DESIGNABLE +@interface CLAnimatedImages : NSView + + + +- (void)addUntitled1Animation; +- (void)addUntitled1AnimationCompletionBlock:(void (^)(BOOL finished))completionBlock; +- (void)removeAnimationsForAnimationId:(NSString *)identifier; +- (void)removeAllAnimations; + +@end diff --git a/Clocker/CLAnimatedImages.m b/Clocker/CLAnimatedImages.m new file mode 100644 index 0000000..3ed36d3 --- /dev/null +++ b/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 diff --git a/Clocker/CLArrowIndicators.h b/Clocker/CLArrowIndicators.h new file mode 100644 index 0000000..144e37a --- /dev/null +++ b/Clocker/CLArrowIndicators.h @@ -0,0 +1,16 @@ +// +// CLArrowIndicators.h +// Clocker +// +// Created by Abhishek Banthia on 5/9/16. +// +// + +#import + +@interface CLArrowIndicators : NSControl + +@property (strong, nonatomic) NSColor *blackColor; +@property (assign, nonatomic) BOOL mouseDown; + +@end diff --git a/Clocker/CLArrowIndicators.m b/Clocker/CLArrowIndicators.m new file mode 100644 index 0000000..86bc562 --- /dev/null +++ b/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 diff --git a/Clocker/CLScaleUpButton.h b/Clocker/CLScaleUpButton.h new file mode 100644 index 0000000..6423b28 --- /dev/null +++ b/Clocker/CLScaleUpButton.h @@ -0,0 +1,15 @@ +// +// CLScaleUpButton.h +// Clocker +// +// Created by Abhishek Banthia on 5/9/16. +// +// + +#import + +@interface CLScaleUpButton : NSButton + +@property (strong, nonatomic) NSTrackingArea *trackingArea; + +@end diff --git a/Clocker/CLScaleUpButton.m b/Clocker/CLScaleUpButton.m new file mode 100644 index 0000000..ae70294 --- /dev/null +++ b/Clocker/CLScaleUpButton.m @@ -0,0 +1,45 @@ +// +// CLScaleUpButton.m +// Clocker +// +// Created by Abhishek Banthia on 5/9/16. +// +// + +#import "CLScaleUpButton.h" +#import + +@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 diff --git a/Clocker/Onboarding/CLIntroView.xib b/Clocker/Onboarding/CLIntroView.xib index 9bc460c..4b639c3 100644 --- a/Clocker/Onboarding/CLIntroView.xib +++ b/Clocker/Onboarding/CLIntroView.xib @@ -1,43 +1,50 @@ - + - + - + - - - - - - - - - - - - + + + + + + + + + + + + + - - + - - + + - + - - - diff --git a/Clocker/Onboarding/CLIntroViewController.m b/Clocker/Onboarding/CLIntroViewController.m index 9bfe96b..c21ff22 100644 --- a/Clocker/Onboarding/CLIntroViewController.m +++ b/Clocker/Onboarding/CLIntroViewController.m @@ -9,10 +9,12 @@ #import "CLIntroViewController.h" #import #import "ApplicationDelegate.h" - +#import +#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 +{ } diff --git a/Clocker/Onboarding/CLOnboardingWindowController.m b/Clocker/Onboarding/CLOnboardingWindowController.m index a7b592c..778b5c4 100644 --- a/Clocker/Onboarding/CLOnboardingWindowController.m +++ b/Clocker/Onboarding/CLOnboardingWindowController.m @@ -8,8 +8,11 @@ #import "CLOnboardingWindowController.h" #import +#import @interface CLOnboardingWindowController () +@property (weak) IBOutlet NSTextField *titleLabel; +@property (weak) IBOutlet NSButton *continueButtonOutlet; @property (strong, nonatomic) CLIntroViewController *introViewController; @@ -21,17 +24,20 @@ static CLOnboardingWindowController *sharedOnboardingWindow; - (void)windowDidLoad { [super windowDidLoad]; - self.window.backgroundColor = [NSColor whiteColor]; self.window.titleVisibility = NSWindowTitleHidden; + 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 { if (sharedOnboardingWindow == nil) @@ -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]; + } diff --git a/Clocker/Onboarding/en.lproj/CLOnboardingWindow.xib b/Clocker/Onboarding/en.lproj/CLOnboardingWindow.xib index 5bde360..db66982 100644 --- a/Clocker/Onboarding/en.lproj/CLOnboardingWindow.xib +++ b/Clocker/Onboarding/en.lproj/CLOnboardingWindow.xib @@ -6,6 +6,8 @@ + + @@ -13,33 +15,35 @@ - + + + - + - + - - + + - + - + - + - + - + @@ -49,11 +53,11 @@ - - + - + @@ -101,10 +105,10 @@ DQ - + - + diff --git a/Clocker/PanelController.m b/Clocker/PanelController.m index 011c0fc..c37e2fb 100755 --- a/Clocker/PanelController.m +++ b/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]; diff --git a/Clocker/Preferences/CLPreferencesViewController.h b/Clocker/Preferences/CLPreferencesViewController.h index 773e2ca..708b71f 100644 --- a/Clocker/Preferences/CLPreferencesViewController.h +++ b/Clocker/Preferences/CLPreferencesViewController.h @@ -7,13 +7,16 @@ // #import +#import +#import +#import typedef enum : NSUInteger { CLDefaultTheme, CLBlackTheme } CLTheme; -@interface CLPreferencesViewController : NSViewController +@interface CLPreferencesViewController : NSViewController diff --git a/Clocker/Preferences/CLPreferencesViewController.m b/Clocker/Preferences/CLPreferencesViewController.m index 48555bb..871b076 100644 --- a/Clocker/Preferences/CLPreferencesViewController.m +++ b/Clocker/Preferences/CLPreferencesViewController.m @@ -14,9 +14,10 @@ #import "CommonStrings.h" #import "CLTimezoneData.h" #import "CLAPI.h" -//#import +#import "EDSunriseSet.h" #import + 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 *)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]; diff --git a/Clocker/Preferences/en.lproj/CLPreferencesView.xib b/Clocker/Preferences/en.lproj/CLPreferencesView.xib index 61017ac..ebfb653 100644 --- a/Clocker/Preferences/en.lproj/CLPreferencesView.xib +++ b/Clocker/Preferences/en.lproj/CLPreferencesView.xib @@ -10,6 +10,7 @@ + @@ -20,11 +21,11 @@ - + - + - + - + @@ -111,7 +112,7 @@ CA - + + + + + + + + + + + + + - - + + + - - + diff --git a/Clocker/QCMethod.h b/Clocker/QCMethod.h new file mode 100644 index 0000000..8a6ede6 --- /dev/null +++ b/Clocker/QCMethod.h @@ -0,0 +1,51 @@ +// +// QCMethod.h +// +// Version 1.2 +// +// www.quartzcodeapp.com +// + +#import "TargetConditionals.h" +#import + +#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE) +#import +#else +#import +#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 \ No newline at end of file diff --git a/Clocker/QCMethod.m b/Clocker/QCMethod.m new file mode 100644 index 0000000..182444e --- /dev/null +++ b/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 diff --git a/Clocker/Rate App/iRate.m b/Clocker/Rate App/iRate.m index 2ddfa98..cf4df90 100755 --- a/Clocker/Rate App/iRate.m +++ b/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]; } diff --git a/Media.xcassets/HongKong.imageset/Contents.json b/Media.xcassets/HongKong.imageset/Contents.json new file mode 100644 index 0000000..7c12e98 --- /dev/null +++ b/Media.xcassets/HongKong.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/HongKong.imageset/HongKong.jpg b/Media.xcassets/HongKong.imageset/HongKong.jpg new file mode 100644 index 0000000..b65f563 Binary files /dev/null and b/Media.xcassets/HongKong.imageset/HongKong.jpg differ diff --git a/Media.xcassets/LA.imageset/Contents.json b/Media.xcassets/LA.imageset/Contents.json new file mode 100644 index 0000000..10a7015 --- /dev/null +++ b/Media.xcassets/LA.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/LA.imageset/LA.jpg b/Media.xcassets/LA.imageset/LA.jpg new file mode 100644 index 0000000..4c4b9da Binary files /dev/null and b/Media.xcassets/LA.imageset/LA.jpg differ diff --git a/Media.xcassets/NYC.imageset/Contents.json b/Media.xcassets/NYC.imageset/Contents.json new file mode 100644 index 0000000..dc64357 --- /dev/null +++ b/Media.xcassets/NYC.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/NYC.imageset/NYC.jpg b/Media.xcassets/NYC.imageset/NYC.jpg new file mode 100644 index 0000000..28f8b92 Binary files /dev/null and b/Media.xcassets/NYC.imageset/NYC.jpg differ diff --git a/Media.xcassets/Paris.imageset/Contents.json b/Media.xcassets/Paris.imageset/Contents.json new file mode 100644 index 0000000..ba3f7ad --- /dev/null +++ b/Media.xcassets/Paris.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/Paris.imageset/Paris.jpg b/Media.xcassets/Paris.imageset/Paris.jpg new file mode 100644 index 0000000..4bcc1e7 Binary files /dev/null and b/Media.xcassets/Paris.imageset/Paris.jpg differ diff --git a/Media.xcassets/SF.imageset/Contents.json b/Media.xcassets/SF.imageset/Contents.json new file mode 100644 index 0000000..1e254b5 --- /dev/null +++ b/Media.xcassets/SF.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/SF.imageset/SF.jpg b/Media.xcassets/SF.imageset/SF.jpg new file mode 100644 index 0000000..55098af Binary files /dev/null and b/Media.xcassets/SF.imageset/SF.jpg differ diff --git a/Media.xcassets/Singapore.imageset/Contents.json b/Media.xcassets/Singapore.imageset/Contents.json new file mode 100644 index 0000000..b8722be --- /dev/null +++ b/Media.xcassets/Singapore.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/Singapore.imageset/Singapore.jpg b/Media.xcassets/Singapore.imageset/Singapore.jpg new file mode 100644 index 0000000..aa3fef7 Binary files /dev/null and b/Media.xcassets/Singapore.imageset/Singapore.jpg differ diff --git a/Media.xcassets/Tokyo.imageset/Contents.json b/Media.xcassets/Tokyo.imageset/Contents.json new file mode 100644 index 0000000..51bafa3 --- /dev/null +++ b/Media.xcassets/Tokyo.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/Tokyo.imageset/Tokyo.jpg b/Media.xcassets/Tokyo.imageset/Tokyo.jpg new file mode 100644 index 0000000..f4e16e2 Binary files /dev/null and b/Media.xcassets/Tokyo.imageset/Tokyo.jpg differ diff --git a/Media.xcassets/london.imageset/Contents.json b/Media.xcassets/london.imageset/Contents.json new file mode 100644 index 0000000..f24191d --- /dev/null +++ b/Media.xcassets/london.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/london.imageset/london.jpg b/Media.xcassets/london.imageset/london.jpg new file mode 100644 index 0000000..68e1060 Binary files /dev/null and b/Media.xcassets/london.imageset/london.jpg differ diff --git a/Media.xcassets/sydney.imageset/Contents.json b/Media.xcassets/sydney.imageset/Contents.json new file mode 100644 index 0000000..1651a95 --- /dev/null +++ b/Media.xcassets/sydney.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Media.xcassets/sydney.imageset/sydney.jpg b/Media.xcassets/sydney.imageset/sydney.jpg new file mode 100644 index 0000000..d18a261 Binary files /dev/null and b/Media.xcassets/sydney.imageset/sydney.jpg differ