From c5d2295ce671f6fb61de1d461dca705d6e1a3479 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 1 Oct 2012 15:22:55 +0200 Subject: [PATCH] Fix animations --- Classes/LinphoneCoreSettingsStore.m | 2 +- Classes/LinphoneUI/UICallBar.m | 1 + .../LinphoneUI/UICompositeViewController.m | 36 +++-- Classes/LinphoneUI/UIMainBar.m | 129 +++++++++++------- .../CAAnimationBlocks/CAAnimation+Blocks.h | 20 +++ .../CAAnimationBlocks/CAAnimation+Blocks.m | 99 ++++++++++++++ linphone.xcodeproj/project.pbxproj | 17 +++ 7 files changed, 242 insertions(+), 62 deletions(-) create mode 100755 Classes/Utils/CAAnimationBlocks/CAAnimation+Blocks.h create mode 100755 Classes/Utils/CAAnimationBlocks/CAAnimation+Blocks.m diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 9db52512c..7f656dafa 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -521,7 +521,7 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); // Post event NSDictionary *eventDic = [NSDictionary dictionaryWithObject:self forKey:@"settings"]; - [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneLogsUpdate object:self userInfo:eventDic]; + [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneSettingsUpdate object:self userInfo:eventDic]; return YES; } diff --git a/Classes/LinphoneUI/UICallBar.m b/Classes/LinphoneUI/UICallBar.m index 553291178..eda89bc0e 100644 --- a/Classes/LinphoneUI/UICallBar.m +++ b/Classes/LinphoneUI/UICallBar.m @@ -21,6 +21,7 @@ #import "LinphoneManager.h" #import "PhoneMainView.h" #import "Utils.h" +#import "CAAnimation+Blocks.h" #include "linphonecore.h" diff --git a/Classes/LinphoneUI/UICompositeViewController.m b/Classes/LinphoneUI/UICompositeViewController.m index 7bbf7f4dc..c9f1877fe 100644 --- a/Classes/LinphoneUI/UICompositeViewController.m +++ b/Classes/LinphoneUI/UICompositeViewController.m @@ -384,28 +384,36 @@ return UIInterfaceOrientationPortrait; } -- (void)updateInterfaceOrientation:(UIInterfaceOrientation)correctOrientation { +- (void)updateInterfaceOrientation:(UIInterfaceOrientation)correctOrientation { UIInterfaceOrientation orientation; orientation = self.interfaceOrientation; - [super willRotateToInterfaceOrientation:correctOrientation duration:0]; - [super willAnimateRotationToInterfaceOrientation:correctOrientation duration:0]; - [super didRotateFromInterfaceOrientation:orientation]; + if(orientation != correctOrientation) { + [super willRotateToInterfaceOrientation:correctOrientation duration:0]; + [super willAnimateRotationToInterfaceOrientation:correctOrientation duration:0]; + [super didRotateFromInterfaceOrientation:orientation]; + } orientation = self.contentViewController.interfaceOrientation; - [self.contentViewController willRotateToInterfaceOrientation:correctOrientation duration:0]; - [self.contentViewController willAnimateRotationToInterfaceOrientation:correctOrientation duration:0]; - [self.contentViewController didRotateFromInterfaceOrientation:orientation]; - + if(orientation != correctOrientation) { + [self.contentViewController willRotateToInterfaceOrientation:correctOrientation duration:0]; + [self.contentViewController willAnimateRotationToInterfaceOrientation:correctOrientation duration:0]; + [self.contentViewController didRotateFromInterfaceOrientation:orientation]; + } + orientation = self.tabBarViewController.interfaceOrientation; - [self.tabBarViewController willRotateToInterfaceOrientation:correctOrientation duration:0]; - [self.tabBarViewController willAnimateRotationToInterfaceOrientation:correctOrientation duration:0]; - [self.tabBarViewController didRotateFromInterfaceOrientation:orientation]; + if(orientation != correctOrientation) { + [self.tabBarViewController willRotateToInterfaceOrientation:correctOrientation duration:0]; + [self.tabBarViewController willAnimateRotationToInterfaceOrientation:correctOrientation duration:0]; + [self.tabBarViewController didRotateFromInterfaceOrientation:orientation]; + } orientation = self.stateBarViewController.interfaceOrientation; - [self.stateBarViewController willRotateToInterfaceOrientation:correctOrientation duration:0]; - [self.stateBarViewController willAnimateRotationToInterfaceOrientation:correctOrientation duration:0]; - [self.stateBarViewController didRotateFromInterfaceOrientation:orientation]; + if(orientation != correctOrientation) { + [self.stateBarViewController willRotateToInterfaceOrientation:correctOrientation duration:0]; + [self.stateBarViewController willAnimateRotationToInterfaceOrientation:correctOrientation duration:0]; + [self.stateBarViewController didRotateFromInterfaceOrientation:orientation]; + } } #define IPHONE_STATUSBAR_HEIGHT 20 diff --git a/Classes/LinphoneUI/UIMainBar.m b/Classes/LinphoneUI/UIMainBar.m index fd2929318..7da223a60 100644 --- a/Classes/LinphoneUI/UIMainBar.m +++ b/Classes/LinphoneUI/UIMainBar.m @@ -20,9 +20,15 @@ #import "UIMainBar.h" #import "PhoneMainView.h" #import "ChatModel.h" +#import "CAAnimation+Blocks.h" @implementation UIMainBar + +static NSString * const kBounceAnimation = @"bounce"; +static NSString * const kAppearAnimation = @"appear"; +static NSString * const kDisappearAnimation = @"disappear"; + @synthesize historyButton; @synthesize contactsButton; @synthesize dialerButton; @@ -73,6 +79,10 @@ selector:@selector(textReceived:) name:kLinphoneTextReceived object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(settingsUpdate:) + name:kLinphoneSettingsUpdate + object:nil]; [self update:FALSE]; } @@ -88,6 +98,9 @@ [[NSNotificationCenter defaultCenter] removeObserver:self name:kLinphoneTextReceived object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:kLinphoneSettingsUpdate + object:nil]; } - (void)viewDidLoad { @@ -213,7 +226,23 @@ [self updateView:[[PhoneMainView instance] firstView]]; } -- (void)textReceived:(NSNotification*)notif { +- (void)settingsUpdate:(NSNotification*)notif { + if([[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"] == false) { + [self stopBounceAnimation:kBounceAnimation target:chatNotificationView]; + chatNotificationView.layer.transform = CATransform3DIdentity; + [self stopBounceAnimation:kBounceAnimation target:historyNotificationView]; + historyNotificationView.layer.transform = CATransform3DIdentity; + } else { + if(![chatNotificationView isHidden] && [chatNotificationView.layer animationForKey:kBounceAnimation] == nil) { + [self startBounceAnimation:kBounceAnimation target:chatNotificationView]; + } + if(![historyNotificationView isHidden] && [historyNotificationView.layer animationForKey:kBounceAnimation] == nil) { + [self startBounceAnimation:kBounceAnimation target:historyNotificationView]; + } + } +} + +- (void)textReceived:(NSNotification*)notif { [self updateUnreadMessage:[ChatModel unreadMessages] appear:TRUE]; } @@ -234,21 +263,25 @@ if (unreadMessage > 0) { if([chatNotificationView isHidden]) { [chatNotificationView setHidden:FALSE]; - if(appear) { - [self appearAnimation:@"appear" target:chatNotificationView completion:^(BOOL finished){ - [self startBounceAnimation:@"bounce" target:chatNotificationView]; - }]; - } else { - [self startBounceAnimation:@"bounce" target:chatNotificationView]; + if([[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"] == true) { + if(appear) { + [self appearAnimation:kAppearAnimation target:chatNotificationView completion:^(BOOL finished){ + [self startBounceAnimation:kBounceAnimation target:chatNotificationView]; + [chatNotificationView.layer removeAnimationForKey:kAppearAnimation]; + }]; + } else { + [self startBounceAnimation:kBounceAnimation target:chatNotificationView]; + } } } [chatNotificationLabel setText:[NSString stringWithFormat:@"%i", unreadMessage]]; } else { if(![chatNotificationView isHidden]) { - [self stopBounceAnimation:@"bounce" target:chatNotificationView]; + [self stopBounceAnimation:kBounceAnimation target:chatNotificationView]; if(appear) { - [self disappearAnimation:@"disappear" target:chatNotificationView completion:^(BOOL finished){ + [self disappearAnimation:kDisappearAnimation target:chatNotificationView completion:^(BOOL finished){ [chatNotificationView setHidden:TRUE]; + [chatNotificationView.layer removeAnimationForKey:kDisappearAnimation]; }]; } else { [chatNotificationView setHidden:TRUE]; @@ -261,21 +294,25 @@ if (missedCall > 0) { if([historyNotificationView isHidden]) { [historyNotificationView setHidden:FALSE]; - if(appear) { - [self appearAnimation:@"appear" target:historyNotificationView completion:^(BOOL finished){ - [self startBounceAnimation:@"bounce" target:historyNotificationView]; - }]; - } else { - [self startBounceAnimation:@"bounce" target:historyNotificationView]; + if([[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"] == true) { + if(appear) { + [self appearAnimation:kAppearAnimation target:historyNotificationView completion:^(BOOL finished){ + [self startBounceAnimation:kBounceAnimation target:historyNotificationView]; + [historyNotificationView.layer removeAnimationForKey:kAppearAnimation]; + }]; + } else { + [self startBounceAnimation:kBounceAnimation target:historyNotificationView]; + } } } [historyNotificationLabel setText:[NSString stringWithFormat:@"%i", missedCall]]; } else { if(![historyNotificationView isHidden]) { - [self stopBounceAnimation:@"bounce" target:historyNotificationView]; + [self stopBounceAnimation:kBounceAnimation target:historyNotificationView]; if(appear) { - [self disappearAnimation:@"disappear" target:historyNotificationView completion:^(BOOL finished){ - + [self disappearAnimation:kDisappearAnimation target:historyNotificationView completion:^(BOOL finished){ + [historyNotificationView setHidden:TRUE]; + [historyNotificationView.layer removeAnimationForKey:kDisappearAnimation]; }]; } else { [historyNotificationView setHidden:TRUE]; @@ -285,40 +322,38 @@ } - (void)appearAnimation:(NSString*)animationID target:(UIView*)target completion:(void (^)(BOOL finished))completion { - target.layer.transform = CATransform3DMakeScale(0.01f, 0.01f, 1.0f); - [UIView animateWithDuration:0.4 - delay:0 - options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction - animations:^{ - target.layer.transform = CATransform3DIdentity; - } - completion:completion]; + CABasicAnimation *appear = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + appear.duration = 0.4; + appear.fromValue = [NSNumber numberWithDouble:0.0f]; + appear.toValue = [NSNumber numberWithDouble:1.0f]; + appear.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + appear.fillMode = kCAFillModeForwards; + appear.removedOnCompletion = NO; + [appear setCompletion:completion]; + [target.layer addAnimation:appear forKey:animationID]; } - (void)disappearAnimation:(NSString*)animationID target:(UIView*)target completion:(void (^)(BOOL finished))completion { - CATransform3D startCGA = target.layer.transform; - [UIView animateWithDuration:0.4 - delay:0 - options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction - animations:^{ - target.layer.transform = CATransform3DConcat(startCGA, CATransform3DMakeScale(0.01f, 0.01f, 1.0f)); - } - completion:completion]; + CABasicAnimation *disappear = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + disappear.duration = 0.4; + disappear.fromValue = [NSNumber numberWithDouble:1.0f]; + disappear.toValue = [NSNumber numberWithDouble:0.0f]; + disappear.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + disappear.fillMode = kCAFillModeForwards; + disappear.removedOnCompletion = NO; + [disappear setCompletion:completion]; + [target.layer addAnimation:disappear forKey:animationID]; } -- (void)startBounceAnimation:(NSString *)animationID target:(UIView *)target { - CATransform3D startCGA = target.layer.transform; - [UIView animateWithDuration: 0.3 - delay: 0 - options: UIViewAnimationOptionRepeat | - UIViewAnimationOptionAutoreverse | - UIViewAnimationOptionAllowUserInteraction | - UIViewAnimationOptionCurveEaseIn - animations:^{ - target.layer.transform = CATransform3DConcat(startCGA, CATransform3DMakeTranslation(0, 8, 0)); - } - completion:^(BOOL finished){ - }]; +- (void)startBounceAnimation:(NSString *)animationID target:(UIView *)target { + CABasicAnimation *bounce = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"]; + bounce.duration = 0.3; + bounce.fromValue = [NSNumber numberWithDouble:0.0f]; + bounce.toValue = [NSNumber numberWithDouble:8.0f]; + bounce.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; + bounce.autoreverses = TRUE; + bounce.repeatCount = HUGE_VALF; + [target.layer addAnimation:bounce forKey:animationID]; } diff --git a/Classes/Utils/CAAnimationBlocks/CAAnimation+Blocks.h b/Classes/Utils/CAAnimationBlocks/CAAnimation+Blocks.h new file mode 100755 index 000000000..47fc08713 --- /dev/null +++ b/Classes/Utils/CAAnimationBlocks/CAAnimation+Blocks.h @@ -0,0 +1,20 @@ +// +// CAAnimation+Blocks.h +// CAAnimationBlocks +// +// Created by xissburg on 7/7/11. +// Copyright 2011 xissburg. All rights reserved. +// + +#import +#import + + +@interface CAAnimation (BlocksAddition) + +@property (nonatomic, copy) void (^completion)(BOOL finished); +@property (nonatomic, copy) void (^start)(void); + +- (void)setCompletion:(void (^)(BOOL finished))completion; // Forces auto-complete of setCompletion: to add the name 'finished' in the block parameter + +@end diff --git a/Classes/Utils/CAAnimationBlocks/CAAnimation+Blocks.m b/Classes/Utils/CAAnimationBlocks/CAAnimation+Blocks.m new file mode 100755 index 000000000..f6ce6c738 --- /dev/null +++ b/Classes/Utils/CAAnimationBlocks/CAAnimation+Blocks.m @@ -0,0 +1,99 @@ +// +// CAAnimation+Blocks.m +// CAAnimationBlocks +// +// Created by xissburg on 7/7/11. +// Copyright 2011 xissburg. All rights reserved. +// + +#import "CAAnimation+Blocks.h" + + +@interface CAAnimationDelegate : NSObject + +@property (nonatomic, copy) void (^completion)(BOOL); +@property (nonatomic, copy) void (^start)(void); + +- (void)animationDidStart:(CAAnimation *)anim; +- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag; + +@end + +@implementation CAAnimationDelegate + +@synthesize completion=_completion; +@synthesize start=_start; + +- (id)init +{ + self = [super init]; + if (self) { + self.completion = nil; + self.start = nil; + } + return self; +} + +- (void)dealloc +{ + self.completion = nil; + self.start = nil; + [super dealloc]; +} + +- (void)animationDidStart:(CAAnimation *)anim +{ + if (self.start != nil) { + self.start(); + } +} + +- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag +{ + if (self.completion != nil) { + self.completion(flag); + } +} + +@end + + +@implementation CAAnimation (BlocksAddition) + +- (void)setCompletion:(void (^)(BOOL))completion +{ + if ([self.delegate isKindOfClass:[CAAnimationDelegate class]]) { + ((CAAnimationDelegate *)self.delegate).completion = completion; + } + else { + CAAnimationDelegate *delegate = [[CAAnimationDelegate alloc] init]; + delegate.completion = completion; + self.delegate = delegate; + [delegate release]; + } +} + +- (void (^)(BOOL))completion +{ + return [self.delegate isKindOfClass:[CAAnimationDelegate class]]? ((CAAnimationDelegate *)self.delegate).completion: nil; +} + +- (void)setStart:(void (^)(void))start +{ + if ([self.delegate isKindOfClass:[CAAnimationDelegate class]]) { + ((CAAnimationDelegate *)self.delegate).start = start; + } + else { + CAAnimationDelegate *delegate = [[CAAnimationDelegate alloc] init]; + delegate.start = start; + self.delegate = delegate; + [delegate release]; + } +} + +- (void (^)(void))start +{ + return [self.delegate isKindOfClass:[CAAnimationDelegate class]]? ((CAAnimationDelegate *)self.delegate).start: nil; +} + +@end diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index ebb82909d..f32a22d72 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -701,6 +701,8 @@ D37DC6C21594AE1800B2A5EB /* LinphoneCoreSettingsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = D37DC6C01594AE1800B2A5EB /* LinphoneCoreSettingsStore.m */; }; D37DC7181594AF3400B2A5EB /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D37DC7171594AF3400B2A5EB /* MessageUI.framework */; }; D37DC7191594AF3F00B2A5EB /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D37DC7171594AF3400B2A5EB /* MessageUI.framework */; }; + D37E3ECD1619C27A0087659A /* CAAnimation+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = D37E3ECC1619C27A0087659A /* CAAnimation+Blocks.m */; }; + D37E3ECE1619C27A0087659A /* CAAnimation+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = D37E3ECC1619C27A0087659A /* CAAnimation+Blocks.m */; }; D37EE10916032DA4003608A6 /* libmediastreamer_base.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22405EE916006F0700B92522 /* libmediastreamer_base.a */; }; D37EE10A16032DA4003608A6 /* libmediastreamer_voip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22405EEA16006F0700B92522 /* libmediastreamer_voip.a */; }; D37EE10B16032DC2003608A6 /* libmediastreamer_base.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22405EE916006F0700B92522 /* libmediastreamer_base.a */; }; @@ -1842,6 +1844,8 @@ D37DC6BF1594AE1800B2A5EB /* LinphoneCoreSettingsStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinphoneCoreSettingsStore.h; sourceTree = ""; }; D37DC6C01594AE1800B2A5EB /* LinphoneCoreSettingsStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LinphoneCoreSettingsStore.m; sourceTree = ""; }; D37DC7171594AF3400B2A5EB /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; + D37E3ECB1619C27A0087659A /* CAAnimation+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CAAnimation+Blocks.h"; sourceTree = ""; }; + D37E3ECC1619C27A0087659A /* CAAnimation+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CAAnimation+Blocks.m"; sourceTree = ""; }; D37EE10F16035793003608A6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ImageViewController.xib; sourceTree = ""; }; D37EE11116036197003608A6 /* fr */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = fr; path = fr.lproj/ImageViewController.xib; sourceTree = ""; }; D37EE160160377D7003608A6 /* DTActionSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTActionSheet.h; sourceTree = ""; }; @@ -3390,6 +3394,7 @@ D326483415887D4400930C67 /* Utils */ = { isa = PBXGroup; children = ( + D37E3ECA1619C27A0087659A /* CAAnimationBlocks */, D380801215C299D0005BE9BC /* ColorSpaceUtilites.m */, D380801115C29984005BE9BC /* ColorSpaceUtilities.h */, D3807FB615C28940005BE9BC /* DCRoundSwitch */, @@ -3427,6 +3432,16 @@ name = Products; sourceTree = ""; }; + D37E3ECA1619C27A0087659A /* CAAnimationBlocks */ = { + isa = PBXGroup; + children = ( + D37E3ECB1619C27A0087659A /* CAAnimation+Blocks.h */, + D37E3ECC1619C27A0087659A /* CAAnimation+Blocks.m */, + ); + name = CAAnimationBlocks; + path = Utils/CAAnimationBlocks; + sourceTree = ""; + }; D37EE15F160377D7003608A6 /* DTFoundation */ = { isa = PBXGroup; children = ( @@ -4791,6 +4806,7 @@ D35E91F4160CA10B0023116B /* UILinphoneTextField.m in Sources */, D35E91F8160CA4FF0023116B /* UILinphoneButton.m in Sources */, D306459E1611EC2A00BB571E /* UILoadingImageView.m in Sources */, + D37E3ECD1619C27A0087659A /* CAAnimation+Blocks.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4888,6 +4904,7 @@ D35E91F5160CA10B0023116B /* UILinphoneTextField.m in Sources */, D35E91F9160CA4FF0023116B /* UILinphoneButton.m in Sources */, D306459F1611EC2A00BB571E /* UILoadingImageView.m in Sources */, + D37E3ECE1619C27A0087659A /* CAAnimation+Blocks.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };