diff --git a/Classes/Base.lproj/WizardViewController.xib b/Classes/Base.lproj/WizardViewController.xib
index bc04a016c..7a88a452a 100644
--- a/Classes/Base.lproj/WizardViewController.xib
+++ b/Classes/Base.lproj/WizardViewController.xib
@@ -1,8 +1,8 @@
-
+
-
-
+
+
@@ -20,7 +20,7 @@
-
+
@@ -97,6 +97,8 @@
+
+
@@ -109,4 +111,9 @@
-
\ No newline at end of file
+
+
+
+
+
+
diff --git a/Classes/Base.lproj/WizardViewController~ipad.xib b/Classes/Base.lproj/WizardViewController~ipad.xib
index ad94a9549..eee0b856d 100644
--- a/Classes/Base.lproj/WizardViewController~ipad.xib
+++ b/Classes/Base.lproj/WizardViewController~ipad.xib
@@ -1,8 +1,8 @@
-
+
-
-
+
+
@@ -21,7 +21,7 @@
-
+
@@ -98,12 +98,14 @@
+
+
-
+
@@ -180,6 +182,8 @@
+
+
@@ -200,4 +204,9 @@
+
+
+
+
+
diff --git a/Classes/Base.lproj/WizardViews.xib b/Classes/Base.lproj/WizardViews.xib
index 19d9acf68..82ac47106 100644
--- a/Classes/Base.lproj/WizardViews.xib
+++ b/Classes/Base.lproj/WizardViews.xib
@@ -1,8 +1,8 @@
-
+
-
+
@@ -22,7 +22,6 @@
-
@@ -244,22 +243,6 @@
-
diff --git a/Classes/InAppProductsManager.m b/Classes/InAppProductsManager.m
index b3657a29b..9ce1f73c9 100644
--- a/Classes/InAppProductsManager.m
+++ b/Classes/InAppProductsManager.m
@@ -44,9 +44,8 @@
- (instancetype)init {
if ((self = [super init]) != nil) {
- _enabled =
- (([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) && ([SKPaymentQueue canMakePayments]) &&
- ([[LinphoneManager instance] lpConfigBoolForKey:@"enabled" forSection:@"in_app_purchase"]));
+ _enabled = (([SKPaymentQueue canMakePayments]) &&
+ ([[LinphoneManager instance] lpConfigBoolForKey:@"enabled" forSection:@"in_app_purchase"]));
_initialized = false;
_available = false;
_accountActivationInProgress = false;
diff --git a/Classes/Utils/TPKeyboardAvoiding/LICENSE.txt b/Classes/Utils/TPKeyboardAvoiding/LICENSE.txt
new file mode 100755
index 000000000..b2071e3e3
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Michael Tyson
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+ distribution.
\ No newline at end of file
diff --git a/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.h b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.h
new file mode 100755
index 000000000..b870e97fd
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.h
@@ -0,0 +1,14 @@
+//
+// TPKeyboardAvoidingCollectionView.h
+//
+// Created by Michael Tyson on 30/09/2013.
+// Copyright 2013 A Tasty Pixel & The CocoaBots. All rights reserved.
+//
+
+#import
+#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
+
+@interface TPKeyboardAvoidingCollectionView : UICollectionView
+- (BOOL)focusNextTextField;
+- (void)scrollToActiveTextField;
+@end
diff --git a/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.m b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.m
new file mode 100755
index 000000000..caad404e9
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.m
@@ -0,0 +1,96 @@
+//
+// TPKeyboardAvoidingCollectionView.m
+//
+// Created by Michael Tyson on 30/09/2013.
+// Copyright 2013 A Tasty Pixel & The CocoaBots. All rights reserved.
+//
+
+#import "TPKeyboardAvoidingCollectionView.h"
+
+@interface TPKeyboardAvoidingCollectionView ()
+@end
+
+@implementation TPKeyboardAvoidingCollectionView
+
+#pragma mark - Setup/Teardown
+
+- (void)setup {
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
+}
+
+-(id)initWithFrame:(CGRect)frame {
+ if ( !(self = [super initWithFrame:frame]) ) return nil;
+ [self setup];
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
+ if ( !(self = [super initWithFrame:frame collectionViewLayout:layout]) ) return nil;
+ [self setup];
+ return self;
+}
+
+-(void)awakeFromNib {
+ [self setup];
+}
+
+-(void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+#if !__has_feature(objc_arc)
+ [super dealloc];
+#endif
+}
+
+-(void)setFrame:(CGRect)frame {
+ [super setFrame:frame];
+ [self TPKeyboardAvoiding_updateContentInset];
+}
+
+-(void)setContentSize:(CGSize)contentSize {
+ if (CGSizeEqualToSize(contentSize, self.contentSize)) {
+ // Prevent triggering contentSize when it's already the same that
+ // cause weird infinte scrolling and locking bug
+ return;
+ }
+ [super setContentSize:contentSize];
+ [self TPKeyboardAvoiding_updateContentInset];
+}
+
+- (BOOL)focusNextTextField {
+ return [self TPKeyboardAvoiding_focusNextTextField];
+
+}
+- (void)scrollToActiveTextField {
+ return [self TPKeyboardAvoiding_scrollToActiveTextField];
+}
+
+#pragma mark - Responders, events
+
+- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+ [[self TPKeyboardAvoiding_findFirstResponderBeneathView:self] resignFirstResponder];
+ [super touchesEnded:touches withEvent:event];
+}
+
+-(BOOL)textFieldShouldReturn:(UITextField *)textField {
+ if ( ![self focusNextTextField] ) {
+ [textField resignFirstResponder];
+ }
+ return YES;
+}
+
+-(void)textFieldDidBeginEditing:(UITextField *)textField {
+ [self scrollToActiveTextField];
+}
+
+-(void)textViewDidBeginEditing:(UITextView *)textView {
+ [self scrollToActiveTextField];
+}
+
+-(void)layoutSubviews {
+ [super layoutSubviews];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
+ [self performSelector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) withObject:self afterDelay:0.1];
+}
+
+@end
diff --git a/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.h b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.h
new file mode 100755
index 000000000..4d38de93c
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.h
@@ -0,0 +1,15 @@
+//
+// TPKeyboardAvoidingScrollView.h
+//
+// Created by Michael Tyson on 30/09/2013.
+// Copyright 2013 A Tasty Pixel. All rights reserved.
+//
+
+#import
+#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
+
+@interface TPKeyboardAvoidingScrollView : UIScrollView
+- (void)contentSizeToFit;
+- (BOOL)focusNextTextField;
+- (void)scrollToActiveTextField;
+@end
diff --git a/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.m b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.m
new file mode 100755
index 000000000..2959ec03b
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.m
@@ -0,0 +1,89 @@
+//
+// TPKeyboardAvoidingScrollView.m
+//
+// Created by Michael Tyson on 30/09/2013.
+// Copyright 2013 A Tasty Pixel. All rights reserved.
+//
+
+#import "TPKeyboardAvoidingScrollView.h"
+
+@interface TPKeyboardAvoidingScrollView ()
+@end
+
+@implementation TPKeyboardAvoidingScrollView
+
+#pragma mark - Setup/Teardown
+
+- (void)setup {
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
+}
+
+-(id)initWithFrame:(CGRect)frame {
+ if ( !(self = [super initWithFrame:frame]) ) return nil;
+ [self setup];
+ return self;
+}
+
+-(void)awakeFromNib {
+ [self setup];
+}
+
+-(void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+#if !__has_feature(objc_arc)
+ [super dealloc];
+#endif
+}
+
+-(void)setFrame:(CGRect)frame {
+ [super setFrame:frame];
+ [self TPKeyboardAvoiding_updateContentInset];
+}
+
+-(void)setContentSize:(CGSize)contentSize {
+ [super setContentSize:contentSize];
+ [self TPKeyboardAvoiding_updateFromContentSizeChange];
+}
+
+- (void)contentSizeToFit {
+ self.contentSize = [self TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames];
+}
+
+- (BOOL)focusNextTextField {
+ return [self TPKeyboardAvoiding_focusNextTextField];
+
+}
+- (void)scrollToActiveTextField {
+ return [self TPKeyboardAvoiding_scrollToActiveTextField];
+}
+
+#pragma mark - Responders, events
+
+- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+ [[self TPKeyboardAvoiding_findFirstResponderBeneathView:self] resignFirstResponder];
+ [super touchesEnded:touches withEvent:event];
+}
+
+-(BOOL)textFieldShouldReturn:(UITextField *)textField {
+ if ( ![self focusNextTextField] ) {
+ [textField resignFirstResponder];
+ }
+ return YES;
+}
+
+-(void)textFieldDidBeginEditing:(UITextField *)textField {
+ [self scrollToActiveTextField];
+}
+
+-(void)textViewDidBeginEditing:(UITextView *)textView {
+ [self scrollToActiveTextField];
+}
+
+-(void)layoutSubviews {
+ [super layoutSubviews];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
+ [self performSelector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) withObject:self afterDelay:0.1];
+}
+
+@end
diff --git a/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.h b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.h
new file mode 100755
index 000000000..83cde3204
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.h
@@ -0,0 +1,14 @@
+//
+// TPKeyboardAvoidingTableView.h
+//
+// Created by Michael Tyson on 30/09/2013.
+// Copyright 2013 A Tasty Pixel. All rights reserved.
+//
+
+#import
+#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
+
+@interface TPKeyboardAvoidingTableView : UITableView
+- (BOOL)focusNextTextField;
+- (void)scrollToActiveTextField;
+@end
diff --git a/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.m b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.m
new file mode 100755
index 000000000..e1b57efa1
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.m
@@ -0,0 +1,91 @@
+//
+// TPKeyboardAvoidingTableView.m
+//
+// Created by Michael Tyson on 30/09/2013.
+// Copyright 2013 A Tasty Pixel. All rights reserved.
+//
+
+#import "TPKeyboardAvoidingTableView.h"
+
+@interface TPKeyboardAvoidingTableView ()
+@end
+
+@implementation TPKeyboardAvoidingTableView
+
+#pragma mark - Setup/Teardown
+
+- (void)setup {
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TPKeyboardAvoiding_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
+}
+
+-(id)initWithFrame:(CGRect)frame {
+ if ( !(self = [super initWithFrame:frame]) ) return nil;
+ [self setup];
+ return self;
+}
+
+-(id)initWithFrame:(CGRect)frame style:(UITableViewStyle)withStyle {
+ if ( !(self = [super initWithFrame:frame style:withStyle]) ) return nil;
+ [self setup];
+ return self;
+}
+
+-(void)awakeFromNib {
+ [self setup];
+}
+
+-(void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+#if !__has_feature(objc_arc)
+ [super dealloc];
+#endif
+}
+
+-(void)setFrame:(CGRect)frame {
+ [super setFrame:frame];
+ [self TPKeyboardAvoiding_updateContentInset];
+}
+
+-(void)setContentSize:(CGSize)contentSize {
+ [super setContentSize:contentSize];
+ [self TPKeyboardAvoiding_updateContentInset];
+}
+
+- (BOOL)focusNextTextField {
+ return [self TPKeyboardAvoiding_focusNextTextField];
+
+}
+- (void)scrollToActiveTextField {
+ return [self TPKeyboardAvoiding_scrollToActiveTextField];
+}
+
+#pragma mark - Responders, events
+
+- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+ [[self TPKeyboardAvoiding_findFirstResponderBeneathView:self] resignFirstResponder];
+ [super touchesEnded:touches withEvent:event];
+}
+
+-(BOOL)textFieldShouldReturn:(UITextField *)textField {
+ if ( ![self focusNextTextField] ) {
+ [textField resignFirstResponder];
+ }
+ return YES;
+}
+
+-(void)textFieldDidBeginEditing:(UITextField *)textField {
+ [self scrollToActiveTextField];
+}
+
+-(void)textViewDidBeginEditing:(UITextView *)textView {
+ [self scrollToActiveTextField];
+}
+
+-(void)layoutSubviews {
+ [super layoutSubviews];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) object:self];
+ [self performSelector:@selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:) withObject:self afterDelay:0.1];
+}
+
+@end
diff --git a/Classes/Utils/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.h b/Classes/Utils/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.h
new file mode 100755
index 000000000..86c151830
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.h
@@ -0,0 +1,22 @@
+//
+// UIScrollView+TPKeyboardAvoidingAdditions.h
+// TPKeyboardAvoidingSample
+//
+// Created by Michael Tyson on 30/09/2013.
+// Copyright 2013 A Tasty Pixel. All rights reserved.
+//
+
+#import
+
+@interface UIScrollView (TPKeyboardAvoidingAdditions)
+- (BOOL)TPKeyboardAvoiding_focusNextTextField;
+- (void)TPKeyboardAvoiding_scrollToActiveTextField;
+
+- (void)TPKeyboardAvoiding_keyboardWillShow:(NSNotification*)notification;
+- (void)TPKeyboardAvoiding_keyboardWillHide:(NSNotification*)notification;
+- (void)TPKeyboardAvoiding_updateContentInset;
+- (void)TPKeyboardAvoiding_updateFromContentSizeChange;
+- (void)TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:(UIView*)view;
+- (UIView*)TPKeyboardAvoiding_findFirstResponderBeneathView:(UIView*)view;
+-(CGSize)TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames;
+@end
diff --git a/Classes/Utils/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.m b/Classes/Utils/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.m
new file mode 100755
index 000000000..cd70affe9
--- /dev/null
+++ b/Classes/Utils/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.m
@@ -0,0 +1,285 @@
+//
+// UIScrollView+TPKeyboardAvoidingAdditions.m
+// TPKeyboardAvoidingSample
+//
+// Created by Michael Tyson on 30/09/2013.
+// Copyright 2013 A Tasty Pixel. All rights reserved.
+//
+
+#import "UIScrollView+TPKeyboardAvoidingAdditions.h"
+#import "TPKeyboardAvoidingScrollView.h"
+#import
+
+static const CGFloat kCalculatedContentPadding = 10;
+static const CGFloat kMinimumScrollOffsetPadding = 20;
+
+static const int kStateKey;
+
+#define _UIKeyboardFrameEndUserInfoKey (&UIKeyboardFrameEndUserInfoKey != NULL ? UIKeyboardFrameEndUserInfoKey : @"UIKeyboardBoundsUserInfoKey")
+
+@interface TPKeyboardAvoidingState : NSObject
+@property (nonatomic, assign) UIEdgeInsets priorInset;
+@property (nonatomic, assign) UIEdgeInsets priorScrollIndicatorInsets;
+@property (nonatomic, assign) BOOL keyboardVisible;
+@property (nonatomic, assign) CGRect keyboardRect;
+@property (nonatomic, assign) CGSize priorContentSize;
+@end
+
+@implementation UIScrollView (TPKeyboardAvoidingAdditions)
+
+- (TPKeyboardAvoidingState*)keyboardAvoidingState {
+ TPKeyboardAvoidingState *state = objc_getAssociatedObject(self, &kStateKey);
+ if ( !state ) {
+ state = [[TPKeyboardAvoidingState alloc] init];
+ objc_setAssociatedObject(self, &kStateKey, state, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+#if !__has_feature(objc_arc)
+ [state release];
+#endif
+ }
+ return state;
+}
+
+- (void)TPKeyboardAvoiding_keyboardWillShow:(NSNotification*)notification {
+ TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
+
+ if ( state.keyboardVisible ) {
+ return;
+ }
+
+ UIView *firstResponder = [self TPKeyboardAvoiding_findFirstResponderBeneathView:self];
+
+ state.keyboardRect = [self convertRect:[[[notification userInfo] objectForKey:_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
+ state.keyboardVisible = YES;
+ state.priorInset = self.contentInset;
+ state.priorScrollIndicatorInsets = self.scrollIndicatorInsets;
+
+ if ( [self isKindOfClass:[TPKeyboardAvoidingScrollView class]] ) {
+ state.priorContentSize = self.contentSize;
+
+ if ( CGSizeEqualToSize(self.contentSize, CGSizeZero) ) {
+ // Set the content size, if it's not set. Do not set content size explicitly if auto-layout
+ // is being used to manage subviews
+ self.contentSize = [self TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames];
+ }
+ }
+
+ // Shrink view's inset by the keyboard's height, and scroll to show the text field/view being edited
+ [UIView beginAnimations:nil context:NULL];
+ [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
+ [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
+
+ self.contentInset = [self TPKeyboardAvoiding_contentInsetForKeyboard];
+
+ if ( firstResponder ) {
+ CGFloat viewableHeight = self.bounds.size.height - self.contentInset.top - self.contentInset.bottom;
+ [self setContentOffset:CGPointMake(self.contentOffset.x,
+ [self TPKeyboardAvoiding_idealOffsetForView:firstResponder
+ withViewingAreaHeight:viewableHeight])
+ animated:NO];
+ }
+
+ self.scrollIndicatorInsets = self.contentInset;
+
+ [UIView commitAnimations];
+}
+
+- (void)TPKeyboardAvoiding_keyboardWillHide:(NSNotification*)notification {
+ TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
+
+ if ( !state.keyboardVisible ) {
+ return;
+ }
+
+ state.keyboardRect = CGRectZero;
+ state.keyboardVisible = NO;
+
+ // Restore dimensions to prior size
+ [UIView beginAnimations:nil context:NULL];
+ [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
+ [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
+
+ if ( [self isKindOfClass:[TPKeyboardAvoidingScrollView class]] ) {
+ self.contentSize = state.priorContentSize;
+ }
+
+ self.contentInset = state.priorInset;
+ self.scrollIndicatorInsets = state.priorScrollIndicatorInsets;
+ [UIView commitAnimations];
+}
+
+- (void)TPKeyboardAvoiding_updateContentInset {
+ TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
+ if ( state.keyboardVisible ) {
+ self.contentInset = [self TPKeyboardAvoiding_contentInsetForKeyboard];
+ }
+}
+
+- (void)TPKeyboardAvoiding_updateFromContentSizeChange {
+ TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
+ if ( state.keyboardVisible ) {
+ state.priorContentSize = self.contentSize;
+ self.contentInset = [self TPKeyboardAvoiding_contentInsetForKeyboard];
+ }
+}
+
+#pragma mark - Utilities
+
+- (BOOL)TPKeyboardAvoiding_focusNextTextField {
+ UIView *firstResponder = [self TPKeyboardAvoiding_findFirstResponderBeneathView:self];
+ if ( !firstResponder ) {
+ return NO;
+ }
+
+ CGFloat minY = CGFLOAT_MAX;
+ UIView *view = nil;
+ [self TPKeyboardAvoiding_findTextFieldAfterTextField:firstResponder beneathView:self minY:&minY foundView:&view];
+
+ if ( view ) {
+ [view performSelector:@selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
+ return YES;
+ }
+
+ return NO;
+}
+
+-(void)TPKeyboardAvoiding_scrollToActiveTextField {
+ TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
+
+ if ( !state.keyboardVisible ) return;
+
+ CGFloat visibleSpace = self.bounds.size.height - self.contentInset.top - self.contentInset.bottom;
+
+ CGPoint idealOffset = CGPointMake(0, [self TPKeyboardAvoiding_idealOffsetForView:[self TPKeyboardAvoiding_findFirstResponderBeneathView:self]
+ withViewingAreaHeight:visibleSpace]);
+
+ // Ordinarily we'd use -setContentOffset:animated:YES here, but it does not appear to
+ // scroll to the desired content offset. So we wrap in our own animation block.
+ [UIView animateWithDuration:0.25 animations:^{
+ [self setContentOffset:idealOffset animated:NO];
+ }];
+}
+
+#pragma mark - Helpers
+
+- (UIView*)TPKeyboardAvoiding_findFirstResponderBeneathView:(UIView*)view {
+ // Search recursively for first responder
+ for ( UIView *childView in view.subviews ) {
+ if ( [childView respondsToSelector:@selector(isFirstResponder)] && [childView isFirstResponder] ) return childView;
+ UIView *result = [self TPKeyboardAvoiding_findFirstResponderBeneathView:childView];
+ if ( result ) return result;
+ }
+ return nil;
+}
+
+- (void)TPKeyboardAvoiding_findTextFieldAfterTextField:(UIView*)priorTextField beneathView:(UIView*)view minY:(CGFloat*)minY foundView:(UIView**)foundView {
+ // Search recursively for text field or text view below priorTextField
+ CGFloat priorFieldOffset = CGRectGetMinY([self convertRect:priorTextField.frame fromView:priorTextField.superview]);
+ for ( UIView *childView in view.subviews ) {
+ if ( childView.hidden ) continue;
+ if ( ([childView isKindOfClass:[UITextField class]] || [childView isKindOfClass:[UITextView class]]) && childView.isUserInteractionEnabled) {
+ CGRect frame = [self convertRect:childView.frame fromView:view];
+ if ( childView != priorTextField
+ && CGRectGetMinY(frame) >= priorFieldOffset
+ && CGRectGetMinY(frame) < *minY &&
+ !(frame.origin.y == priorTextField.frame.origin.y
+ && frame.origin.x < priorTextField.frame.origin.x) ) {
+ *minY = CGRectGetMinY(frame);
+ *foundView = childView;
+ }
+ } else {
+ [self TPKeyboardAvoiding_findTextFieldAfterTextField:priorTextField beneathView:childView minY:minY foundView:foundView];
+ }
+ }
+}
+
+- (void)TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:(UIView*)view {
+ for ( UIView *childView in view.subviews ) {
+ if ( ([childView isKindOfClass:[UITextField class]] || [childView isKindOfClass:[UITextView class]]) ) {
+ [self TPKeyboardAvoiding_initializeView:childView];
+ } else {
+ [self TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:childView];
+ }
+ }
+}
+
+-(CGSize)TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames {
+
+ BOOL wasShowingVerticalScrollIndicator = self.showsVerticalScrollIndicator;
+ BOOL wasShowingHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;
+
+ self.showsVerticalScrollIndicator = NO;
+ self.showsHorizontalScrollIndicator = NO;
+
+ CGRect rect = CGRectZero;
+ for ( UIView *view in self.subviews ) {
+ rect = CGRectUnion(rect, view.frame);
+ }
+ rect.size.height += kCalculatedContentPadding;
+
+ self.showsVerticalScrollIndicator = wasShowingVerticalScrollIndicator;
+ self.showsHorizontalScrollIndicator = wasShowingHorizontalScrollIndicator;
+
+ return rect.size;
+}
+
+
+- (UIEdgeInsets)TPKeyboardAvoiding_contentInsetForKeyboard {
+ TPKeyboardAvoidingState *state = self.keyboardAvoidingState;
+ UIEdgeInsets newInset = self.contentInset;
+ CGRect keyboardRect = state.keyboardRect;
+ newInset.bottom = keyboardRect.size.height - (CGRectGetMaxY(keyboardRect) - CGRectGetMaxY(self.bounds));
+ return newInset;
+}
+
+-(CGFloat)TPKeyboardAvoiding_idealOffsetForView:(UIView *)view withViewingAreaHeight:(CGFloat)viewAreaHeight {
+ CGSize contentSize = self.contentSize;
+ CGFloat offset = 0.0;
+
+ CGRect subviewRect = [view convertRect:view.bounds toView:self];
+
+ // Attempt to center the subview in the visible space, but if that means there will be less than kMinimumScrollOffsetPadding
+ // pixels above the view, then substitute kMinimumScrollOffsetPadding
+ CGFloat padding = (viewAreaHeight - subviewRect.size.height) / 2;
+ if ( padding < kMinimumScrollOffsetPadding ) {
+ padding = kMinimumScrollOffsetPadding;
+ }
+
+ // Ideal offset places the subview rectangle origin "padding" points from the top of the scrollview.
+ // If there is a top contentInset, also compensate for this so that subviewRect will not be placed under
+ // things like navigation bars.
+ offset = subviewRect.origin.y - padding - self.contentInset.top;
+
+ // Constrain the new contentOffset so we can't scroll past the bottom. Note that we don't take the bottom
+ // inset into account, as this is manipulated to make space for the keyboard.
+ if ( offset > (contentSize.height - viewAreaHeight) ) {
+ offset = contentSize.height - viewAreaHeight;
+ }
+
+ // Constrain the new contentOffset so we can't scroll past the top, taking contentInsets into account
+ if ( offset < -self.contentInset.top ) {
+ offset = -self.contentInset.top;
+ }
+
+ return offset;
+}
+
+- (void)TPKeyboardAvoiding_initializeView:(UIView*)view {
+ if ( [view isKindOfClass:[UITextField class]] && ((UITextField*)view).returnKeyType == UIReturnKeyDefault && (![(id)view delegate] || [(UIScrollView*)view delegate] == (id)self) ) {
+ [(UIScrollView*)view setDelegate:(id)self];
+ UIView *otherView = nil;
+ CGFloat minY = CGFLOAT_MAX;
+ [self TPKeyboardAvoiding_findTextFieldAfterTextField:view beneathView:self minY:&minY foundView:&otherView];
+
+ if ( otherView ) {
+ ((UITextField*)view).returnKeyType = UIReturnKeyNext;
+ } else {
+ ((UITextField*)view).returnKeyType = UIReturnKeyDone;
+ }
+ }
+}
+
+@end
+
+
+@implementation TPKeyboardAvoidingState
+@end
diff --git a/Classes/WizardViewController.h b/Classes/WizardViewController.h
index 35a97b423..87aa1a152 100644
--- a/Classes/WizardViewController.h
+++ b/Classes/WizardViewController.h
@@ -22,6 +22,7 @@
#import "UICompositeViewController.h"
#import "UILinphoneTextField.h"
#import "LinphoneUI/UILinphoneButton.h"
+#import "TPKeyboardAvoidingScrollView.h"
@interface WizardViewController : TPMultiLayoutViewController